ICS lab2: Defusing a Binary Bomb

本文详细介绍了如何通过GDB和objdump分析二进制文件bomb,以逐步解决多个阶段的问题,成功拆除虚拟的二进制炸弹。内容包括设置断点、分析汇编代码、理解每个phase的逻辑,以及找到隐藏的secret phase。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

lab2的要求

lab2的要求是拆除“炸弹”,也就是通过objdump 和 gdb 或者其他工具对可执行文件 bomb 进行分析,从而给出“炸弹”不会引爆的输入来“拆除炸弹”。(就是通过gdb等工具对程序进行分析从而给出不会发生爆炸的输入)

工具准备:GDB,objdump

GDB:Gnu DeBugger

GDB的作用:

  • 开始和中止程序
  • 在特定条件或者指定地址暂停程序
  • 测试发生了什么,查看指定地址或寄存器中的值
  • 改变程序中的东西(寄存器中的值等)来测试程序

命令:

 - gdb <filename>           开始用gdb调试程序
 - break FUNC | *ADDR       在FUNC或ADDR地址处设置断点
 - run                      运行程序  
 - print</?>  $REG | ADDR   打印寄存器的值或者指定地址的值
 - continue | stepi | nexti 继续运行到下一个断点或者程序结束|下一步(不进入函数)| 下一步(进入程序)
 - quit                     退出调试

objdump:OBJect-file DUMP

objdump用来显示来自对象文件的信息
命令:

objdump –d | -D <object-file> > <destination-file>

举例:
objdump可以将二进制文件转换成以下形式
objdump举例
工具准备好了,就可以开始做lab啦!

开始做lab

得到 lab 文件之后,打开文件夹发现文件夹内有三个文件:

  • README:判断bomb是不是你的
  • bomb:可执行的bomb二进制文件
  • bomb.c:源文件与炸弹的主程序(但是没有关键代码T^T)
    第一步阅读README文档,检验这个bomb真的是自己的。
    第二步阅读bomb.c(如下,可跳过(但是写的很有意思))
/***************************************************************************
 * Dr. Evil's Insidious Bomb, Version 1.0
 * Copyright 2002, Dr. Evil Incorporated. All rights reserved.
 *
 * LICENSE:
 *
 * Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the
 * VICTIM) explicit permission to use this bomb (the BOMB).  This is a
 * time limited license, which expires on the death of the VICTIM.
 * The PERPETRATOR takes no responsibility for damage, frustration,
 * insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other
 * harm to the VICTIM.  Unless the PERPETRATOR wants to take credit,
 * that is.  The VICTIM may not distribute this bomb source code to
 * any enemies of the PERPETRATOR.  No VICTIM may debug,
 * reverse-engineer, run "strings" on, decompile, decrypt, or use any
 * other technique to gain knowledge of and defuse the BOMB.  BOMB
 * proof clothing may not be worn when handling this program.  The
 * PERPETRATOR will not apologize for the PERPETRATOR's poor sense of
 * humor.  This license is null and void where the BOMB is prohibited
 * by law.
 ***************************************************************************/

#include <stdio.h>
#include "support.h"
#include "phases.h"

/* 
 * Note to self: Remember to erase this file so my victims will have no
 * idea what is going on, and so they will all blow up in a
 * spectaculary fiendish explosion. -- Dr. Evil 
 */

FILE *infile;

