二元弹阶段4汇编
我有一个非常类似的问题:Binary Bomb - Phase 4但它仍然不同,我不完全确定该怎么做。二元弹阶段4汇编
这里是我的phase_4代码:
08048d3e <phase_4>:
8048d3e: 83 ec 2c sub $0x2c,%esp
8048d41: 8d 44 24 18 lea 0x18(%esp),%eax
8048d45: 89 44 24 0c mov %eax,0xc(%esp)
8048d49: 8d 44 24 1c lea 0x1c(%esp),%eax
8048d4d: 89 44 24 08 mov %eax,0x8(%esp)
8048d51: c7 44 24 04 75 a7 04 movl $0x804a775,0x4(%esp)
8048d58: 08
8048d59: 8b 44 24 30 mov 0x30(%esp),%eax
8048d5d: 89 04 24 mov %eax,(%esp)
8048d60: e8 6b fb ff ff call 80488d0 <[email protected]>
8048d65: 83 f8 02 cmp $0x2,%eax //making sure I have 2 inputs
8048d68: 75 0e jne 8048d78 <phase_4+0x3a> //if not explodes bomb
8048d6a: 8b 44 24 18 mov 0x18(%esp),%eax
8048d6e: 83 f8 01 cmp $0x1,%eax //has to be greater than 1
8048d71: 7e 05 jle 8048d78 <phase_4+0x3a> //otherwise jumps to bomb
8048d73: 83 f8 04 cmp $0x4,%eax
8048d76: 7e 05 jle 8048d7d <phase_4+0x3f> //has to be less than 4 or jumps to bomb
8048d78: e8 af 05 00 00 call 804932c <explode_bomb>
8048d7d: 8b 44 24 18 mov 0x18(%esp),%eax
8048d81: 89 44 24 04 mov %eax,0x4(%esp)
8048d85: c7 04 24 09 00 00 00 movl $0x9,(%esp)
8048d8c: e8 50 ff ff ff call 8048ce1 <func4> //calls function 4
8048d91: 3b 44 24 1c cmp 0x1c(%esp),%eax
8048d95: 74 05 je 8048d9c <phase_4+0x5e> //compares two values and explodes bomb if not equal
8048d97: e8 90 05 00 00 call 804932c <explode_bomb>
8048d9c: 83 c4 2c add $0x2c,%esp
8048d9f: 90 nop
8048da0: c3 ret
这里是func_4代码:
08048ce1 <func4>: //not entirely sure what's happening here but it might be a binary search?
8048ce1: 83 ec 1c sub $0x1c,%esp
8048ce4: 89 5c 24 10 mov %ebx,0x10(%esp)
8048ce8: 89 74 24 14 mov %esi,0x14(%esp)
8048cec: 89 7c 24 18 mov %edi,0x18(%esp)
8048cf0: 8b 74 24 20 mov 0x20(%esp),%esi
8048cf4: 8b 5c 24 24 mov 0x24(%esp),%ebx
8048cf8: 85 f6 test %esi,%esi
8048cfa: 7e 2b jle 8048d27 <func4+0x46>
8048cfc: 83 fe 01 cmp $0x1,%esi
8048cff: 74 2b je 8048d2c <func4+0x4b>
8048d01: 89 5c 24 04 mov %ebx,0x4(%esp)
8048d05: 8d 46 ff lea -0x1(%esi),%eax
8048d08: 89 04 24 mov %eax,(%esp)
8048d0b: e8 d1 ff ff ff call 8048ce1 <func4>
8048d10: 8d 3c 18 lea (%eax,%ebx,1),%edi
8048d13: 89 5c 24 04 mov %ebx,0x4(%esp)
8048d17: 83 ee 02 sub $0x2,%esi
8048d1a: 89 34 24 mov %esi,(%esp)
8048d1d: e8 bf ff ff ff call 8048ce1 <func4>
8048d22: 8d 1c 07 lea (%edi,%eax,1),%ebx
8048d25: eb 05 jmp 8048d2c <func4+0x4b>
8048d27: bb 00 00 00 00 mov $0x0,%ebx
8048d2c: 89 d8 mov %ebx,%eax
8048d2e: 8b 5c 24 10 mov 0x10(%esp),%ebx
8048d32: 8b 74 24 14 mov 0x14(%esp),%esi
8048d36: 8b 7c 24 18 mov 0x18(%esp),%edi
8048d3a: 83 c4 1c add $0x1c,%esp
8048d3d: c3 ret
我检查,以确保输入必须是两位小数,而且我还可以看到最后两个数字相互比较(第8048d97行,0x1c(%esp)和%eax)。在阶段4开始时,我认为代码也表明第一个数字必须在1到4之间,而在阶段4结束时,数字已被修改,它必须等于第二个数字。如果我错了,请纠正我。
我只是不确定func_4在做什么,以及如何确定输入应该是什么。我认为这可能是二分搜索,但不知道如何检查它与第一个输入的对应关系。任何帮助将不胜感激!
func_4正在做什么,以及如何确定输入应该是什么。
8048d81: 89 44 24 04 mov %eax,0x4(%esp)
; input value loaded to [esp+4] -> [esp+0x24] inside func4
8048d85: c7 04 24 09 00 00 00 movl $0x9,(%esp)
; 9 stored to [esp+0] -> [esp+0x20] inside func4
8048d8c: e8 50 ff ff ff call 8048ce1 <func4>
; something calculated
; then the result is compared with other input value, they should be equal
我不知道,哪个输入是(你知道sscanf的格式字符串和您的ABI,所以你可以告诉越好,一个存储到[ESP +为0x18]和测试要在计算中使用值2,3或4时,只是比较存储在[esp + 0x1c]中的值,我猜测计算的输入是第二个(对于+ 0x0c的sscanf,另一个是+ 0x08)?因此密码是“<func4(9,2-4)> <2-4>
”?
由于func4是干净的asm递归代码,因此您可以针对所有三种可能的输入运行它,以查看它产生的结果(在调试器中,逐步执行指令,以便设法捕获if一些p参数会导致无限循环或其他一些问题,再加上你会明白它是如何工作的)。
然后找出哪个输入是哪个。
不知道什么func_4做
嘿,这就是如何组装工作。你很少看看指令流,并快速浏览一下它们的算法。更常见的情况是,需要通过指令彻底模拟头部指令中的CPU状态,注意每一个细节(比如标志根据指令改变,看起来只用于设置一个值,然后在条件中使用几条指令后保存标志跳转),并且通过保持一些计算值的时间轴,通常可以猜测实现的算法。
或者如果不是算法,那么至少要知道计算的是什么值。
我检查代码一个更多的时间,它看起来像Fibonnaci主题的变化,像func4(0,x) = 0
,func4(1,x) = x
,并func4(y, x)
= (只是猜测快,懒得去验证我猜中了)x + func4(y-1, x) + func4(y-2, x)
。
编辑:我现在确定公式是不正确的,它至少缺少一个常量(但也许它错了甚至更多)。
所以我想知道,你是懒得费心彻底模拟CPU,并获得正确的结果,或者你有一些特殊指令的问题,它究竟做(即。你是懒得阅读说明书参考指南)?所以它归结为“你是懒惰还是懒惰?”因为我绝对都是,所以这是我对你的问题的回答。 :)
如果您不明白某些指令的某些特定细节,请询问。
编辑约的评论:
“//必须是小于4或跳转到炸弹”
不,这是jle
,这是记忆法“跳签署以下/等于“,所以正确的评论是”必须小于或等于4“,并且对于值[TYPE_MIN,4]是有效的。
对于“少于4”,您需要使用jl
=“跳过少签名”。
对于“小于4”,无符号的有jb
=“跳到下面”,覆盖值[0,3]。 jbe
涵盖[0,4]值。
如果您将检查Jcc description,你会看到那些条件跳转仅基于在标志寄存器中几个标志,仅此而已(除了jcxz/jecxz
,其中比较cx
寄存器和不接触标志在所有)。
另外你可能会注意到有几个别名,所以你可以在你的代码中写出一个符合你的目的的语义。例如jz
和je
是相同的指令,第一个别名代表“jump when zero(flag)”,另一个代表“跳转时相等”。所以仔细阅读并习惯这些缩写,它会使拆解的阅读更容易一些。
//调用函数4
那是没用的评论,这是由指令本身明显。您是否会添加例如参数(9,input_2),这对读者会更有好处。
下一个“比较”评论具有类似的无用性质。两个数字是什么?如果你已经记下了它们,你应该把这个结果写入注释,所以像“比较func4和input_1的结果”。
我会努力向您展示的例子中,FUNC4:
8048ce1 <func4>:
; allocates 0x1c bytes on stack for local variables
; (so return address is at [esp+0x1c] now, was at [esp])
8048ce1: 83 ec 1c sub $0x1c,%esp
; stores current ebx, esi and edi in [esp+0x10/0x14/0x18]
8048ce4: 89 5c 24 10 mov %ebx,0x10(%esp)
8048ce8: 89 74 24 14 mov %esi,0x14(%esp)
8048cec: 89 7c 24 18 mov %edi,0x18(%esp)
; esi = [esp+0x20] = first argument of func4(arg1, arg2)
8048cf0: 8b 74 24 20 mov 0x20(%esp),%esi
; ebx = [esp+0x24] = second argument of func4(arg1, arg2)
8048cf4: 8b 5c 24 24 mov 0x24(%esp),%ebx
; when esi(arg1) <= 0, jump to ExitWith0
8048cf8: 85 f6 test %esi,%esi
8048cfa: 7e 2b jle 8048d27 ExitWith0
; when esi(arg1) == 1, jump to ExitWithValueFromEbx
8048cfc: 83 fe 01 cmp $0x1,%esi
8048cff: 74 2b je 8048d2c ExitWithValueFromEbx
; store arg2 in [esp+4]
8048d01: 89 5c 24 04 mov %ebx,0x4(%esp)
; store (arg1-1) in [esp] (preparing args for recursive call)
8048d05: 8d 46 ff lea -0x1(%esi),%eax
8048d08: 89 04 24 mov %eax,(%esp)
; recursion: eax = func4(arg1-1, arg2) ; ebx/esi/edi preserved
8048d0b: e8 d1 ff ff ff call 8048ce1 <func4>
; edi = eax (result) + ebx*1 (arg2)
8048d10: 8d 3c 18 lea (%eax,%ebx,1),%edi
; [esp+4] is set to arg2 again
; (it's still there, but this asm looks like debug level of C, not very efficient)
8048d13: 89 5c 24 04 mov %ebx,0x4(%esp)
; esi -= 2 (no more original arg1 in esi), and set [esp+0]
8048d17: 83 ee 02 sub $0x2,%esi
8048d1a: 89 34 24 mov %esi,(%esp)
; second recursive call: func4(arg1-2, arg2)
8048d1d: e8 bf ff ff ff call 8048ce1 <func4>
; ebx = edi + eax*1 ; edi was arg2 + f4(arg1-1, arg2)
8048d22: 8d 1c 07 lea (%edi,%eax,1),%ebx
; so ebx = arg2 + f4(arg1-1, arg2) + f4(arg1-2, arg2), return that value
8048d25: eb 05 jmp 8048d2c ExitWithValueFromEbx
ExitWith0:
8048d27: bb 00 00 00 00 mov $0x0,%ebx
ExitWithValueFromEbx:
8048d2c: 89 d8 mov %ebx,%eax
; restore values of ebx/esi/edi (return value is in eax)
8048d2e: 8b 5c 24 10 mov 0x10(%esp),%ebx
8048d32: 8b 74 24 14 mov 0x14(%esp),%esi
8048d36: 8b 7c 24 18 mov 0x18(%esp),%edi
; restore esp value, so [esp] is return address, and return
8048d3a: 83 c4 1c add $0x1c,%esp
8048d3d: c3 ret
所以我实际上在我的答案猜测正确,在LEA那些,1)
搞糊涂了,我不习惯AT & T语法,所以在一个较弱的时刻,我认为结果是+1,但它是* 1到索引寄存器(我习惯于英特尔语法,它看起来像lea ebx,[edi+eax]
)。
但是,正如你所看到的,一旦你开始记下笔记,并专注于单指令,这次我确实设法正确解密它。
目前,确保您理解每条指令非常重要,我指的是每个细节,比如lea
的工作原理以及为什么它不读取存储器值,即使参数是(...)
,以及什么是全部可能的寻址模式(如果你想要做f(a,b)= 1 + b + f(a-1,b)+ f(a-2,b),它看起来会如何?尝试找到一个,必须修改一个lea
(这两个中的任何一个))。
我不确定你有什么样的文献,因为我使用英特尔语法所有东西(我认为AT & T语法对于C编译器是好的,但对人类来说不是那么重要......但总的来说并不是那么糟糕,如果你已经知道另一个,大部分都很烦人,如果你只知道T,那可能是相当不错的)。
在最坏的情况下请问,尽管关于指令目的的问题是“低效”,因为所有的x86手册都是免费的,但如果您不确定某些措辞的真正含义,并且在调试器中几次运行此类指令,没有帮助,你必须问。只需添加你的想法和什么词让你感到困惑。
肯定是懒惰的,但我一直试图通过这个代码3天,所以我可能只是不明白的基本指导方针。而且这个项目已经给出了如果我模拟一个CPU炸弹爆炸。我会尝试输入三个不同的值,但可能是这样做的方式。谢谢。 –
@SnigdaaSethuram我的意思是“模仿”在你的脑海。你有清单,所以你可以执行你的想法中的每一条指令(很可能在纸张的帮助下将“CPU”状态保持在某个地方:))。尽管为深度“9”做完整的'func4'递归将是一件很乏味的工作。如果你真的可以在gdb中运行这些代码,那么只需在'call'后面放置断点,然后进入几次迭代就可以很容易地看到它的工作方式,然后让它运行到断点并检查结果值。 – Ped7g
更新:看起来第二个输入必须在2到4之间。我也测试了第二个输入的所有三个值,但是对于所有三个值,我在最后得到%esp的值为9,这是有道理的,因为有一条线将9移入该寄存器。我不明白的是,第一个输入是如何相关的,以及我们将如何特别匹配eax,因为3个输入中没有一个给出9%的结果值%esp。 –
1和4之间?为什么?我在那里看到'jle'。这会让我更容易,如果你将代码与你的评论交错,你认为这几行代码可以做什么(所以我不需要自己计算什么是'0x24(%esp)') fn4。搜索几乎每个跳转地址的整个代码,无论是导致爆炸,还是化解,添加一些标签......它还会显示更多的努力,除此之外,您是否考虑过打字这到真正的机器和看着调试?或者它被认为是作弊的炸弹实验室?然后问在SO也必须。:D – Ped7g
只是在评论!对不起!我确实使用调试器,但无论如何它通过函数4跳转,它继续到爆炸炸弹的步骤,但我无法跟随,因为我不擅长解码汇编代码。 –
我用'func4'的“样本”注释扩展了我的答案。通过它,让我知道它是否有帮助。“不擅长解密”=需要一些时间,但是通常只有x86 CPU的许多指令,每个指令都只是非常简单的事情,当你将自己限制在80386指令集时,它实际上比任何高级语言(就intructions/keywords而言)学习ASM要容易得多)。这是您需要做的一些有用的指令,这使得在ASM中进行编程变得困难,而不是指令本身。那些很简单。 – Ped7g