阅读 IA32 汇编代码 - 确定隐藏字符串?
Reading IA32 Assembly Code - Determining Hidden String?
我是一名学习 IA-32 汇编的 CS 学生。对于一个项目,我们已经获得了一个程序的可执行文件。我们可以使用objdump
等工具来检查二进制文件,但不允许查看原始源代码。该程序接受一个输入字符串并将其与另一个神秘字符串进行比较。如果两个字符串 not 相同,程序就会发出警报,我的作业不及格。这将是一个有趣的任务...如果 TA 愿意回答我的问题...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()
或其他东西的包装函数——然后指向该字符串的指针被保存到寄存器 %eax
。下一行将指针移动到 %esp
,然后调用 test_string()
。这是代码:
08048bb0 <test_string>:
8048bb0: 83 ec 1c sub [=11=]x1c,%esp
8048bb3: c7 44 24 04 6c a4 04 movl [=11=]x804a46c,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 [=11=]x1c,%esp
8048bd3: c3 ret
这是我认为正在发生的事情...
08048bb0 <test_string>:
8048bb0: sub [=12=]x1c,%esp // Adjusts %esp for new function
8048bb3: movl [=12=]x804a46c,0x4(%esp) // test_string is stored at [=12=]x804a46c; 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 [=12=]x1c,%esp // restores %esp to original value
8048bd3: ret // exits
所以...如果我是对的,第 2 行是这里的重要一行。我怀疑神秘字符串存储在内存地址 [=21=]x804a46c
中。但我不确定。我还注意到,当我使用字符串工具时,我看到了这个:
[linux]$ strings -t x CODE | grep 46c
246c My dog has fleas.
[linux]$
这很有希望……但不令人信服。内存地址 [=21=]x804a46c
不是 246c
.
那么...对于冗长的 post 表示歉意,但是大家可以告诉我我是否在正确的轨道上吗?非常感谢任何见解或智慧!
非常感谢!
-饶
除非有一些反调试技巧,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 在运行时直接检查 «secret» 字符串的内容(这通常是必需的,因为此处未显示的代码可能会重写它)。只是 break *0x8048bc2
、run
然后是 x/sb 0x804a46c
.
The next line moves the pointer to %esp, then calls test_string().
mov %eax,(%esp)
将 eax
中的值存储到 esp
寻址的内存中,即。在堆栈的顶部。要将该指针复制到 esp 中,您必须执行 mov %eax, %esp
这不是一个好主意,因为 ss:esp
被 CPU.
用作堆栈指针
movl [=15=]x804a46c,0x4(%esp) // test_string is stored at [=15=]x804a46c; move that pointer into %esp
同样,"into esp
" 在完全错误的层面上是不准确的。这会将值 0x804a46c
写入内存地址 esp+4
,因此如果您要从堆栈中获取 pop
值,它将是弹出的第二个值(右 "under" 堆栈顶部).
mov 0x20(%esp),%eax // Moves test_string ptr to %eax
将 "input string pointer" 加载到 eax
。那是 call <test_string>
之前 eax
的那个。您可能是这个意思,写错了评论?
mov %eax,(%esp) // Moves test_string ptr to %esp - not sure why...?
将它存储在 "top of the stack",因此如果您要从此处的堆栈中弹出值,您将首先弹出输入字符串指针,然后是 0x804a46c
值。有关堆栈内容的 ASCII 艺术,请参阅 hidefromkgb 的答案。
然后很可能 call 8049084 <cmp_strings>
从堆栈中选择这两个指针作为参数,做一些事情,并且 return 将正确的字符串设为零(因为任何非零 return value 将使 next je
失败,并触发 call <alarm>
.
您可能也应该快速浏览一下 cmp_strings
,看看它是否是普通的 C 语言 strcmp
或者它如何 return 为零。
正如 Jester 指出的那样,objdump
神秘的 0x804a46c
内容也应该是可能的。如果是一些早期的任务,它可能属于具有易于阅读的字符串数据的数据部分。
如果这会是一个更困难的任务,它也可以指向代码段中形成一些字符串的假指令......或者最终甚至不是假指令(尽管产生有意义的 asm 代码也形成一些短字符串是在 x86 上不是微不足道的……例如,我曾经在我的 256B intros .com 文件的开头添加 "PED",它只是把堆栈弄乱了一点,不影响我介绍的其余部分……并且在一个大小编码竞赛我使用 xlat
指向代码以获得想要的位模式以在 51 bytes 中绘制希腊国旗)。
我是一名学习 IA-32 汇编的 CS 学生。对于一个项目,我们已经获得了一个程序的可执行文件。我们可以使用objdump
等工具来检查二进制文件,但不允许查看原始源代码。该程序接受一个输入字符串并将其与另一个神秘字符串进行比较。如果两个字符串 not 相同,程序就会发出警报,我的作业不及格。这将是一个有趣的任务...如果 TA 愿意回答我的问题...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()
或其他东西的包装函数——然后指向该字符串的指针被保存到寄存器 %eax
。下一行将指针移动到 %esp
,然后调用 test_string()
。这是代码:
08048bb0 <test_string>:
8048bb0: 83 ec 1c sub [=11=]x1c,%esp
8048bb3: c7 44 24 04 6c a4 04 movl [=11=]x804a46c,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 [=11=]x1c,%esp
8048bd3: c3 ret
这是我认为正在发生的事情...
08048bb0 <test_string>:
8048bb0: sub [=12=]x1c,%esp // Adjusts %esp for new function
8048bb3: movl [=12=]x804a46c,0x4(%esp) // test_string is stored at [=12=]x804a46c; 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 [=12=]x1c,%esp // restores %esp to original value
8048bd3: ret // exits
所以...如果我是对的,第 2 行是这里的重要一行。我怀疑神秘字符串存储在内存地址 [=21=]x804a46c
中。但我不确定。我还注意到,当我使用字符串工具时,我看到了这个:
[linux]$ strings -t x CODE | grep 46c
246c My dog has fleas.
[linux]$
这很有希望……但不令人信服。内存地址 [=21=]x804a46c
不是 246c
.
那么...对于冗长的 post 表示歉意,但是大家可以告诉我我是否在正确的轨道上吗?非常感谢任何见解或智慧!
非常感谢! -饶
除非有一些反调试技巧,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 在运行时直接检查 «secret» 字符串的内容(这通常是必需的,因为此处未显示的代码可能会重写它)。只是 break *0x8048bc2
、run
然后是 x/sb 0x804a46c
.
The next line moves the pointer to %esp, then calls test_string().
mov %eax,(%esp)
将 eax
中的值存储到 esp
寻址的内存中,即。在堆栈的顶部。要将该指针复制到 esp 中,您必须执行 mov %eax, %esp
这不是一个好主意,因为 ss:esp
被 CPU.
movl [=15=]x804a46c,0x4(%esp) // test_string is stored at [=15=]x804a46c; move that pointer into %esp
同样,"into esp
" 在完全错误的层面上是不准确的。这会将值 0x804a46c
写入内存地址 esp+4
,因此如果您要从堆栈中获取 pop
值,它将是弹出的第二个值(右 "under" 堆栈顶部).
mov 0x20(%esp),%eax // Moves test_string ptr to %eax
将 "input string pointer" 加载到 eax
。那是 call <test_string>
之前 eax
的那个。您可能是这个意思,写错了评论?
mov %eax,(%esp) // Moves test_string ptr to %esp - not sure why...?
将它存储在 "top of the stack",因此如果您要从此处的堆栈中弹出值,您将首先弹出输入字符串指针,然后是 0x804a46c
值。有关堆栈内容的 ASCII 艺术,请参阅 hidefromkgb 的答案。
然后很可能 call 8049084 <cmp_strings>
从堆栈中选择这两个指针作为参数,做一些事情,并且 return 将正确的字符串设为零(因为任何非零 return value 将使 next je
失败,并触发 call <alarm>
.
您可能也应该快速浏览一下 cmp_strings
,看看它是否是普通的 C 语言 strcmp
或者它如何 return 为零。
正如 Jester 指出的那样,objdump
神秘的 0x804a46c
内容也应该是可能的。如果是一些早期的任务,它可能属于具有易于阅读的字符串数据的数据部分。
如果这会是一个更困难的任务,它也可以指向代码段中形成一些字符串的假指令......或者最终甚至不是假指令(尽管产生有意义的 asm 代码也形成一些短字符串是在 x86 上不是微不足道的……例如,我曾经在我的 256B intros .com 文件的开头添加 "PED",它只是把堆栈弄乱了一点,不影响我介绍的其余部分……并且在一个大小编码竞赛我使用 xlat
指向代码以获得想要的位模式以在 51 bytes 中绘制希腊国旗)。