int main(int argc, char *argv[])
{
   
   
    char *input;

    /* Note to self: remember to port this bomb to Windows and put a 
     * fantastic GUI on it. */

    /* When run with no arguments, the bomb reads its input lines 
     * from standard input. */
    if (argc == 1) {
   
     
	infile = stdin;
    } 

    /* When run with one argument <file>, the bomb reads from <file> 
     * until EOF, and then switches to standard input. Thus, as you 
     * defuse each phase, you can add its defusing string to <file> and
     * avoid having to retype it. */
    else if (argc == 2) {
   
   
	if (!(infile = fopen(argv[1], "r"))) {
   
   
	    printf("%s: Error: Couldn't open %s\n", argv[0], argv[1]);
	    exit(8);
	}
    }

    /* You can't call the bomb with more than 1 command line argument. */
    else {
   
   
	printf("Usage: %s [<input_file>]\n", argv[0]);
	exit(8);
    }

    /* Do all sorts of secret stuff that makes the bomb harder to defuse. */
    initialize_bomb();

    printf("Welcome to my fiendish little bomb. You have 6 phases with\n");
    printf("which to blow yourself up. Have a nice day!\n");

    /* Hmm...  Six phases must be more secure than one phase! */
    input = read_line();             /* Get input                   */
    phase_1(input);                  /* Run the phase               */
    phase_defused();                 /* Drat!  They figured it out!
				      * Let me know how they did it. */
    printf("Phase 1 defused. How about the next one?\n");

    /* The second phase is harder.  No one will ever figure out
     * how to defuse this... */
    input = read_line();
    phase_2(input);
    phase_defused();
    printf("That's number 2.  Keep going!\n");

    /* I guess this is too easy so far.  Some more complex code will
     * confuse people. */
    input = read_line();
    phase_3(input);
    phase_defused();
    printf("Halfway there!\n");

    /* Oh yeah?  Well, how good is your math?  Try on this saucy problem! */
    input = read_line();
    phase_4(input);
    phase_defused();
    printf("So you got that one.  Try this one.\n");
    
    /* Round and 'round in memory we go, where we stop, the bomb blows! */
    input = read_line();
    phase_5(input);
    phase_defused();
    printf("Good work!  On to the next...\n");

    /* This phase will never be used, since no one will get past the
     * earlier ones.  But just in case, make this one extra hard. */
    input = read_line();
    phase_6(input);
    phase_defused();

    /* Wow, they got it!  But isn't something... missing?  Perhaps
     * something they overlooked?  Mua ha ha ha ha! */
    
    return 0;
}

看完bomb.c我们对bomb有了初步的了解,就是:读入一个文件,如果没有文件,就读入输入,然后根据输入一步一步地运行phase,如果正确,返回正确的信息并向服务器发送正确报告,如果错误返回错误信息并向服务器发送错误报告。

接下来通过

objdump -d bomb > asm 

把二进制可执行文件bomb反汇编到asm里(我随便取的名字),这样我们就会得到一个包含汇编指令的文档。接下来就可以求解phase啦!

求解phase

运行bomb之前

在运行bomb之前一定要先设置断点,不然gdb就认为你直接run这个程序,那,,就炸了(在发现忘记输断点就run之后,不要万念俱焚,断网!这样服务器端检测不到错误,本地会因为网络连接失败而返回错误信息,重新开始,这次不要再忘记设断点了)
首先在main函数处设置断点,然后run检查main的地址和asm文件里地址是否一致,不一致的话后面asm文件里的地址都要保持一样的差值就好了。

break main

为了使程序在爆炸前及时停止而不是向服务器发送错误信息(会扣分),我们采取在错误信息函数之前加断点的方式(嘻嘻)(引爆炸弹函数名可能会不同)。

break explode_bomb

这样我们就可以放心大胆地开始我们的 defuse bomb 之旅啦!

phase1

首先

break phase_1
break phase_2

然后跑到asm文件里面看到phase1是这个样子的:

0000000000001350 <phase_1>:
    1350:	48 83 ec 08          	sub    $0x8,%rsp
    1354:	48 8d 35 95 10 00 00 	lea    0x1095(%rip),%rsi        # 23f0 <_IO_stdin_used+0x150>
    135b:	e8 90 04 00 00       	callq  17f0 <strings_not_equal>
    1360:	85 c0                	test   %eax,%eax
    1362:	75 05                	jne    1369 <phase_1+0x19>
    1364:	48 83 c4 08          	add    $0x8,%rsp
    1368:	c3                   	retq   
    1369:	e8 92 0c 00 00       	callq  2000 <explode_bomb>
    136e:	eb f4                	jmp    1364 <phase_1+0x14>

就是简单的比较了一下输入的字符串(作为函数的参数通过%rdi传入函数)和标准字符串(0x1095(%rip))如果equal就跳出,如果not equal就爆炸。
所以只需要输出标准字符串就可以了
可以使用以下指令输出标准字符串(当然也可以一个一个char的蹦(嘻))

print (char *)($<寄存器> + <对应立即数>)

得到结果如下:phase_1
所以 Why make trillions when we could make… billions? 就是我 phase1的答案啦!kill掉验证一下,对啦!开始做phase_2。

phase2

照例break phase_3
然后跑到asm里看到phase2是这个样子的:

