大理寺少卿 发表于 2025-5-18 16:04:29

X86C++反汇编09.switch case语句

### case 分支不超过3个

当 case 分支少于3个,不会怎么优化,直接3个跳转,这种很像if esle ,但是跟if esle 有区别,它跳转和跳转之间没有实质性代码,只有影响标志位代码

其次 它的代码结构分2部分

!(./notesimg/1657939310023-3fb0c50d-65e9-43a4-bb13-cdd5e9d016dc.png)

而且必须这么设计,因为break的原因

case种有break 就跳走,没有的话就顺着走,且不做判定,一旦把case 值:   插入casejxx 那么一旦遇到break,就要做比较

```
int main(int argc, char* argv[])
{
   switch(argc)
   {
   case 0:
       printf("case 0");
   case 1:
       printf("case 1");
       break;
   case 2:
       printf("case 2");
   }
   return 0;
}

反汇编代码:
debug 版
       mov   eax,
       mov   , eax
       cmp   , 0
       jz      short loc_401042
       cmp   , 1
       jz      short loc_40104F
       cmp   , 2
       jz      short loc_40105E
       jmp   short loc_40106B
loc_401042:                        
       push    offset Format   ; "case 0"
       call    _printf
       add   esp, 4
loc_40104F:                        
       push    offset aCase1   ; "case 1"
       call    _printf
       add   esp, 4
       jmp   short loc_40106B
loc_40105E:                           
       push    offset aCase2   ; "case 2"
       call    _printf
       add   esp, 4
loc_40106B:

分析:遇到上面定式,就可以判断位 switch case ,还原时就可以无脑还原 ,jxx 比的是谁 case 就是 谁,而且需要看最后一个跳转,如果是jne或者jnz 就是default 或者 switch end , jne 或者 jnz后面的jmp 就是 case,否则如果是 jz 或者je,后面的jmp 就是    default 或者 switch end

release 版有优化
       mov   eax,
       sub   eax, 0
       jz      short loc_40101F   ;case 0
       dec   eax                           
       jz      short loc_40102C   ;case1
       dec   eax
       jnz   short loc_401039      ;case2 ,因为前面已经减1,再减1就是 减2
       push    offset aCase2   ; "case 2"
       call    sub_401040
       add   esp, 4
       xor   eax, eax
       retn
loc_40101F:                           
       push    offset aCase0   ; "case 0"
       call    sub_401040
       add   esp, 4
loc_40102C:                           
       push    offset aCase1   ; "case 1"
       call    sub_401040
       add   esp, 4
loc_401039:

分析: 有无default 的的区别 看把 break;   break 肯定不执行 default的代码,break肯定跳到 switchend
看判断 跟 jnz 跳出的是不是同一个点,是的话就没有 default ,否则就是有
int main(int argc, char* argv[])
{
   switch(argc)
   {
   default:
         printf("default:");
         break;
   case 0:
       printf("case 0");
   case 1:
       printf("case 1");
       break;
   case 2:
       printf("case 2");
   }
   return 0;
}
反汇编代码;
       mov   eax,
       sub   eax, 0
       jz      short loc_40102F      ; -0 = 0 CASE 0
       dec   eax
       jz      short loc_40103C      ; -1= 0 CASE 1
       dec   eax
       jz      short loc_40101F       ; -1-1= 0 CASE 2
      ;default
       push    offset aDefault ;   "default:"
       call    sub_401050
       add   esp, 4
       xor   eax, eax
       retn
loc_40101F:                           
       push    offset aCase2   ; "case 2"
       call    sub_401050
       add   esp, 4
       xor   eax, eax
       retn
loc_40102F:                        
       push    offset aCase0   ; "case 0"
       call    sub_401050
       add   esp, 4
loc_40103C:                        
       push    offset aCase1   ; "case 1"
       call    sub_401050
```

### case 分支大于3 且较为连续

会做表

