文章目录
- 结合源代码 + 汇编,完整逆向一次 `continue` 的真实执行路径
- 一、先从外层 for 入手(对照 C 看汇编)
- 二、外层循环体第一句:printf("up")
- 三、进入内层 for:结构先看清楚
- 四、内层循环体:continue 真正起作用的地方
- 1️⃣ printf("inner")
- 2️⃣ continue —— 核心就在这一条 jmp
- 五、从“源代码语义”到“汇编真实行为”
- 六、为什么 printf("down") 永远在 inner 循环之后?
- 七、从逆向角度总结 continue 的识别方法
- 八、一句话结尾(逆向视角)
结合源代码 + 汇编,完整逆向一次continue的真实执行路径
这段代码本身不复杂,但我关心的点只有一个:continue在汇编里到底体现在哪里?
先把完整 C 源码放出来,方便后面对照:
voidfunc2(){for(intindex=0;index<10;index++){printf("up");for(intinner_index=0;inner_index<10;inner_index++){printf("inner");continue;}printf("down");}}一、先从外层 for 入手(对照 C 看汇编)
C 代码:
for(intindex=0;index<10;index++)对应汇编:
00A51C06 mov dword ptr [ebp-8],0 ; index = 0 00A51C0D jmp 0A51C18h ; 先跳到条件判断 00A51C0F mov eax,dword ptr [ebp-8] ; index++ 00A51C12 add eax,1 00A51C15 mov dword ptr [ebp-8],eax 00A51C18 cmp dword ptr [ebp-8],0Ah ; index < 10 ? 00A51C1C jge 0A51C63h ; >=10 跳出外层循环看到这里基本不用想,这是MSVC 经典 for 模板:
- 初始化
- 跳条件
- 循环尾自增
- 判断失败跳出
外层循环只是“舞台”,真正的主角还在里面。
二、外层循环体第一句:printf(“up”)
C 代码:
printf("up");汇编:
00A51C1E push offset string "up" 00A51C23 call _printf 00A51C28 add esp,4没什么花样,继续往下。
三、进入内层 for:结构先看清楚
C 代码:
for(intinner_index=0;inner_index<10;inner_index++)对应汇编:
00A51C2B mov dword ptr [ebp-14h],0 ; inner_index = 0 00A51C32 jmp 0A51C3Dh ; 跳到条件判断 00A51C34 mov eax,dword ptr [ebp-14h] ; inner_index++ 00A51C37 add eax,1 00A51C3A mov dword ptr [ebp-14h],eax 00A51C3D cmp dword ptr [ebp-14h],0Ah ; inner_index < 10 ? 00A51C41 jge 0A51C54h ; >=10 跳出内层到这里我已经在心里标了三个关键地址:
0A51C34——自增位置0A51C3D——条件判断0A51C54——内层循环结束后的位置
这三个点,后面理解continue全靠它们。
四、内层循环体:continue 真正起作用的地方
1️⃣ printf(“inner”)
C 代码:
printf("inner");汇编:
00A51C43 push offset string "inner" 00A51C48 call _printf 00A51C4D add esp,4目前一切都还是“正常路径”。
2️⃣ continue —— 核心就在这一条 jmp
C 代码:
continue;对应的汇编只有一行:
00A51C50 jmp 0A51C34h我当时看到这里,第一反应就是去看0A51C34h在哪。
回头一对照:
00A51C34 mov eax,dword ptr [ebp-14h] 00A51C37 add eax,1 00A51C3A mov dword ptr [ebp-14h],eax正好是inner_index++。
五、从“源代码语义”到“汇编真实行为”
在 C 里我们习惯这样理解continue:
跳过本次循环剩余代码,进入下一次循环
但在汇编层面,它的真实含义是:
无条件跳转到循环的“自增语句位置”
也就是说,这一段逻辑:
printf("inner");continue;在 CPU 看来等价于:
printf("inner");gotoinner_index++;它不会跳到条件判断,也不会跳出循环,只是“提前走了一次循环尾”。
六、为什么 printf(“down”) 永远在 inner 循环之后?
C 代码:
printf("down");汇编位置:
00A51C54 push offset string "down" 00A51C59 call _printf 00A51C5E add esp,4而注意一个事实:
- 内层循环体里
每次都会执行jmp 0A51C34h - 永远不会顺序流执行到
0A51C54
只有当:
cmp inner_index, 0Ah jge 0A51C54条件失败(inner_index >= 10)时,
CPU 才会真正落到"down"这里。
七、从逆向角度总结 continue 的识别方法
结合这次完整对照,我给自己总结了一条非常好用的经验:
在循环体中看到一个
jmp:
- 如果跳到自增语句位置
👉continue- 如果跳到循环外部
👉break
不需要看符号,不需要看源码,只看跳转目标。
八、一句话结尾(逆向视角)
当你真正把 C 和汇编这样对着看完一次之后,continue这个关键字就“消失”了。
在逆向里,它只剩下一句话:
“哦,又是一个跳回自增位置的 jmp。”