别担心,我不会问答案的。
我正在尝试在一个简单的 1 函数 32 位 exe 中找到一个隐藏的字符串(也许是电子邮件?
我已经在文件上运行了字符串,没有什么有用的。
我已经将文件反编译为 ASCII 并找到了主要功能。
文件显示它是一个 GCC 可执行文件。
以下是主函数的 ASM:
; ================ B E G I N N I N G O F P R O C E D U R E ================
; Variables:
; arg_0: int, 4
main:
080489cc lea ecx, dword [esp+arg_0] ; Begin of unwind block (FDE at 0x80d6cb8), DATA XREF=_start+23
080489d0 and esp, 0xfffffff0
080489d3 push dword [ecx-4]
080489d6 push ebp
080489d7 mov ebp, esp
080489d9 push esi
080489da push ebx
080489db push ecx
080489dc sub esp, 0x2c
080489df call __x86.get_pc_thunk.cx ; __x86.get_pc_thunk.cx
080489e4 add ecx, 0xa261c
080489ea mov eax, dword [gs:0x14]
080489f0 mov dword [ebp-0x1c], eax
080489f3 xor eax, eax
080489f5 mov eax, esp
080489f7 mov esi, eax
080489f9 mov dword [ebp-0x2c], 0x15
08048a00 mov eax, dword [ebp-0x2c]
08048a03 lea edx, dword [eax-1]
08048a06 mov dword [ebp-0x28], edx
08048a09 shl eax, 0x2
08048a0c lea edx, dword [eax+3]
08048a0f mov eax, 0x10
08048a14 sub eax, 0x1
08048a17 add eax, edx
08048a19 mov ebx, 0x10
08048a1e mov edx, 0x0
08048a23 div ebx
08048a25 imul eax, eax, 0x10
08048a28 sub esp, eax
08048a2a mov eax, esp
08048a2c add eax, 0x3
08048a2f shr eax, 0x2
08048a32 shl eax, 0x2
08048a35 mov dword [ebp-0x24], eax
08048a38 mov eax, dword [ebp-0x24]
08048a3b mov dword [eax], 0x2391
08048a41 mov eax, dword [ebp-0x24]
08048a44 mov dword [eax+4], 0x239d
08048a4b mov eax, dword [ebp-0x24]
08048a4e mov dword [eax+8], 0x239d
08048a55 mov eax, dword [ebp-0x24]
08048a58 mov dword [eax+0xc], 0x2399
08048a5f mov eax, dword [ebp-0x24]
08048a62 mov dword [eax+0x10], 0x239c
08048a69 mov eax, dword [ebp-0x24]
08048a6c mov dword [eax+0x14], 0x2363
08048a73 mov eax, dword [ebp-0x24]
08048a76 mov dword [eax+0x18], 0x2358
08048a7d mov eax, dword [ebp-0x24]
08048a80 mov dword [eax+0x1c], 0x2358
08048a87 mov eax, dword [ebp-0x24]
08048a8a mov dword [eax+0x20], 0x2390
08048a91 mov eax, dword [ebp-0x24]
08048a94 mov dword [eax+0x24], 0x2398
08048a9b mov eax, dword [ebp-0x24]
08048a9e mov dword [eax+0x28], 0x2398
08048aa5 mov eax, dword [ebp-0x24]
08048aa8 mov dword [eax+0x2c], 0x2357
08048aaf mov eax, dword [ebp-0x24]
08048ab2 mov dword [eax+0x30], 0x2390
08048ab9 mov eax, dword [ebp-0x24]
08048abc mov dword [eax+0x34], 0x2395
08048ac3 mov eax, dword [ebp-0x24]
08048ac6 mov dword [eax+0x38], 0x2358
08048acd mov eax, dword [ebp-0x24]
08048ad0 mov dword [eax+0x3c], 0x2377
08048ad7 mov eax, dword [ebp-0x24]
08048ada mov dword [eax+0x40], 0x235e
08048ae1 mov eax, dword [ebp-0x24]
08048ae4 mov dword [eax+0x44], 0x2380
08048aeb mov eax, dword [ebp-0x24]
08048aee mov dword [eax+0x48], 0x237a
08048af5 mov eax, dword [ebp-0x24]
08048af8 mov dword [eax+0x4c], 0x2381
08048aff mov eax, dword [ebp-0x24]
08048b02 mov dword [eax+0x50], 0x23a3
08048b09 mov eax, dword [ebp-0x2c]
08048b0c sub esp, 0xc
08048b0f push eax ; argument #1 for method __libc_malloc
08048b10 mov ebx, ecx
08048b12 call __libc_malloc ; __libc_malloc
08048b17 add esp, 0x10
08048b1a add eax, 0x1
08048b1d mov dword [ebp-0x20], eax
08048b20 mov dword [ebp-0x30], 0x0
08048b27 jmp loc_8048b44
行 08048a35 - 08048b09 看起来它一次移动 1 个字符,我肯定它是字符串。
这里的问题是,有人能帮我弄清楚这些角色是什么吗?它们不是ASCII编码,我不确定ASM是如何真正做字符编码之类的东西的,所以也许我只是没有看到它。也许它是加密的?
我是新手,真的不知道最好的方法。谢谢!
序列
08048a38 mov eax, dword [ebp-0x24]
08048a3b mov dword [eax], 0x2391
08048a41 mov eax, dword [ebp-0x24]
08048a44 mov dword [eax+4], 0x239d
(等等(正在写0x2391,0x239d,...在 32 位整数数组中的连续位置(请参阅以 4 个字节间隔的连续偏移量(,其指针作为参数传递(指针值每次都莫名其妙地从 ebp减去一些东西(。最终它的内容将是:
0x2391
0x239d
0x239d
0x2399
0x239c
0x2363
0x2358
0x2358
0x2390
0x2398
0x2398
0x2357
0x2390
0x2395
0x2358
0x2377
0x235e
0x2380
0x237a
0x2381
0x23a3
现在,这不是ASCII,但是第二和第三个元素的重复(加上后面的其他重复(以及它们几乎都在同一个范围内的事实使我认为它们都必须以相同的简单方式编码,大概是具有某些固定值的求和或异或(始终相同的顶部0x23字节是一个死赠品(; 所以, 由于您的问题中缺少其余代码(大概是解码此数组的位置(,我只是猜测并尝试将它们全部减去相同的值,以使它们回到 ASCII 范围。
我的第一个猜测是,上面重复的数字(0x239d(必须是l
(通常在英语中是情侣(。因此,我需要一个数字,使0x239d成为l
(ASCII 108(;0x239d - 108 = 9009,这就是我减去每个字符的内容。结果都是 ASCII(令人鼓舞 - 如果方案更复杂,除了两个l
之外,我会得到不可读的随机垃圾(,但荒谬。
我选择了蛮力方法(最合理的情况只有 62 - 大写、小写和数字 - 使用这种方法进行详尽搜索最多是 256 个案例,仍然可以通过目视检查进行管理(并尝试了一些类似的数字 - 所有导致 ASCII 字符的东西,但希望更明智。
事实上,一旦我达到 9001:
In [18]: [chr(int(x,16)-9001) for x in s.split()]
Out[18]:
['h',
't',
't',
'p',
's',
':',
'/',
'/',
'g',
'o',
'o',
'.',
'g',
'l',
'/',
'N',
'5',
'W',
'Q',
'X',
'z']
(s
这里是包含本文第二个代码块内容的字符串,其中包含所有数组值的代码块(
享受游戏的下一个级别。
顺便说一下,这种集会确实很可怕。其中一些,例如继续将相同的值从堆栈重新加载到寄存器
mov eax, dword [ebp-0x24]
会让我想到一个非优化的、调试器友好的构建;OTOH,有些东西似乎并不是来自编译器:
mov eax, 0x10
sub eax, 0x1
在这里,即使是在适度的优化水平上编译常量传播也会产生mov eax, 0xf
,或者,在-O0
,它会在堆栈上执行,而不是在寄存器中,以帮助源级单步执行。
mov ebx, 0x10
mov edx, 0x0
div ebx
imul eax, eax, 0x10
这在多个层面上都是脑残的;你永远不会看到编译器发出mov edx, 0x0
- 即使在-O0
将寄存器归零几乎总是xor edx, edx
。此外,数据类型也存在一些混淆:首先是无符号div
,然后是有符号imul
(它映射到类似((int)((unsigned)(foo)/16))*16
的东西,我觉得不太可能(。
但最重要的是,gcc 永远不会发出除法/乘以 16 的div
或mul
;即使在-O0
时,它也会将它们转换为移位;clang 是一样的(尽管在-O0
时它仍然会发出有符号除法的idiv
,而不是在更高优化级别上使用的移位 + 符号位 twiddling(。
最后,如果输入值是无符号的(根据div
(,这整个事情归结为掩盖低 4 位,所以所有这些混乱可能只是and eax, 0xfffffff0
.
所以,在我看来,这是由一个对汇编不是很有经验的人手写的代码;这种事情甚至看起来不是"故意的困难",以使反汇编更加困难 - 代码非常简单,只是非常幼稚。