```
int main(int argc, char* argv[])
{
   switch(argc)
   {
   default:
         printf("default:");
         break;
   case 0:
       printf("case 0");
   case 1:
       printf("case 1");
       break;
   case 2:
       printf("case 2");
   case 3:
       printf("case 3");
   case 5:
       printf("case 5");
   case 6:
       printf("case 6");
   }
   printf("hello");
   printf("hello");
   return 0;
}
反汇编代码:
       mov   eax,
       mov   , eax
       cmp   , 6            ;跟 case值的区间比较
       ja      short def_40D747         ;这里就是 switch end 或者default,至于是否有 default 需要后面验证
       mov   ecx,
       jmp   ds:jpt_40D747      ; 寻址数组首地址40D747
def_40D747:                                                                                                                                  
       push    offset Format   ; jumptable 0040D747 default case, case 4
       call    _printf
       add   esp, 4
       jmp   short loc_40D7AD
loc_40D75D:                        
       push    offset aCase0   ; jumptable 0040D747 case 0
       call    _printf
       add   esp, 4
loc_40D76A:                           ;
       push    offset aCase1   ; jumptable 0040D747 case 1
       call    _printf
       add   esp, 4
       jmp   short loc_40D7AD
loc_40D779:                           
       push    offset aCase2   ; jumptable 0040D747 case 2
       call    _printf
       add   esp, 4
loc_40D786:                        
       push    offset aCase3   ; jumptable 0040D747 case 3
       call    _printf
       add   esp, 4
loc_40D793:
       push    offset aCase5   ; jumptable 0040D747 case 5
       call    _printf
       add   esp, 4
loc_40D7A0:
       push    offset aCase6   ; jumptable 0040D747 case 6
       call    _printf
       add   esp, 4
loc_40D7AD:                        
       push    offset aHello   ; "hello"
       call    _printf
       add   esp, 4
       push    offset aHello   ; "hello"
       call    _printf
```

分析:

先观察 eax 的取值范围(0-6),在跳转到调表 ,分别命名为 0 - 6,接着看每个case,看谁有 break,找到有break 的地方直接命名为default ,接着论证 default 分时是否存在,当把代码外提,内联都搞清楚以后如果 default 和 switch end 重合,说明没有default分支

**跳表的数组**

!(./notesimg/1657941177776-0cdd6657-5c8e-47b8-a3ac-1eda98767e63.png)

!(./notesimg/1657941673648-7e84392b-23a1-44fc-8736-d11f6cac38ca.png)

当如果case 不是从 0 - 6 而是 100 -106 , 那么就会 先减去最小 case 值

```
int main(int argc, char* argv[])
{
    switch (argc)
    {
    default:
      printf("default:");
      break;
    case 100:
      printf("case 0");
    case 101:
      printf("case 1");
      break;
    case 102:
      printf("case 2");
    case 103:
      printf("case 3");
    case 105:
      printf("case 5");
    case 106:
      printf("case 6");
    }
    printf("hello");
    printf("hello");
    return 0;
}
反汇编代码:
```

!(./notesimg/1657941995308-75d37b84-3af8-4b2d-b924-e75e72c852ad.png)

### case分支大于3且不连续

case 的 值区间超过12 ,就会换方案

再按上面坐标 ,需要很多四字节来放地址 ,大部分都是 default ,所以不划算

```
int main(int argc, char* argv[])
{
    switch (argc)
    {
    default:
      printf("default:");
      break;
    case 100:
      printf("case 0");
    case 111:
      printf("case 1");
      break;
    case 122:
      printf("case 2");
    case 133:
      printf("case 3");
    case 145:
      printf("case 5");
    case 156:
      printf("case 6");
    }
    printf("hello");
    printf("hello");
    return 0;
}

反汇编代码:
       push    ebp
       mov   ebp, esp
       mov   eax,
       add   eax, 0FFFFFF9Ch ; switch 57 cases
       cmp   eax, 38h
       ja      short $LN4   
       movzx   eax, ds:byte_4010E0   ;第一次寻址
       jmp   ds:jpt_401055                ;;第二次寻址

$LN5:                                 
       push    offset _Format; jumptable 00401055 case 100
       call    _printf
       add   esp, 4
$LN6:                              
       mov   eax, offset aCase1 ; jumptable 00401055 case 111
       jmp   short loc_4010A3
$LN7:                           
       push    offset aCase2   ; jumptable 00401055 case 122
       call    _printf
       add   esp, 4

$LN8:                              
       push    offset aCase3   ; jumptable 00401055 case 133
       call    _printf
       add   esp, 4
$LN9:                                 
       push    offset aCase5   ; jumptable 00401055 case 145
       call    _printf
       add   esp, 4
$LN10:                              
       mov   eax, offset aCase6 ; jumptable 00401055 case 156
       jmp   short loc_4010A3
$LN4:      
       mov   eax, offset aDefault ;
loc_4010A3:                     
       push    eax             ; _Format
       call    _printf
       push    offset aHello   ; "hello"
       call    _printf
       push    offset aHello   ; "hello"
       call    _printf
```

