我是一名学习IA-32装配的CS学生。对于一个项目,我们已经获得了程序的可执行文件。我们可以使用objdump
和其他工具来检查二进制文件,但不允许查看原始源代码。该程序接受一个输入字符串,并将其与另一个神秘字符串进行比较。如果两个字符串 不 相同,则程序会发出警报,并且我不知道该作业。这将是一项有趣的任务......如果助教又懒得回答我的问题...... Grr ......
所以,如果你不介意给我一些指示,我想询问论坛我是否走在正确的轨道上。当我在CODE可执行文件上运行objdump -d CODE
时,我可以向下钻取并在main()函数中看到它:
08048a44 <main>:
...
8048af6: e8 d0 08 00 00 call 80493cb <get_string>
8048afb: 89 04 24 mov %eax,(%esp)
8048afe: e8 ad 00 00 00 call 8048bb0 <test_string>
我有理由确定get_string()
从用户那里获取一个字符串 - 它可能是fscanf()
或其他东西的包装函数 - 然后指向该字符串的指针被保存到寄存器{{1 }}。下一行将指针移至%eax
,然后调用%esp
。这是代码:
test_string()
这就是我认为正在发生的事情......
08048bb0 <test_string>:
8048bb0: 83 ec 1c sub $0x1c,%esp
8048bb3: c7 44 24 04 6c a4 04 movl $0x804a46c,0x4(%esp)
8048bba: 08
8048bbb: 8b 44 24 20 mov 0x20(%esp),%eax
8048bbf: 89 04 24 mov %eax,(%esp)
8048bc2: e8 bd 04 00 00 call 8049084 <cmp_strings>
8048bc7: 85 c0 test %eax,%eax
8048bc9: 74 05 je 8048bd0 <test_string+0x20>
8048bcb: e8 bc 07 00 00 call 804938c <alarm>
8048bd0: 83 c4 1c add $0x1c,%esp
8048bd3: c3 ret
所以...如果我是对的,第2行是重要的一个。我怀疑神秘字符串存储在内存地址08048bb0 <test_string>:
8048bb0: sub $0x1c,%esp // Adjusts %esp for new function
8048bb3: movl $0x804a46c,0x4(%esp) // test_string is stored at $0x804a46c; move that pointer into %esp
8048bba: // ???
8048bbb: mov 0x20(%esp),%eax // Moves test_string ptr to %eax
8048bbf: mov %eax,(%esp) // Moves test_string ptr to %esp - not sure why...?
8048bc2: call 8049084 <cmp_strings> // Calls cmp_strings(), probably with %eax and %esp as argument strings
8048bc7: test %eax,%eax // %eax is the returned value
8048bc9: je 8048bd0 <test_string+0x20> // Should we jump to alarm()?
8048bcb: call 804938c <alarm> // If we reach here, I flunk
8048bd0: add $0x1c,%esp // restores %esp to original value
8048bd3: ret // exits
中。但我不确定。我还注意到,当我使用字符串工具时,我看到了:
$0x804a46c
这很有希望......但不能令人信服。内存地址[linux]$ strings -t x CODE | grep 46c
246c My dog has fleas.
[linux]$
不是$0x804a46c
。
所以...为冗长的帖子道歉,但是人们可以告诉我,我是否在正确的轨道上?任何见解或智慧都非常受欢迎!
非常感谢! -RAO
答案 0 :(得分:3)
除非有一些反调试技巧在进行,否则import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
只接受两个在cmp_strings()
内部给出的参数。当然,它们都是字符串,第一个字符串取自常量位置test_string()
,而第二个字符串(指向它的指针,当然不是字符串本身)是0x804a46c
的参数。在调用之前,堆栈看起来像这样:
test_string()
您可以使用GDB直接在运行时检查«secret»字符串内容(通常,这是必要的,因为此处未显示的代码可能会重写它)。只需 |_______________|
ESP: | <your string> | <-- cmp_strings() 1st arg
+04: | 0x804a46c | <-- cmp_strings() 2nd arg
+08: | ... |
+0C: | ... |
+10: | ... |
+14: | ... |
+18: | ... |
+1C: | return adress | <-- ESP at the start of test_string()
+20: | <your string> | <-- test_string() 1st arg
+24: | ... |
,break *0x8048bc2
,然后run
。
答案 1 :(得分:2)
下一行将指针移动到%esp,然后调用test_string()。
mov %eax,(%esp)
将eax
中的值存储到esp
所寻址的内存中,即。在堆栈的顶部。要将该指针复制到esp中,您必须执行mov %eax, %esp
,这不是一个好主意,因为ss:esp
被CPU用作堆栈指针。
movl $0x804a46c,0x4(%esp) // test_string is stored at $0x804a46c; move that pointer into %esp
再次,“into esp
”在完全错误的程度上是不准确的。这会将值0x804a46c
写入地址esp+4
的内存中,因此如果您要从堆栈中pop
值,则会弹出第二个值(右侧“在堆栈顶部”)。
mov 0x20(%esp),%eax // Moves test_string ptr to %eax
将“输入字符串指针”加载到eax
。这是eax
之前call <test_string>
的那个。你可能就是这个意思,写了错误的评论?
mov %eax,(%esp) // Moves test_string ptr to %esp - not sure why...?
将它存储在“堆栈顶部”,因此如果您要在此处开始从堆栈中弹出值,则首先弹出输入字符串指针,然后弹出0x804a46c
值。有关堆栈内容的ASCII艺术,请参阅hidefromkgb的答案。
然后很可能call 8049084 <cmp_strings>
从堆栈中选择那两个指针作为参数,执行某些操作,并为正确的字符串返回零(因为任何非零返回值将使下一个je
失败,并触发call <alarm>
。
您也应该快速查看cmp_strings
,看看它是否是普通的C strcmp
或它是如何返回零的。
正如杰斯特所指出的那样,objdump
也应该有神秘的0x804a46c
内容。如果它是一些早期任务,它可能属于具有易于读取的字符串数据的数据部分。
如果这将是更困难的任务,它也可以指向代码段中的伪指令形成一些字符串..或最终甚至不是假指令(虽然产生有意义的asm代码,形成一些短字符串也不是微不足道的在x86上...例如我曾经在我的256B intros .com文件的开头添加“PED”,它只是搞乱堆栈,不影响我的介绍的其余部分......并且在一个大小的编码竞赛中我使用xlat
指向代码以获得想要的位模式以在51 bytes中绘制希腊旗帜。