|
利刃信安 利刃信安攻防实验室 2023-12-02 19:01 发表于北京
题目地址:
- https://buuoj.cn/challenges#SimpleRev
复制代码
- https://files.buuoj.cn/files/7458c5c0ce999ac491df13cf7a7ed9f1/SimpleRev
复制代码
首先,查壳
- 信息:
- 文件名: H://BUUCTF/SimpleRev/SimpleRev
- 大小: 13128(12.82 KiB)
- 操作系统: Ubuntu Linux(ABI: 3.2.0)
- 架构: AMD64
- 模式: 64 位
- 类型: DYN
- 字节序: LE
复制代码
使用IDA64打开
F5
- unsigned __int64 Decry()
- {
- char v1; // [rsp+Fh] [rbp-51h]
- int v2; // [rsp+10h] [rbp-50h]
- int v3; // [rsp+14h] [rbp-4Ch]
- int i; // [rsp+18h] [rbp-48h]
- int v5; // [rsp+1Ch] [rbp-44h]
- char src[8]; // [rsp+20h] [rbp-40h] BYREF
- __int64 v7; // [rsp+28h] [rbp-38h]
- int v8; // [rsp+30h] [rbp-30h]
- __int64 v9[2]; // [rsp+40h] [rbp-20h] BYREF
- int v10; // [rsp+50h] [rbp-10h]
- unsigned __int64 v11; // [rsp+58h] [rbp-8h]
- v11 = __readfsqword('(');
- *(_QWORD *)src = 'SLCDN';
- v7 = 0LL;
- v8 = 0;
- v9[0] = 'wodah';
- v9[1] = 0LL;
- v10 = 0;
- text = join(key3, (const char *)v9);
- strcpy(key, key1);
- strcat(key, src);
- v2 = 0;
- v3 = 0;
- getchar();
- v5 = strlen(key);
- for ( i = 0; i < v5; ++i )
- {
- if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
- key[i] = key[v3 % v5] + 32;
- ++v3;
- }
- printf("Please input your flag:");
- while ( 1 )
- {
- v1 = getchar();
- if ( v1 == '\n' )
- break;
- if ( v1 == ' ' )
- {
- ++v2;
- }
- else
- {
- if ( v1 <= '`' || v1 > 'z' )
- {
- if ( v1 > '@' && v1 <= 'Z' )
- {
- str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
- ++v3;
- }
- }
- else
- {
- str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
- ++v3;
- }
- if ( !(v3 % v5) )
- putchar(32);
- ++v2;
- }
- }
- if ( !strcmp(text, str2) )
- puts("Congratulation!\n");
- else
- puts("Try again!\n");
- return __readfsqword(0x28u) ^ v11;
- }
复制代码
这里涉及数据在内存中存储的方式大小端问题。
涉及大小端存储问题,elf文件这种通常使用小端存储,而IDA会把内存中的数据自动转成大端存储,但是有些变量双击过去,在文本视图能直接看到转好的字符串,以key3为例
而有些却不能,这个时候就需要自己把字符串倒过来,比如我们在伪代码看到的 str 是 SLCDN ,可实际用这个字符串的时候应该用 NDCLS 同理,wodah 改成 hadow 。
数据在内存中存储的方式:大端模式与小端模式
所谓的大端模式(Big-endian),是指数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
所谓小端模式(Little-endian), 是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内在的低地址中,这种存储模式将地址的高低和数据位 权有效结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致;
假设一个十六进制数0x12345678
大端的存储方式是:12,34,56,78,然后读取的时候也是从前往后读
小端的存储方式是:78,56,34,12,然后读取的时候是从后往前读取
我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
src = 'SLCDN' 则 src 小端存储 = 'NDCLS'
v9[0] = 'wodah' 则 v9[0] 小端存储 = 'hadow'
key1 = 'ADSFK'
key3 = 'kills'
text = join(key3, (const char *)v9) = 'killshadow'
key = 'ADSFKNDCLS'
上面的代码是将 key 的字符全部转成小写即 key = 'adsfkndcls'
分析str2
if ( !strcmp(text, str2) ) 由此段代码可知,当 str2 与 text 的字符串相同时,条件满足。这里可以得知,str2 是正确的 flag 经过一些列处理得到的,我们现在只需要把处理过程逆一下,就可以的到正确的 flag
用C++写脚本
- #include <stdio.h>
- #include <string.h>
- int main() {
- int v3 = 0;
- char key[] = "adsfkndcls";
- char str2[] = "killshadow";
- int v5 = strlen(key);
- for (int v2 = 0; v2 < v5; v2++) {
- for (int v1 = 'A'; v1 <= 'z'; v1++) {
- if (str2[v2] == (v1 - 39 - key[v3 % v5] + 97) % 26 + 97) {
- printf("%c", v1);
- ++v3;
- break;
- }
- }
- }
-
- return 0;
- }
复制代码
用Python3写脚本
- key = 'adsfkndcls'
- text = 'killshadow'
- v5 = len(key)
- flag = ''
- for v3, text_char in enumerate(text):
- for v1 in range(65, 91):
- if (v1 - 39 - ord(key[v3 % v5]) + 97) % 26 + 97 == ord(text_char):
- flag += chr(v1)
- print(flag)
复制代码
运行结果为:KLDQCUDFZO
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|