分析:采用二次寻址来方式 来获取跳转地址

先用 一个 int 数组 保存 case 的 跳转坐标 ,在用一个char 数组保存每个 case 区间值 跳转 的 坐标 在坐标数组的索引, 访问时现根据索引数组 拿索引,在 把索引转 整形 到坐标数组拿对应坐标,再跳转

!(./notesimg/1657946051061-557732c7-1dfb-4ae8-a102-fdfa23857178.png)

说明case 的区间是100-156

对应的下标索引表

!(./notesimg/1657946142700-f6d543d5-c27d-460b-ba1a-30567bddf0b0.png)

因为大部分是 default ,所以 6对应的   derault 跳转的地址,然后 其他 非 6 值 表示case的的值

例如 0   表示100 +0 = 100 => case 100   表示坐标表索引为0的坐标就是 case100 跳转的坐标,       1=> 100 +11 = 111 => case111    表示坐标表索引为1的坐标就是 case111 跳转的坐标,2 => 100 + 22 => case 122   表示坐标表索引为2的坐标就是 case122 跳转的坐标, 100表示 case 最小值 , 后面加的值表示在数组中的索引

对应的地址表:

!(./notesimg/1657946538039-1ed0412a-d1a9-4973-9517-b3d323065db3.png)

!(./notesimg/1657946225068-892c81d8-9ce5-4e3c-8690-dbca6845e97b.png)

带位图的位图保存方式   **CreateCompatibleBitmap**

!(./notesimg/1657942852857-051761d0-39b8-40e9-b173-fa246746a68c.png)

先用一个数组保存 颜色种类(调色板),在用另一个 char 数组 保存每个 坐标 对应的 颜色在 颜色数组的下标,这样就只需要一个 char 数组就可以了,这样就不需要用int 数组 , 因此可以节省大量空间 ,但缺点就是需要2次 数组寻址,需要先在坐标数组 取出   对应颜色的下标转成整形 ,在根据下标在 颜色数组取出对应的颜色 ,而且颜色种类不能超过256种

### 混合方案

switch   是一个多分支的机器优化方案,优化的时候视为各个分支节点命中率均等,且必须是整形 或 类整形.不能是区间和浮点,

```
int main(int argc, char* argv[])
{
    switch (argc)
    {
    default:
      printf("default:");
      break;
case 100:
      printf("case 0");
case 200:
      printf("case 0");
case 300:
      printf("case 0");
case 400:
      printf("case 0");
case 500:
      printf("case 0");
case 1100:
      printf("case 0");
case 2111:
      printf("case 1");
      break;
case 3122:
      printf("case 2");
case 4133:
      printf("case 3");
case 5545:
      printf("case 5");
case 6656:
      printf("case 6");
    }
    printf("hello");
    printf("hello");
    return 0;
}

编译器优化时,使用 平衡比较数来优化   会先对csae 的值进行排序

100      200      300   400   500   1100    2111   3122   4133    5545   6656

然后先比 中间值    1100
如果 等于 直接走   
如果小于    在 跟左边 比较,跟左边比较 是也会 先跟中间值比较
如果   大于    在 跟到边 比较,跟右边比较 是也会 先跟中间值比较
一直递归比较值回到 一边值 满足上面 3种情况之一 ,就采用上面 的 对应的优化方案
                                                                1100
                                 <                           =                                  >
                                  300                                                            4133
   <                            =                        >             <                            =                        >
=100, =200                              =400,=500   =2111, =3122                                    =5545,=6656

这种方案还原 直接找等于 就行了 ,大于小于 都是引导,等于的值 就是 case值
比较大于,小于,等于 2个跳转就够了,因此上式的特征就是很多 2跳在一起 ,其中 je 肯定有, 另一个 jg 或 jl 之一
```