0000000000001370 <phase_2>:
    1370:	55                   	push   %rbp
    1371:	53                   	push   %rbx
    1372:	48 83 ec 28          	sub    $0x28,%rsp
    1376:	48 89 e5             	mov    %rsp,%rbp
    1379:	48 89 e6             	mov    %rsp,%rsi
    137c:	e8 bb 0c 00 00       	callq  203c <read_six_numbers>
    1381:	48 89 e3             	mov    %rsp,%rbx
    1384:	48 83 c5 14          	add    $0x14,%rbp
    1388:	eb 09                	jmp    1393 <phase_2+0x23>
    138a:	48 83 c3 04          	add    $0x4,%rbx
    138e:	48 39 eb             	cmp    %rbp,%rbx
    1391:	74 11                	je     13a4 <phase_2+0x34>
    1393:	8b 03                	mov    (%rbx),%eax
    1395:	83 c0 05             	add    $0x5,%eax
    1398:	39 43 04             	cmp    %eax,0x4(%rbx)
    139b:	74 ed                	je     138a <phase_2+0x1a>
    139d:	e8 5e 0c 00 00       	callq  2000 <explode_bomb>
    13a2:	eb e6                	jmp    138a <phase_2+0x1a>
    13a4:	48 83 c4 28          	add    $0x28,%rsp
    13a8:	5b                   	pop    %rbx
    13a9:	5d                   	pop    %rbp
    13aa:	c3                   	retq   

可以看到phase调用了另外一个函数read_six_numbers,所以找来这个函数看一看:

000000000000203c <read_six_numbers>:
    203c:	48 83 ec 08          	sub    $0x8,%rsp
    2040:	48 89 f2             	mov    %rsi,%rdx
    2043:	48 8d 4e 04          	lea    0x4(%rsi),%rcx
    2047:	48 8d 46 14          	lea    0x14(%rsi),%rax
    204b:	50                   	push   %rax
    204c:	48 8d 46 10          	lea    0x10(%rsi),%rax
    2050:	50                   	push   %rax
    2051:	4c 8d 4e 0c          	lea    0xc(%rsi),%r9
    2055:	4c 8d 46 08          	lea    0x8(%rsi),%r8
    2059:	48 8d 35 47 07 00 00 	lea    0x747(%rip),%rsi        # 27a7 <array.3089+0x327>
    2060:	b8 00 00 00 00       	mov    $0x0,%eax
    2065:	e8 96 ef ff ff       	callq  1000 <__isoc99_sscanf@plt>
    206a:	48 83 c4 10          	add    $0x10,%rsp
    206e:	
### 具身智能概述 具身智能是一种强调物理实体与其环境之间交互作用的人工智能形式[^1]。这种类型的智能不仅依赖于计算资源和算法,还特别重视机体如何通过感知、行动来理解和适应周围世界。 #### 核心算法原理 具身智能的核心在于模拟生物体的感觉运动协调过程。它利用传感器获取外部世界的反馈信息,并基于这些输入调整行为策略以实现特定目标。这类系统通常会集成多种技术,包括但不限于: - **强化学习**:让机器人或其他设备能够自主探索最优解法; - **深度神经网络**:用于处理复杂视觉或听觉信号; - **自适应控制理论**:使机械臂等装置可以灵活应对变化的工作条件; 上述组件共同工作使得机器可以在动态环境中表现出类似于人类的认知功能。 #### 应用实例 在硬件设计方面,具身智能已经取得了显著进展。例如,在制造工业中使用的协作型机器人(Cobot),它们配备了精密触觉感应器和其他高级感测装备,能够在共享空间里安全高效地与工人合作完成任务。此外,还有应用于医疗手术辅助系统的微型外科器械,借助高精度定位能力和实时图像引导提高了操作精准度。 #### 发展趋势与挑战 展望未来,随着材料科学的进步和技术成本降低,预计会出现更多轻量化且能耗更低的新一代移动平台。然而,要真正达到甚至超越自然界的智慧水平仍面临诸多难题,比如提高能源效率、增强鲁棒性和通用性等问题亟待解决。 ```python # Python代码示例展示了一个简单的具身智能仿真框架 class EmbodiedAgent: def __init__(self, sensors, actuators): self.sensors = sensors self.actuators = actuators def perceive_environment(self): return {sensor.name: sensor.read() for sensor in self.sensors} def act_based_on_perception(self, perception_data): actions = {} for actuator in self.actuators: action_value = calculate_action(perception_data, actuator) actions[actuator.name] = action_value apply_actions(actions) def simulate(agent, environment_state): while True: perceptions = agent.perceive_environment() updated_env_state = update_world(environment_state, perceptions) if check_goal_reached(updated_env_state): break agent.act_based_on_perception(perceptions) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值