引言
曾经,你以为只有源代码才是真理,汇编只是冰冷的机器残渣。 面对屏幕上杂乱无章的 JNZ 和 JMP,你感到过恐惧,就像在没有地图的迷宫中行走。
但在这个阶段,你练就了一双'透视之眼'。 你不再试图一行行去'读'代码,而是学会了去'看'结构。 你明白了:汇编不是乱码,它是被压扁了的逻辑。
你学会了在迷雾中插上路标(写注释),你学会了把破碎的镜子拼回原状(还原C语言)。 从此刻起,编译器不再是你的黑箱,而是你的笔友。 你听懂了它的方言。
Level_1
反汇编代码
c
__declspec(naked) int login_check(int password, int is_admin)
{
__asm {
// ... (函数头) ...
// === 检查 A ===
mov eax, dword ptr ds:[ebp + 8] ; 取 password
cmp eax, 123456 ; 比较 123456
je SHORT_PASS_OK ; 【注意看】JE = 相等跳转
// === 路径 B (密码不对走这里) ===
mov eax, 0 ; 返回 0
jmp SHORT_END ; 结束
SHORT_PASS_OK:
// === 检查 C (密码对了走这里) ===
mov eax, dword ptr ds:[ebp + 0xC] ; 取 is_admin
cmp eax, 1 ; 比较 1
je SHORT_ADMIN_LOGIN ; 【注意看】JE = 相等跳转
// === 路径 D (是普通人) ===
mov eax, 1 ; 返回 1
jmp SHORT_END
SHORT_ADMIN_LOGIN:
// === 路径 E (是管理员) ===
mov eax, 2 ; 返回 2
jmp SHORT_END
SHORT_END:
// ... (函数尾) ...
ret
}
}
具体代码
c
int login_check(int password, int is_admin)
{
if(password == 123456)
{
if(is_admin == 1)
{
return 2;
}
return 1;
}
return 0;
}
Level_2:殊途同归
反汇编代码
c
__declspec(naked) int can_equip(int level, int is_vip)
{
__asm {
// ... (函数头) ...
// === 第一道坎 ===
mov eax, dword ptr ds:[ebp + 8] ; 取 level
cmp eax, 50 ; 比较 50
jge SHORT_SUCCESS ; 【关键】如果 >= 50,直接跳去 SUCCESS
// === 第二道坎 (没跳走才会来这里) ===
mov eax, dword ptr ds:[ebp + 0xC] ; 取 is_vip
cmp eax, 1 ; 比较 1
je SHORT_SUCCESS ; 【关键】如果 == 1,也跳去 SUCCESS
// === 失败路径 (两个条件都没满足) ===
mov eax, 0 ; 返回 0 (不可装备)
jmp SHORT_END
SHORT_SUCCESS:
// === 成功路径 ===
mov eax, 1 ; 返回 1 (可以装备)
jmp SHORT_END
SHORT_END:
// ... (函数尾) ...
ret
}
}
具体代码
c
int can_equip(int level, int is_vip)
{
if(level >= 50 || is_vip == 1)
{
return 1;
}
return 0;
}
Level_3:严苛的门卫
反汇编代码
c
__declspec(naked) int login(int id, int password)
{
__asm {
// ... (函数头) ...
// === 第一关:检查 ID ===
mov eax, dword ptr ds:[ebp + 8] ; 取 id
cmp eax, 888 ; 比较 888
jne SHORT_FAIL ; 【关键】如果 != 888,直接踢去 FAIL
// === 第二关:检查 密码 (能走到这说明ID对了) ===
mov eax, dword ptr ds:[ebp + 0xC] ; 取 password
cmp eax, 123456 ; 比较 123456
jne SHORT_FAIL ; 【关键】如果 != 123456,也踢去 FAIL
// === 成功路径 (两关都过了) ===
mov eax, 1 ; 返回 1 (登录成功)
jmp SHORT_END
SHORT_FAIL:
// === 失败路径 ===
mov eax, 0 ; 返回 0 (登录失败)
jmp SHORT_END
SHORT_END:
// ... (函数尾) ...
ret
}
}
具体代码
c
int login(int id, int password)
{
if(id == 888 && password == 123456)
{
return 1;
}
return 0;
}
Level_4
反汇编代码
c
__declspec(naked) int func(int val)
{
__asm {
push ebp
mov ebp, esp
mov eax, dword ptr ds:[ebp + 8] //取出val放入寄存器
cmp eax, 10 //跟10进行比较
jl SHORT_LABEL_A //如果小于10,则跳转
//能执行到这里说明 val >= 10
mov eax, dword ptr ds:[ebp + 8] //重新取出val
cmp eax, 20 //跟20进行比较
jg SHORT_LABEL_A //如果大于20说明进行跳转
//到此为止,得出以下结论, 10<= val <= 20
mov eax, 1 //return 1
jmp SHORT_END
SHORT_LABEL_A: //return 0
xor eax, eax
SHORT_END:
pop ebp
ret
}
}
具体代码
c
int func(int val)
{
if(10 <= val && val <=20)
{
return 1;
}
return 0;
}
Level_5
反汇编代码
c
__declspec(naked) int func(int n)
{
__asm {
push ebp
mov ebp, esp
//核心代码
mov eax, dword ptr ds:[ebp + 8] //取出n放入寄存器
cmp eax, 0 //跟0进行比较
jg SHORT_LABEL_A //大于0,进行跳转_A
mov eax, dword ptr ds:[ebp + 8] //重新取出n放入寄存器
cmp eax, 0 //跟0进行比较
jl SHORT_LABEL_B //小于0,进行跳转_B
//执行核心代码
mov eax, 0 //return 0
jmp SHORT_END
SHORT_LABEL_A:
mov eax, 1 //return 1
jmp SHORT_END
SHORT_LABEL_B:
mov eax, -1 //return -1
jmp SHORT_END
SHORT_END:
pop ebp
ret
}
}
具体代码
c
int func(int n)
{
if(n > 0)
{
return 1;
}
if(n < 0)
{
return -1;
}
return 0;
}
Level_6
反汇编代码
c
__declspec(naked) int logic_maze(int a, int b)
{
__asm {
push ebp
mov ebp, esp
; === 第一阶段 ===
mov eax, dword ptr ds:[ebp + 8] //取出a
cmp eax, dword ptr ds:[ebp + 0xC] //跟b进行比较
jle SHORT_PATH_BLUE //如果小于等于则跳转
; === 红色路径 (a > b) ===
mov eax, dword ptr ds:[ebp + 8] //取出a,放入寄存器中
cmp eax, 100 //跟100进行比较
jge SHORT_RED_BOSS //大于等于即可跳转
//没有跳转,则执行下面代码
mov eax, 1 ; 普通红色怪
jmp SHORT_END //对eax进行赋值1,然后跳转到集合点
//标签_boss
SHORT_RED_BOSS:
mov eax, 100 ; 红色BOSS
jmp SHORT_END //对eax进行赋值100,然后跳转到集合点
SHORT_PATH_BLUE:
; === 蓝色路径 (a <= b) ===
mov eax, dword ptr ds:[ebp + 0xC]
cmp eax, 100
jge SHORT_BLUE_BOSS
mov eax, 2 ; 普通蓝色怪
jmp SHORT_END
SHORT_BLUE_BOSS:
mov eax, 200 ; 蓝色BOSS
jmp SHORT_END
SHORT_END:
pop ebp
ret
}
}
具体代码
c
int logic_maze(int a, int b)
{
if(a > b)
{
if(a < 100)
{
return 1;
}
else
{
return 100;
}
}
else
{
if(b < 100)
{
return 2;
}
else
{
return 200;
}
}
}
Level_7
反汇编代码
c
__declspec(naked) int final_exam(int a, int b, int c)
{
__asm {
push ebp
mov ebp, esp
sub esp, 4 ; 开辟空间给局部变量 result
; === [Block 1] ===
mov dword ptr ds:[ebp - 4], 0 ; 初始化 result = 0
; === [Block 2] ===
mov eax, dword ptr ds:[ebp + 8]
cmp eax, 0
jl SHORT_ERROR ; 检查 a,小于0进行跳转
mov eax, dword ptr ds:[ebp + 0xC]
cmp eax, 0
jl SHORT_ERROR ; 检查 b,小于0进行跳转
mov eax, dword ptr ds:[ebp + 0x10]
cmp eax, 0
jl SHORT_ERROR ; 检查 c,小于0进行跳转
//外层if
; === [Block 3] ===
mov eax, dword ptr ds:[ebp + 8]
cmp eax, 50
jle SHORT_LOW_TIER ; 关键:如果 a <= 50,去低级区
//相干留下,继续执行下面判断
mov eax, dword ptr ds:[ebp + 0xC]
cmp eax, 50
jle SHORT_LOW_TIER ; 关键:如果 b <= 50,也去低级区
//这里可以得到结论 if(a > 50 && b > 50),否则跳转
//里层if
; === [Block 4: High Tier] ===
; 能走到这里,说明 a > 50 并且 b > 50
mov dword ptr ds:[ebp - 4], 100 ; result = 100
mov eax, dword ptr ds:[ebp + 0x10]
cmp eax, 50
jle SHORT_END ; 如果 c <= 50,结束
add dword ptr ds:[ebp - 4], 100 ; result += 100
jmp SHORT_END ; 强制结束
//外层else
SHORT_LOW_TIER:
; === [Block 5: Low Tier] ===
mov dword ptr ds:[ebp - 4], 10 ; result = 10
mov eax, dword ptr ds:[ebp + 0x10]
cmp eax, 20
jle SHORT_END ; 如果 c <= 20,结束
add dword ptr ds:[ebp - 4], 20 ; result += 20
jmp SHORT_END
//返回-1
SHORT_ERROR:
; === [Block 6: Error] ===
mov eax, -1
jmp SHORT_RET
SHORT_END:
; === [Block 7: Success Return] ===
mov eax, dword ptr ds:[ebp - 4] ; 把 result 放入返回值
SHORT_RET:
mov esp, ebp
pop ebp
ret
}
}
具体代码
c
int final_exam(int a, int b, int c)
{
int result = 0;
if(a < 0 || b < 0 || c < 0)
{
return -1;
}
if(a > 50 && b > 50)
{
result = 100;
if(c > 50)
{
result += 100;
}
}
else
{
result = 10;
if(c > 20)
{
result += 20;
}
}
return result;
}
战利品
-
逻辑的形状 (Shape of Logic):
-
IF 的本质: 看透了 CMP + Jcc 的二元对立。
-
殊途同归 (||): 识别出多个跳转指向同一个"成功地"即为逻辑或。
-
一票否决 (&&): 识别出多个跳转指向同一个"失败地"即为逻辑与。
-
-
层级的重建 (Hierarchy Reconstruction):
- 克服了汇编"扁平化"的视觉欺骗,能够从线性的指令中还原出嵌套 (Nested) 的立体结构(盒子里套盒子)。
-
补集思维 (Complementary Thinking):
- 建立了"反向跳转 = 正向逻辑"的直觉。看到
JLE(小于等于跳走),脑中直接映射出 if ( > ) (大于则留下)。
- 建立了"反向跳转 = 正向逻辑"的直觉。看到
-
迷雾拼图法 (The Fog Puzzle Method):
- 这是本卷最重要的心法。 养成了 "读一行、注一行、不急看终点" 的工程习惯。学会了先切分基本块 (Basic Block),再进行逻辑合并。
结语
我们已经征服了'分叉路口'。 在你的剑下,所有的 IF 和 ELSE 都已现出原形。 你证明了自己拥有在静态的迷宫中找到出口的能力。
但计算机的世界不仅仅是静态的选择,更是动态的律动。 接下来,我们要面对的是时间的魔法------循环 (Loop)。 路不再只是向前延伸,它会卷曲、折叠、首尾相连。
这将是一场对耐心的终极考验。 但既然你已拥有透视之眼,那些周而复始的圆圈,终将化作你登云的阶梯。