### 周末作业

1. GreenVPN 对配置文件进行了加密 分析,解析出解密算法,并用高级语言还原出源码,并解密出远程服务器信息相关的密文。

思路:   既然是对配置文件信息解密,那么肯定会先读取配置文件,再对配置文件的内容 进行 解密

步骤:

先通过OD 打开 可执行文件,在careteFileapi上设置断点

!(./notesimg/1657970051656-526f2dba-2984-4ea5-b43b-06aaf0ea73fc.png)

获取缓冲区大小

!(./notesimg/1657971444922-fd4aba6c-06e9-44f1-842b-c4f03c082b05.png)

对缓冲区字符进行转义

!(./notesimg/1657971684720-cbb0bae2-5a6c-48a1-890f-9374fe24645d.png)

因此可以推测这块就是解密算法

!(./notesimg/1657971732320-6078f5b7-e6e5-4930-9cf1-fa443037379b.png)

直接跑完这段断码.可以发现 配置文件已经解密了

!(./notesimg/1657971768140-fa70ce38-16b2-4987-baee-e1b14b320402.png)

所以解密算法是

```
00407704|> /8A11          /mov   dl, byte ptr
00407706|. |80F2 BD       |xor   dl, 0BD
00407709|. |80C2 69       |add   dl, 69
0040770C|. |8811          |mov   byte ptr , dl
0040770E|. |41            |inc   ecx
0040770F|. |48            |dec   eax
00407710|.^\75 F2         \jnz   short 00407704
```

1. 解密编译器求幻数

C2.DLL

这个dll 是通过loadlibrary 加载的

调试方法:   用 OD 打开   CL.EXE

!(./notesimg/1658054904899-eb0348d3-ab78-4133-8d86-9fd08f8c2c42.png)

!(./notesimg/1658056767025-1a719406-0f29-47eb-a192-e8fb9cef945c.png)

然后在 loadlibrary api上下断点

第二次断下来的时候就是 C2.DLL

!(./notesimg/1658056411419-eadec1ce-c543-469a-bbfc-6d8002c51f52.png)

解决不认识   stdio.h,配置环境变量

!(./notesimg/1658056268579-a8e0a7e0-0940-40a3-9672-bc8d3afe7a36.png)

解决字符问题:   用vc6.0 写程序,不要用vs2019

!(./notesimg/1658056825504-958a91d6-5d5b-446e-a9cc-c0557f89f0bc.png)

样本中关键算法(文件偏移5FACE处)。

!(./notesimg/1658058306190-52dabe63-e7fa-4c16-9f92-1451edc5b379.png)

!(./notesimg/1658056797989-c63ee28b-03f6-4cdd-862b-9f57f885be94.png)

