第一种方法:
-
首先将文件拖入IDA 64,查找main函数
-
观察发现main函数中存在一个判断。结合右侧“sorry”提示,估计为false。观察主函数汇编。
; Attributes: bp-based frame
; int __cdecl main(int argc, const char **argv, const char **envp)
public main
main proc near ;这两行是对 main 函数的定义,这是程序的入口点。
var_34= dword ptr -34h ;定义了一些局部变量。这些变量存储在栈中,其位置相对于基指针 rbp。
s= byte ptr -30h ;它声明了一个名为 s 的变量,该变量是一个字节大小的内存位置,位于基指针 rbp 下 0x30 字节的位置
var_28= qword ptr -28h ;这个声明定义了一个名为 var_28 的局部变量,它是一个 qword(Quad Word,也就是 8 字节或 64 位)大小的变量,位于基指针 rbp 下 0x28 个字节的位置
var_20= qword ptr -20h ;这个声明定义了一个名为 var_20 的局部变量,它也是一个 qword 大小的变量,位于 rbp 下 0x20 个字节的位置
var_18= qword ptr -18h ;这个声明定义了一个名为 var_18 的局部变量,它也是一个 qword 大小的变量,位于 rbp 下 0x18 个字节的位置
var_10= dword ptr -10h ;这个声明定义了一个名为 var_10 的局部变量,它是一个 dword(Double Word,也就是 4 字节或 32 位)大小的变量,位于 rbp 下 0x10 个字节的位置
var_C= byte ptr -0Ch ;这个声明定义了一个名为 var_C 的局部变量,它是一个 byte(1 字节)大小的变量,位于 rbp 下 0xC 个字节的位置
; __unwind {
push rbp ;这个指令将当前的基指针 rbp 压入栈中
mov rbp, rsp ;将当前的栈指针 rsp(指向栈顶的指针)赋值给 rbp。这是为了设置新的栈帧
sub rsp, 40h ;从栈指针 rsp 中减去 0x40 (也就是64)。在大多数系统中,栈是向下增长的,所以减去一个数实际上是在栈上分配新的空间
mov rax, 6E30637B67616C66h ;将16进制数6E30637B67616C66移动到rax寄存器中。rax是一个64位的寄存器
mov rdx, 74406C7574407267h ;将16进制数74406C7574407267移动到rdx寄存器中
mov qword ptr [rbp+s], rax ;将 rdx 寄存器中的值复制到内存中。内存的地址是通过 rbp(基指针)和 var_28 的偏移量计算得到的
mov [rbp+var_28], rdx ;将 rdx 寄存器中的值复制到内存中的一个位置,这个位置是由基指针 rbp 和 var_28 的偏移量确定的。在这个例子中,var_28 是一个在之前定义的局部变量
mov rax, 5F7230665F6E3069h ;将16进制数 5F7230665F6E3069 复制到 rax 寄存器中
mov rdx, 6D756E5F6B63756Ch ;将16进制数 5F7230665F6E3069 复制到 rax 寄存器中
mov [rbp+var_20], rax ;将 rax 寄存器中的值复制到内存中的一个位置,这个位置是由基指针 rbp 和 var_20 的偏移量确定的
mov [rbp+var_18], rdx ;将 rdx 寄存器中的值复制到内存中的一个位置,这个位置是由基指针 rbp 和 var_18 的偏移量确定的
mov [rbp+var_10], 7D723362h ;将16进制数 7D723362 复制到内存中的一个位置,这个位置是由基指针 rbp 和 var_10 的偏移量确定的
mov [rbp+var_C], 0 ;将0值移动到内存的一个位置
mov [rbp+var_34], 0 ;将0值移动到内存的一个位置
lea rax, [rbp+var_34] ;将rbp+var_34的地址加载到rax寄存器中。lea指令是"load effective address"的缩写,它将源操作数的有效地址加载到目标操作数(这里是rax)中
mov rsi, rax ;将rax寄存器中的值复制到rsi寄存器
lea rdi, unk_2004 ;将unk_2004的地址加载到rdi寄存器中
mov eax, 0 ;将0值移动到eax寄存器中
call ___isoc99_scanf ;调用函数___isoc99_scanf
mov eax, [rbp+var_34] ;将内存中的一个值移动到eax寄存器中
cmp eax, 7 ;比较eax寄存器中的值和7
jnz short loc_11C5 ;如果上一条cmp指令的结果不为零(也就是eax中的值不等于7),则跳转到loc_11C5
mov rdi, rax ; s ;这条指令将 rax 寄存器中的值复制到 rdi 寄存器中,注意这里提示了:s
call _puts ;这条指令调用了 puts 函数,这是一个 C 标准库函数,用于在控制台上打印一个字符串。在这条指令执行之前,字符串的地址应该已经被放在 rdi 寄存器中,所以这个 puts 调用将打印出存储在 rax 中的地址指向的字符串。
jmp short loc_11D1 ;这是一个无条件跳转指令,它将控制流跳转到地址
栈图:
Higher addresses
+---------------------+
| | <- Previous stack frame
+---------------------+
| Return Addr |
+---------------------+
| Old rbp | <- rbp (after "push rbp" and "mov rbp, rsp")
+---------------------+
| |
| |
| |
| | <- rsp (after "sub rsp, 40h")
| |
| |
| |
| |
+---------------------+
| var_10 (dword) | <- rbp - 0x10
+---------------------+
| var_18 (qword) | <- rbp - 0x18
+---------------------+
| var_20 (qword) | <- rbp - 0x20
+---------------------+
| var_28 (qword) | <- rbp - 0x28
+---------------------+
| s (byte) | <- rbp - 0x30
+---------------------+
| var_34 (dword) | <- rbp - 0x34
+---------------------+
| | <- Future stack growth
Lower addresses
- 通过观察
cmp eax, 7
,我们可以得出,如果当我们输入的值为7时,会跳转出我们想要的答案。放到Linux去进行尝试。
获得了flag为:flag{c0ngr@tul@ti0n_f0r_luck_numb3r}
第二种方法:
- 我们观察如果为True 跳转的代码块
lea rax, [rbp+s]
mov rdi, rax ; s
call _puts
jmp short loc_11D1
- 发现调了一个_puts函数,看看里面会显示点什么。发现这段代码会将
char s
里面的字符打印出来。推测在前面的几串hex有关。
通过编写代码进行尝试:
hexStrings = ["6E30637B67616C66","74406C7574407267",\
"5F7230665F6E3069","6D756E5F6B63756C","7D723362"] # 定义一个存储hex的列表
flagStrings = [] # 定义一个空列表
for i in hexStrings:
byte_data = bytes.fromhex(i) # bytes.fromhex(string): 这个方法是 bytes 类型的一个类方法,它接受一个包含十六进制数字的字符串,并返回一个字节串对象,这个字节串对象的内容是根据字符串中的十六进制数字解析得到的
ascii_str = byte_data.decode('ASCII') #这个方法是 bytes 类型的一个实例方法,它用来将字节串解码成字符串,这里我们转换成ASCII。
flagStrings.append(ascii_str[::-1])
print("".join(flagStrings))
结果flag为:flag{c0ngr@tul@ti0n_f0r_luck_numb3r}
第三种方法:
直接用IDA PRO的F5反编译查看
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
int v4; // [rsp+Ch] [rbp-34h] BYREF
char s[48]; // [rsp+10h] [rbp-30h] BYREF
strcpy(s, "flag{c0ngr@tul@ti0n_f0r_luck_numb3r}");
v4 = 0;
__isoc99_scanf(&unk_2004, &v4);
if ( v4 == 7 )
result = puts(s);
else
result = puts("sorry!");
return result;
}
flag为:flag{c0ngr@tul@ti0n_f0r_luck_numb3r}