Back

/ 5 min read

c逆向之分支与循环

if跳转

特征

  • 不满足向下跳转,汇编的跳转条件和源码中的逻辑取反。
  • if-else->cmp-比较取反+jmp-标签
  • 有可能使用return优化if最后的jmp跳转
  • 单分支很难优化,双分支、多分支优化空间大。

单分支

#include <cstdio>
#include <cstdint>
void test_if(uint32_t n1, int32_t n2){
// 单分支
if(n1 >= 10){
printf("n1 >= 10, n1: %u", n1);
}
if(n1 >= 20 && n2 < -15){
printf("n1 >= 20 && n2 < -15, n1: %u, n2: %d", n1, n2);
}
if(n1 >= 30 || n2 >= -15){
printf("n1 >= 20 && n2 < -15, n1: %u, n2: %d", n1, n2);
}
return;
}
unsigned __int64 `__local_stdio_printf_options'::`2'::_OptionsStorage DQ 01H DUP (?) ; `__local_stdio_printf_options'::`2'::_OptionsStorage
`string' DB 'n'
DB '1 >= 20 && n2 < -15, n1: %u, n2: %d', 00H ; `string'
`string' DB 'n1 >= 10, n1: %u', 00H ; `string'
_n1$ = 8 ; size = 4
_n2$ = 12 ; size = 4
void test_if(unsigned int,int) PROC ; test_if, COMDAT
push esi
mov esi, DWORD PTR _n1$[esp]
push edi
cmp esi, 10 ; 0000000aH
jb SHORT $LN2@test_if
push esi
push OFFSET `string'
call _printf
add esp, 8
$LN2@test_if:
mov edi, DWORD PTR _n2$[esp+4]
cmp esi, 20 ; 00000014H
jb SHORT $LN3@test_if
cmp edi, -15 ; fffffff1H
jge SHORT $LN3@test_if
push edi
push esi
push OFFSET `string'
call _printf
add esp, 12 ; 0000000cH
$LN3@test_if:
cmp esi, 30 ; 0000001eH
jae SHORT $LN5@test_if
cmp edi, -15 ; fffffff1H
jl SHORT $LN4@test_if
$LN5@test_if:
push edi
push esi
push OFFSET `string'
call _printf
add esp, 12 ; 0000000cH
$LN4@test_if:
pop edi
pop esi
ret 0
void test_if(unsigned int,int) ENDP ; test_if
image-20250119105807935
  • 跳转语句取反后是原本的if判断条件。

&&连接

image-20250119111431483
  • 每个表达式都取反。

||定式

最后一个||中的条件取反。

逆向还原时,最后一个条件取反

image-20250118154534163 image-20250118154741627

双分支

三目运算符优化

image-20250119112227251

代码外提-体积优化

image-20250118160542101

提出公共部分,逆向时不需要管。

image-20250118160810243 image-20250119113340157

减少跳转

image-20250118161013520 image-20250118161140573
?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA DQ 01H DUP (?) ; `__local_stdio_printf_options'::`2'::_OptionsStorage
??_C@_08IDOHMDJP@not?5all?$CB@ DB 'not all!', 00H ; `string'
??_C@_0BE@CAHAPFEI@n1?5?$DO?51?5?$CG?$CG?5n2?5?$DM?5100?6@ DB 'n1 > 1 && '
DB 'n2 < 100', 0aH, 00H ; `string'
??_C@_0BE@MPEFODFA@n1?5?$DO?$DN?55?5?$HM?$HM?5n2?5?$DM?510?6@ DB 'n1 >= 5'
DB ' || n2 < 10', 0aH, 00H ; `string'
??_C@_0BG@KGLBGBHM@n1?5?$DO?$DN?510?5?$HM?$HM?5n2?5?$DM?5?915?6@ DB 'n1 >'
DB '= 10 || n2 < -15', 0aH, 00H ; `string'
_n1$ = 8 ; size = 4
_n2$ = 12 ; size = 4
?test_if_else2@@YAXIH@Z PROC ; test_if_else2, COMDAT
mov eax, DWORD PTR _n1$[esp-4]
cmp eax, 10 ; 0000000aH
jae SHORT $LN4@test_if_el
mov ecx, DWORD PTR _n2$[esp-4]
cmp ecx, -15 ; fffffff1H
jl SHORT $LN4@test_if_el
; if(n1 >= 10 || n2 < -15) {printf("n1 >= 10 || n2 < -15\n"); return;}
cmp eax, 5
jae SHORT $LN7@test_if_el
cmp ecx, 10 ; 0000000aH
jl SHORT $LN7@test_if_el
; if(n1 >= 5 || n2 < 10) {printf("n1 >= 5 || n2 < 10\n"); return;}
cmp eax, 1
jbe SHORT $LN8@test_if_el
cmp ecx, 100 ; 00000064H
jge SHORT $LN8@test_if_el
; if(n1 > 1 && n2 < 100) {printf("n1 > 1 && n2 < 100\n"); return;}
mov eax, OFFSET ??_C@_0BE@CAHAPFEI@n1?5?$DO?51?5?$CG?$CG?5n2?5?$DM?5100?6@
push eax
call _printf
; printf("not all!");
; return;
pop ecx
ret 0
$LN8@test_if_el:
mov eax, OFFSET ??_C@_08IDOHMDJP@not?5all?$CB@
push eax
call _printf
pop ecx
ret 0
$LN7@test_if_el:
mov eax, OFFSET ??_C@_0BE@MPEFODFA@n1?5?$DO?$DN?55?5?$HM?$HM?5n2?5?$DM?510?6@
push eax
call _printf
pop ecx
ret 0
$LN4@test_if_el:
mov eax, OFFSET ??_C@_0BG@KGLBGBHM@n1?5?$DO?$DN?510?5?$HM?$HM?5n2?5?$DM?5?915?6@
push eax
call _printf
pop ecx
ret 0
?test_if_else2@@YAXIH@Z ENDP ; test_if_else2

switch分支

case小于等于3个

image-20250118163243167 image-20250119114855976 image-20250119114959865

大于3个分支

当大于三个分支且case中最大值和最小值的差值在255以内,此时会生成跳表。

image-20250118163614443 image-20250118163546270 image-20250118163528196 image-20250118163651464

跳表优化

双表优化

条件:最大值和最小值差值在0-255之间。

增加新的跳表下标表。

image-20250120102343840 image-20250118164600946

折半优化-二叉树优化

条件:差值较大

先判断中间条件。

image-20250118165526150 image-20250120102501249 image-20250120102727411

还原的时候也算是比较清晰的。

循环

所有循环的特征都是上跳。

do-while循环

特征:先执行再判断,向上跳转。

优化空间:平坦优化(可能)。

Debug、Release区别:无。

image-20250120104055044

while循环

特征:先判断再执行,向上跳转。

Debug、Release区别:Release优化为if + do-while循环(大部分情况)。

image-20250120104538977

for循环

MSVC+Debug版:1. 初始化 2. 步长 3. 比较 4. 循环体执行 5. 跳转2

image-20250118172738238

MSVC+Release版:(初始值确定)优化为do-while版。

image-20250120105242922