```
1075EACE    83EC 08         sub   esp, 8
1075EAD1    83F9 03         cmp   ecx, 3
1075EAD4    894C24 04       mov   dword ptr , ecx
1075EAD8    7C 10         jl      short 1075EAEA
1075EADA    83F9 0D         cmp   ecx, 0D
1075EADD    73 0B         jnb   short 1075EAEA
1075EADF    8D04CD D8E07A10 lea   eax, dword ptr
1075EAE6    83C4 08         add   esp, 8
1075EAE9    C3            retn
//算法开始
1075EAEA    8BC1            mov   eax, ecx
1075EAEC    53            push    ebx
1075EAED    55            push    ebp
1075EAEE    56            push    esi
1075EAEF    99            cdq
1075EAF0    57            push    edi
1075EAF1    8BF1            mov   esi, ecx
1075EAF3    8BF8            mov   edi, eax
1075EAF5    BB 00000080   mov   ebx, 80000000
1075EAFA    C1EE 1F         shr   esi, 1F
1075EAFD    33FA            xor   edi, edx
1075EAFF    81EE 00000080   sub   esi, 80000000
1075EB05    2BFA            sub   edi, edx
1075EB07    8BC6            mov   eax, esi
1075EB09    33D2            xor   edx, edx
1075EB0B    C74424 10 1F000>mov   dword ptr , 1F
1075EB13    F7F7            div   edi
1075EB15    B8 00000080   mov   eax, 80000000
1075EB1A    2BF2            sub   esi, edx
1075EB1C    33D2            xor   edx, edx
1075EB1E    4E            dec   esi
1075EB1F    F7F6            div   esi
1075EB21    33D2            xor   edx, edx
1075EB23    8BE8            mov   ebp, eax
1075EB25    0FAFC6          imul    eax, esi
1075EB28    2BD8            sub   ebx, eax
1075EB2A    B8 00000080   mov   eax, 80000000
1075EB2F    F7F7            div   edi
1075EB31    BA 00000080   mov   edx, 80000000
1075EB36    8BC8            mov   ecx, eax
1075EB38    0FAFC7          imul    eax, edi
1075EB3B    2BD0            sub   edx, eax
1075EB3D    EB 08         jmp   short 1075EB47
1075EB3F    8BC7            mov   eax, edi
1075EB41    2BC2            sub   eax, edx
1075EB43    3BE8            cmp   ebp, eax
1075EB45    73 22         jnb   short 1075EB69
1075EB47    8B4424 10       mov   eax, dword ptr
1075EB4B    03DB            add   ebx, ebx
1075EB4D    40            inc   eax
1075EB4E    03ED            add   ebp, ebp
1075EB50    3BDE            cmp   ebx, esi
1075EB52    894424 10       mov   dword ptr , eax
1075EB56    0F83 AB080300   jnb   1078F407
1075EB5C    03D2            add   edx, edx
1075EB5E    03C9            add   ecx, ecx
1075EB60    3BD7            cmp   edx, edi
1075EB62^ 72 DB         jb      short 1075EB3F
1075EB64    41            inc   ecx
1075EB65    2BD7            sub   edx, edi
1075EB67^ EB D6         jmp   short 1075EB3F
1075EB69    0F84 A0080300   je      1078F40F
1075EB6F    8D41 01         lea   eax, dword ptr
//算法结束
1075EB72    8B4C24 14       mov   ecx, dword ptr
1075EB76    5F            pop   edi
1075EB77    5E            pop   esi
1075EB78    5D            pop   ebp
1075EB79    A3 90F07910   mov   dword ptr , eax
1075EB7E    85C9            test    ecx, ecx
1075EB80    5B            pop   ebx
1075EB81    0F8C 95080300   jl      1078F41C
1075EB87    8B4C24 00       mov   ecx, dword ptr
1075EB8B    B8 90F07910   mov   eax, 1079F090
1075EB90    83C1 E0         add   ecx, -20
1075EB93    890D 94F07910   mov   dword ptr , ecx
1075EB99    83C4 08         add   esp, 8
1075EB9C    C3            retn

```

自己找 算法的方法:

!(./notesimg/1658199573246-e42510bf-e3f8-4c0b-8685-ccdca5b744ca.png)

