NightGlow 发表于 2023-7-19 20:03

攻防世界 Reverse Lucknum

#### 第一种方法:
1. 首先将文件拖入IDA 64,查找main函数


2. 观察发现main函数中存在一个判断。结合右侧“sorry”提示,估计为false。观察主函数汇编。

```asm
; 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 , rax ;将 rdx 寄存器中的值复制到内存中。内存的地址是通过 rbp(基指针)和 var_28 的偏移量计算得到的
mov   , rdx ;将 rdx 寄存器中的值复制到内存中的一个位置,这个位置是由基指针 rbp 和 var_28 的偏移量确定的。在这个例子中,var_28 是一个在之前定义的局部变量
mov   rax, 5F7230665F6E3069h ;将16进制数 5F7230665F6E3069 复制到 rax 寄存器中
mov   rdx, 6D756E5F6B63756Ch ;将16进制数 5F7230665F6E3069 复制到 rax 寄存器中
mov   , rax ;将 rax 寄存器中的值复制到内存中的一个位置,这个位置是由基指针 rbp 和 var_20 的偏移量确定的
mov   , rdx ;将 rdx 寄存器中的值复制到内存中的一个位置,这个位置是由基指针 rbp 和 var_18 的偏移量确定的
mov   , 7D723362h ;将16进制数 7D723362 复制到内存中的一个位置,这个位置是由基指针 rbp 和 var_10 的偏移量确定的
mov   , 0 ;将0值移动到内存的一个位置
mov   , 0 ;将0值移动到内存的一个位置
lea   rax, ;将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, ;将内存中的一个值移动到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 ;这是一个无条件跳转指令,它将控制流跳转到地址
```

栈图:

```sql
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
```

3. 通过观察`cmp   eax, 7 `,我们可以得出,如果当我们输入的值为7时,会跳转出我们想要的答案。放到Linux去进行尝试。

获得了flag为:flag{c0ngr@tul@ti0n_f0r_luck_numb3r}

#### 第二种方法:
1. 我们观察如果为True 跳转的代码块
```asm
lea   rax,
mov   rdi, rax      ; s
call    _puts
jmp   short loc_11D1
```
2. 发现调了一个_puts函数,看看里面会显示点什么。发现这段代码会将 `char s`里面的字符打印出来。推测在前面的几串hex有关。
通过编写代码进行尝试:

```python3
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; // BYREF
char s; // 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}

ncww 发表于 2023-7-21 10:45

能有个详细解说就好了,我们这些小白看的头晕

se34218 发表于 2023-7-21 12:08

能说详细点就好了,继续学校

xiong1017 发表于 2023-7-21 12:11

好东西呀

路过并看了一眼 发表于 2023-7-20 22:09

哇,太棒啦

Do_zh 发表于 2023-7-21 08:43

这是个说明书吧。{:1_921:}

marco527 发表于 2023-7-21 08:49

看不懂,不过还是要支持一下楼主!

ydna1234 发表于 2023-7-21 08:58

LZ最好能给个说明,对于某些小白来说(比如我)

wzbAwxl 发表于 2023-7-21 09:25

看不懂啊 呜呜呜

exiaowe 发表于 2023-7-21 10:20

好,就是看不懂而已
页: [1] 2
查看完整版本: 攻防世界 Reverse Lucknum