2016-10-26 45 views
1

我是CS学生,学习IA-32程序集。对于一个项目,我们已经获得了一个程序的可执行文件。我们可以使用objdump等工具来检查二进制文件,但不允许看到原始的源代码。该程序接受一个输入字符串并将其与另一个神秘字符串进行比较。如果两个字符串都是不是相同,程序会发出警报,并且我放弃了这个任务。这将是一个有趣的任务...如果电讯局长会打扰回答我的问题... Grr ...阅读IA32汇编代码 - 确定隐藏的字符串?

所以,如果你不介意给我一些指针,我想问问论坛如果我走在正确的轨道上。当我的代码可执行文件运行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()或其他 - 然后指向该字符串的指针被保存到寄存器%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  

这就是我认为正在发生的事情...

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 

所以......如果我是对的,线#2是这里最重要的一个。我怀疑神秘字符串存储在内存地址$0x804a46c。但我不确定。我还注意到,当我使用字符串工具时,我看到:

[linux]$ strings -t x CODE | grep 46c 
    246c My dog has fleas. 
[linux]$ 

这是有希望的......但不具有说服力。内存地址$0x804a46c不是246c

所以......对于这篇冗长的文章道歉,但人们可以告诉我,如果我在正确的轨道上?任何洞察力或智慧是疯狂的赞赏!

非常感谢! -RAO

+2

使用'objdump'来查看给定地址处的字符串。 'strings'给你文件偏移量,而不是虚拟地址。当然,如果您再次使用'objdump'查看节标题,那么也可以翻译它们。 – Jester

+1

地址为“8048bba”的“神秘操作码”只是前面指令的一部分。它可能包含在下一行,因为指令编码太长了。请注意,指令中的值是'0x804a46c','6c''a4'和'04'全部列在前一行。 – davmac

+0

@davmac:是的,正好。我通常使用'objdump -drwC'来避免('-w'意思是“宽”,并且将指令的所有字节放在同一行上,而不管列的宽度如何)。 –

回答

3

除非存在一些反调试技巧,否则cmp_strings()只接受两个参数,这两个参数都在test_string()内给出。当然,它们都是字符串,第一个字符串取自一个常量位置0x804a46c,而第二个字符串(它的指针,当然不是字符串本身)是test_string()的一个参数。通话前即时堆叠看起来是这样的:

 |_______________| 
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: |  ...  | 

您可以直接在运行时使用GDB(在一般情况下,有必要检查«秘密»字符串内容,因为这里没有显示的代码可以改写)。只需break *0x8048bc2,run然后x/sb 0x804a46c

+0

是的,这样做! x/sb 0x804a46c“我的狗有跳蚤。”完美,谢谢!你也给了我一个GDB x命令的好消息,我预计在不久的将来会使用这个命令。谢谢! – Pete

+0

@Pete:顺便说一下,GDB可以比默认情况下更具交互性。使用'gdb --tui',并在启动时输入'layout asm'来查看程序集。 – hidefromkgb

2

下一行将指针移至%esp,然后调用test_string()。在eaxesp寻址的存储器,即

mov %eax,(%esp)存储值。在堆栈顶部。要将该指针复制到esp中,您必须执行mov %eax, %esp,这不是一个好主意,因为CPU使用ss:esp作为堆栈指针。

movl $0x804a46c,0x4(%esp) // test_string is stored at $0x804a46c; move that pointer into %esp

再次 “入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值。查看hidefromkgb堆栈内容的ASCII艺术的答案。

然后,它很可能是call 8049084 <cmp_strings>挑选出栈作为参数的两个指针,做一些事情,并为正确的字符串返回零(因为任何非零返回值将使未来je失败,并引发call <alarm>

你或许应该在cmp_strings我们快速浏览一下也一样,看它是否是普通的C类strcmp或者它如何可以返回零。

而作为小丑指出,它应该能够objdump也是神秘0x804a46c内容。如果这是早期的任务,它可能会变得更糟使用易于读取的字符串数据访问数据部分。

如果这将是更困难的任务,它也可以指向代码段中的假指令形成一些字符串..或最终甚至不是假指令(尽管产生有意义的asm代码也形成一些短字符串不是在x86上微不足道......例如,我曾经为我的256B intros .com文件的开头添加了“PED”,它只是搞乱了一些堆栈,并未影响我的其他介绍......并且在一次大小的编码比赛中我用xlat指向代码,以获得想要的位模式,在51 bytes中绘制希腊国旗)。

+0

谢谢Ped7g,这是很好的细节。我正在慢慢地学习,虽然IA-32的语法看起来很简单,但它很难遵循,也很容易被误解。我已将您的所有评论复制到笔记中。 :) – Pete

+0

@Pete我个人非常喜欢英特尔语法(特别是NASM变种)。但恐怕你不是完全可以自由选择。虽然objdump可以配置为产生Intel语法的GNU方言:http://stackoverflow.com/a/10362655/4271923但是请确保它不会在课堂上稍后咬你,当你将被强制执行到AT&T吗?此外,如果您将此视为第一次ASM,也许AT&T不会伤害那么多。 (我在几个月/年的时间里学习x86,在其他CPU上编码,而且英特尔语法看起来很熟悉) – Ped7g

+0

嗯......好的食物。老实说,我是一名IA-32的新手,并且只在两天前了解到objdump。我正在处理摆在我面前的语法,而不是真正理解它来自哪里。我必须考虑更多。谢谢! – Pete