```
// CLProject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <stdio.h>
#include <stdlib.h>

int g_nExp = 0; //指数
int g_nMagicNumber = 0; //幻数

int Test(int Divisor) {

//.text:1075EACE               sub   esp, 8
    int ecx = Divisor;
//.text:1075EAD1               cmp   ecx, 3
//.text:1075EAD4               mov   , ecx
//.text:1075EAD8               jl      short loc_1075EAEA
//.text:1075EADA               cmp   ecx, 13
//.text:1075EADD               jnb   short loc_1075EAEA
    if (ecx >= 3 && ecx < 13) {
    //.text:1075EADF               lea   eax, dword_107AE0D8
    //.text:1075EAE6               add   esp, 8
    //.text:1075EAE9               retn

      printf("需要查表\r\n");
      return 0;
    }
//.text:1075EAEA loc_1075EAEA:                     
//.text:1075EAEA                                    
//.text:1075EAEA               mov   eax, ecx
//.text:1075EAEC               push    ebx
//.text:1075EAED               push    ebp
//.text:1075EAEE               push    esi
//.text:1075EAEF               cdq                ;流水线优化的代码,可以后提            
//.text:1075EAF0               push    edi
//.text:1075EAF1               mov   esi, ecx
//.text:1075EAF3               mov   edi, eax
//.text:1075EAF5               mov   ebx, 80000000h
    int eax = ecx;
    unsigned int esi = ecx;
    int edi = eax;
    unsigned int ebx = 0x80000000;
//.text:1075EAFA               shr   esi, 1Fh
    esi = esi >> 31; //能这么移说明它是无符号的
//                               cdq                        ;流水线优化的代码可以提到这里
//.text:1075EAFD               xor   edi, edx
//.text:1075EB05               sub   edi, edx         ;流水线优化的代码
    edi = abs(eax); //绝对值
//.text:1075EAFF               sub   esi, 80000000h   ;流水线优化的代码
    esi = esi - 0x80000000;

//.text:1075EB0B               mov   , 1Fh
    int nExp = 31;

//.text:1075EB07               mov   eax, esi ;两处流水线优化,调整到这里
//.text:1075EB09               xor   edx, edx
//.text:1075EB13               div   edi
//.text:1075EB1A               sub   esi, edx
//.text:1075EB1E               dec   esi
    esi = esi - esi % edi - 1;

//.text:1075EB15               mov   eax, 80000000h
//.text:1075EB1F               div   esi
//.text:1075EB21               xor   edx, edx
//.text:1075EB23               mov   ebp, eax
    unsigned int ebp = 0x80000000 / esi;
//.text:1075EB25               imul    eax, esi
//.text:1075EB28               sub   ebx, eax
    ebx = ebx - ebp * esi;
//.text:1075EB2A               mov   eax, 80000000h
//.text:1075EB1C               xor   edx, edx
//.text:1075EB2F               div   edi
//.text:1075EB36               mov   ecx, eax
    ecx = 0x80000000 / edi;
//.text:1075EB38               imul    eax, edi
//.text:1075EB31               mov   edx, 80000000h
//.text:1075EB3B               sub   edx, eax
    int edx = 0x80000000 - ecx * edi;
//.text:1075EB3D               jmp   short LOOP_BEGIN2 ;直接跳到循环体内了
//.text:1075EB3F ; ---------------------------------------------------------------------------
//.text:1075EB3F
//.text:1075EB3F LOOP_BEGIN://;这里相当于第一次不执行,后续循环再执行,将EB3F的代码挪到调用的地方,这块就不存在了
//.text:1075EB3F               mov   eax, edi
//.text:1075EB41               sub   eax, edx
//.text:1075EB43               cmp   ebp, eax
//.text:1075EB45               jnb   short loc_1075EB69

//.text:1075EB3F            
    do {

      //.text:1075EB47
      //.text:1075EB47 LOOP_BEGIN2:                     
      //.text:1075EB47                                    
      //.text:1075EB47               mov   eax,
      //.text:1075EB4D               inc   eax
      eax = nExp + 1;
      //.text:1075EB4B               add   ebx, ebx
      ebx = ebx * 2;
      //.text:1075EB4E               add   ebp, ebp
      ebp = ebp * 2;

      //.text:1075EB52               mov   , eax ;这句可以提到上面,就相当于nExp++;
      nExp = eax;
      //.text:1075EB50               cmp   ebx, esi
      //.text:1075EB56               //jnb   loc_1078F407改为 jb loc_1075EB5C

      //;这里是跳到外部游离代码处,把游离代码贴回来后就要修改条件,jnb 跳到游离代码,就要改为jb 跳到下面的地方 loc_1075EB5C
      // 之前是不小于则跳到游离代码,现在改为小于则跳到原先下面的代码,也就是不小于的话不跳,照常执行游离代码

      if(ebx >= esi){
            //.text:1078F407 loc_1078F407 :                     ;把游离代码贴回来
            //.text : 1078F407               inc   ebp
            ebp++;
            //.text : 1078F408               sub   ebx, esi
            ebx = ebx - esi;
            //.text : 1078F40A               jmp   loc_1075EB5C ;这一句就没用了

      }

      //.text:1075EB5C loc_1075EB5C:                     
      //.text:1075EB5C               add   edx, edx
      edx = edx * 2;
      //.text:1075EB5E               add   ecx, ecx
      ecx = ecx * 2;
      //.text:1075EB60               cmp   edx, edi
      //.text:1075EB62               jb      short LOOP_BEGIN ?
      if(edx < edi ){
            //可以把EB3F的代码搬到这里来,jb 还原为if ,成立就跳到这里
            //.text:1075EB3F               mov   eax, edi
            //.text:1075EB41               sub   eax, edx
            eax = edi - edx;
            //.text:1075EB43               cmp   ebp, eax
            //.text:1075EB45               jnb   short loc_1075EB69;不小于还原为等于,但由于EB69出还有个jnz所以只能是大于了
            if (ebp > eax) {
                break;
            }
            continue;
      }


      //.text:1075EB64               inc   ecx
      ecx++;
      //.text:1075EB65               sub   edx, edi
      edx = edx - edi;
      //EB3F的代码
      //.text:1075EB3F               mov   eax, edi
      eax = edi;
      //.text:1075EB41               sub   eax, edx
      eax = eax - edx; //?
      //.text:1075EB43               cmp   ebp, eax
      //.text:1075EB45               jnb   short loc_1075EB69
      if (ebp < eax) {
            //.text:1075EB67               jmp   short LOOP_BEGIN   ;
               //可以把EB3F的代码搬到这里来,jb 还原为if ,成立就跳到这里
            //.text:1075EB3F               mov   eax, edi
            //.text:1075EB41               sub   eax, edx
            eax = edi - edx;
            //.text:1075EB43               cmp   ebp, eax
            //.text:1075EB45               jnb   short loc_1075EB69;不小于还原为等于,但由于EB69出还有个jnz所以只能是大于了
            if (ebp > eax) {
                break;
            }
            continue;
      }

//.text:1075EB69 loc_1075EB69:                     
//.text:1075EB69               jnz      LOOPEND;jz      loc_1078F40F 满足条件则执行,改为不满足条件跳下面的代码
      if(ebp>eax){
            break;
      }
      //外提代码贴回来
      //.text:1078F40F loc_1078F40F:                     
      //.text:1078F40F               test    ebx, ebx
      //.text:1078F411               jz      LOOP_BEGIN2
      if (ebx != 0) { //避免每次continue检查ebx,所以直接写为死循环,然后判断ebx
            break;
      }
    } while (1);


//.text:1075EB6F
//.text:1075EB6F LOOPEND:                     
//.text:1075EB6F               lea   eax,
    eax = ecx + 1;
//.text:1075EB72               mov   ecx,
    ecx = Divisor;
//.text:1075EB76               pop   edi
//.text:1075EB77               pop   esi
//.text:1075EB78               pop   ebp
//.text:1075EB79               mov   ds:dword_1079F090, eax
    g_nMagicNumber = eax;
//.text:1075EB7E               test    ecx, ecx
//.text:1075EB80               pop   ebx
//.text:1075EB81               jnl      loc_1075EB87 ;同样修改一下,满足条件跳下面的代码,不满足则执行游离代码
    if(ecx < 0){
    //游离代码
    // .text:1078F41C loc_1078F41C:                     
    //.text:1078F41C               neg   eax
    //.text:1078F41E               mov   ds:dword_1079F090, eax
      g_nMagicNumber = -eax;
    //.text:1078F423               jmp   loc_1075EB87
    }
//.text:1075EB87
//.text:1075EB87 loc_1075EB87:                     
//.text:1075EB87               mov   ecx, ;局部指数变量
//.text:1075EB8B               mov   eax, offset dword_1079F090
//.text:1075EB90               add   ecx, -32;指数 ,因为指数起步加32,所以要减去32,把剩下的返回出去
//.text:1075EB93               mov   ds:dword_1079F094, ecx ;
    g_nExp = nExp - 32;
//.text:1075EB99               add   esp, 8
//.text:1075EB9C               retn
//.text:1075EB9C sub_1075EACE    endp
    return g_nMagicNumber;
}


int main(int argc)
{

    Test(-54321);
    printf("%08x ,Exp:%d", g_nMagicNumber,g_nExp);

    return 0;
}
```

YINXN 发表于 2025-5-19 21:42:18

谢谢分享
页: [1]
查看完整版本: X86C++反汇编09.switch case语句