逆向之hash算法
此算法为hash中比较简单的线性探测法,代码优化选项OD(无)
顺便说句,这些算法实现大多会拿我在学数据结构的时候自己实现的或者书上的,所以风格编码肯定不能和百度到的那些比,权当练练手,不过物尽其用吧,也不枉费当时特意把这些代码保存下来,嘿嘿
以下为C的算法代码:
- //线性探测
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
- #define MAX_SIZE 13
- #define b 13
- char *ht[MAX_SIZE];
- int stringtoint(char *key)
- {
- int number;
- for(number=0;*key;key++)
- number+=*key;
- return number;
- }
- int f(int k)
- {
- return k%b;
- }
- char* search(char* key)
- {
- int current,homebucket;
- homebucket=f(stringtoint(key));
- for(current=homebucket;ht[current]&&strcmp(ht[current],key);)
- {
- current=(current+1)%b;
- if(current==homebucket)
- return NULL;
- }
- if(strcmp(ht[current],key)==0)
- return ht[current];
- return NULL;
- }
- void insert(char *key)
- {
- int homebucket,current;
- homebucket=f(stringtoint(key));
- for(current=homebucket;ht[current];)
- {
- current=(current+1)%b;
- if(current==homebucket)
- return;
- }
- ht[current]=(char*)malloc(sizeof(*key));
- strcpy(ht[current],key);
- }
- int main()
- {
- int i;
- char word[MAX_SIZE];
- for(i=0;i<MAX_SIZE;i++)
- {
- ht[i]=NULL;
- }
- for(i=0;i<3;i++)
- {
- scanf("%s",word);
- insert(word);
- fflush(stdin);
- }
- printf("search:");
- scanf("%s",word);
- printf("%s\n",search(word));
- for(i=0;i<MAX_SIZE;i++)
- printf("%s\n",ht[i]);
- system("pause");
- return 0;
- }
//线性探测
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define MAX_SIZE 13
#define b 13
char *ht[MAX_SIZE];
int stringtoint(char *key)
{
int number;
for(number=0;*key;key++)
number+=*key;
return number;
}
int f(int k)
{
return k%b;
}
char* search(char* key)
{
int current,homebucket;
homebucket=f(stringtoint(key));
for(current=homebucket;ht[current]&&strcmp(ht[current],key);)
{
current=(current+1)%b;
if(current==homebucket)
return NULL;
}
if(strcmp(ht[current],key)==0)
return ht[current];
return NULL;
}
void insert(char *key)
{
int homebucket,current;
homebucket=f(stringtoint(key));
for(current=homebucket;ht[current];)
{
current=(current+1)%b;
if(current==homebucket)
return;
}
ht[current]=(char*)malloc(sizeof(*key));
strcpy(ht[current],key);
}
int main()
{
int i;
char word[MAX_SIZE];
for(i=0;i<MAX_SIZE;i++)
{
ht[i]=NULL;
}
for(i=0;i<3;i++)
{
scanf("%s",word);
insert(word);
fflush(stdin);
}
printf("search:");
scanf("%s",word);
printf("%s\n",search(word));
for(i=0;i<MAX_SIZE;i++)
printf("%s\n",ht[i]);
system("pause");
return 0;
}
- 惯例,OD跟踪,往下翻,有个jmp main指令,很明显就是它啦,F7跟进去,显示如下代码
- 01381170 >/$ 83EC 18 sub esp, 18 ; 首先分配临时存储空间
- 01381173 |. A1 00303801 mov eax, dword ptr [__security_cookie]
- 01381178 |. 33C4 xor eax, esp
- 0138117A |. 894424 14 mov dword ptr [esp+14], eax
- 0138117E |. 33C0 xor eax, eax
- 01381180 |. 53 push ebx
- 01381181 |. 8B1D A8203801 mov ebx, dword ptr [<&MSVCR90.fflush>] ; MSVCR90.fflush
- 01381187 |. 55 push ebp
- 01381188 |. 8B2D AC203801 mov ebp, dword ptr [<&MSVCR90.__iob_func>] ; MSVCR90.__p__iob
- 0138118E |. 56 push esi
- 0138118F |. 8B35 B0203801 mov esi, dword ptr [<&MSVCR90.scanf>] ; MSVCR90.scanf
- 01381195 |. A3 6C333801 mov dword ptr [ht], eax ; 初始化全局变量的指针数组
- .....................
- ......................
- 013811DE |. 57 push edi
- 013811DF |. 90 nop
- 013811E0 |> 8D4424 14 /lea eax, dword ptr [esp+14] ; eax指向分配存储空间中最后一个变量
- 013811E4 |. 50 |push eax
- 013811E5 |. 68 04213801 |push 01382104 ; ASCII "%s"
- 013811EA |. FFD6 |call esi ; scanf("%s",esp+14)
- 013811EC |. 8D7C24 1C |lea edi, dword ptr [esp+1C] ; 其实这个esp+1c就是上面那个esp+14,详细可以查查C的调用约定
- 013811F0 |. E8 FBFEFFFF |call insert ; 额。。这个我们先不管,先把主函数整体给反汇编出来
- 013811F5 |. FFD5 |call ebp ; fflush
- 013811F7 |. 50 |push eax
- 013811F8 |. FFD3 |call ebx
- 013811FA |. 83C4 0C |add esp, 0C ; 堆栈平衡跑这来了,服了
- 013811FD |. 836C24 10 01 |sub dword ptr [esp+10], 1 ; 其实就是上面那个mov dword ptr [esp+c],3,看到没
- 01381202 |.^ 75 DC \jnz short 013811E0 ; if [esp+10]==1 break;
- 01381204 |. 8B1D A0203801 mov ebx, dword ptr [<&MSVCR90.printf>] ; MSVCR90.printf
- 0138120A |. 68 08213801 push 01382108 ; /format = "search:"
- 0138120F |. FFD3 call ebx ; \printf
- 01381211 |. 8BCF mov ecx, edi
- 01381213 |. 51 push ecx
- 01381214 |. 68 04213801 push 01382104 ; ASCII "%s"
- 01381219 |. FFD6 call esi ; scanf调用
- 0138121B |. E8 E0FDFFFF call search
- 01381220 |. 50 push eax ; 从这里可以看出eax的返回值是个字符串指针
- 01381221 |. 68 10213801 push 01382110 ; ASCII "%s",LF
- 01381226 |. FFD3 call ebx
- 01381228 |. 83C4 14 add esp, 14 ; 还是平衡堆栈
- 0138122B |. BE 6C333801 mov esi, offset ht ; ht是个全局变量
- 01381230 |. 5F pop edi
- 01381231 |> 8B16 /mov edx, dword ptr [esi]
- 01381233 |. 52 |push edx
- 01381234 |. 68 10213801 |push 01382110 ; ASCII "%s",LF
- 01381239 |. FFD3 |call ebx
- 0138123B |. 83C6 04 |add esi, 4 ; 由此可见全局变量是每个元素4字节的数组
- 0138123E |. 83C4 08 |add esp, 8
- 01381241 |. 81FE A0333801 |cmp esi, offset _adjust_fdiv
- 01381247 |.^ 7C E8 \jl short 01381231
- 01381249 |. 68 14213801 push 01382114 ; /command = "pause"
- 0138124E |. FF15 A4203801 call dword ptr [<&MSVCR90.system>] ; \system
- 01381254 |. 8B4C24 24 mov ecx, dword ptr [esp+24]
- 01381258 |. 83C4 04 add esp, 4
- 0138125B |. 5E pop esi
- 0138125C |. 5D pop ebp
- 0138125D |. 5B pop ebx
- 0138125E |. 33CC xor ecx, esp
- 01381260 |. 33C0 xor eax, eax
- 01381262 |. E8 04000000 call __security_check_cookie
- 01381267 |. 83C4 18 add esp, 18
- 0138126A \. C3 retn
- 下面是insert函数,简单的将字符串每个字节相加,得到的数再取余数,然后看能不能插入hash表,不过有个地方代码很古怪,作用肯定是求余啦,只是。。。
- 012810F0 >/$ 8A07 mov al, byte ptr [edi] ; 这里edi就是指向输入的字符啦
- 012810F2 |. 33C9 xor ecx, ecx
- 012810F4 |. 8BD7 mov edx, edi ; 随时关注edi的动向哦~~~
- 012810F6 |. 84C0 test al, al
- 012810F8 |. 74 12 je short 0128110C
- 012810FA |. 8D9B 00000000 lea ebx, dword ptr [ebx] ; 前面用到的寄存器在这都有效。。。
- 01281100 |> 0FBEC0 /movsx eax, al ; movsx:此乃带符号扩展
- 01281103 |. 42 |inc edx
- 01281104 |. 03C8 |add ecx, eax
- 01281106 |. 8A02 |mov al, byte ptr [edx]
- 01281108 |. 84C0 |test al, al
- 0128110A |.^ 75 F4 \jnz short 01281100 ; 仔细分析这一段代码就是把每个字符的Ascii数值相加放入ecx
- 0128110C |> B8 4FECC44E mov eax, 4EC4EC4F ; 除法,取模运算的优化,定点表示法(即4EC4EC4F为除数的倒数小数位的1倍或2的n次方倍的16进制表示)
- 01281111 |. F7E9 imul ecx ;指令执行后eax为商的小数部分,edx为商的整数部分(可能是2的n次方倍)
- 01281113 |. C1FA 02 sar edx, 2 ; 带符号右移4位,由此可以看出商为真正的商的4倍
- 01281116 |. 8BC2 mov eax, edx
- 01281118 |. C1E8 1F shr eax, 1F ;取符号位(适应负数情况)
- 0128111B |. 03C2 add eax, edx ;加上符号位
- 0128111D |. 6BC0 0D imul eax, eax, 0D ; 三操作数乘法指令,以前还真没见过 eax=eax*0D 如是
- 01281120 |. 2BC8 sub ecx, eax ; 执行后ecx即为余数,(x%y=x-(x/y)*y) ,还不明白可以去看百度文库的代码逆向文章其中有除法,取模的优化详解~~
- 01281122 |. 833C8D 6C3328>cmp dword ptr [ecx*4+ht], 0
- 0128112A |. 56 push esi
- 0128112B |. 8BF1 mov esi, ecx
- 0128112D |. 74 1C je short 0128114B ; 如果为NULL
- 0128112F |. 90 nop
- 01281130 |> 8D46 01 /lea eax, dword ptr [esi+1] ; ht数组的下一个下标
- 01281133 |. 99 |cdq
- 01281134 |. BE 0D000000 |mov esi, 0D
- 01281139 |. F7FE |idiv esi
- 0128113B |. 8BF2 |mov esi, edx
- 0128113D |. 3BF1 |cmp esi, ecx
- 0128113F |. 74 2A |je short 0128116B ; 插入失败
- 01281141 |. 833CB5 6C3328>|cmp dword ptr [esi*4+ht], 0
- 01281149 |.^ 75 E5 \jnz short 01281130 ; 嗯,这里还是没有空位,继续找吧
- 0128114B |> 6A 01 push 1 ; /size = 1
- 0128114D |. FF15 B4202801 call dword ptr [<&MSVCR90.malloc>] ; \malloc
- 01281153 |. 83C4 04 add esp, 4
- 01281156 |. 8904B5 6C3328>mov dword ptr [esi*4+ht], eax
- 0128115D |. 8BCF mov ecx, edi
- 0128115F |. 8BD0 mov edx, eax
- 01281161 |> 8A01 /mov al, byte ptr [ecx] ; 简单地将字符拷贝到新分配的内存中
- 01281163 |. 8802 |mov byte ptr [edx], al
- 01281165 |. 41 |inc ecx
- 01281166 |. 42 |inc edx
- 01281167 |. 84C0 |test al, al
- 01281169 |.^ 75 F6 \jnz short 01281161
- 0128116B |> 5E pop esi
- 0128116C \. C3 retn
- 这是search函数
- 00241000 /$ 8A07 mov al, byte ptr [edi] ; 此处的edi就是那个存字符的缓冲区也是要搜索的
- 00241002 |. 33C9 xor ecx, ecx
- 00241004 |. 8BD7 mov edx, edi
- 00241006 |. 84C0 test al, al
- 00241008 |. 74 12 je short 0024101C ; 如果字符串结尾
- 0024100A |. 8D9B 00000000 lea ebx, dword ptr [ebx] ; 此处是printf函数地址,可以在主函数找到。。顺便感叹下这寄存器窜的
- 00241010 |> 0FBEC0 /movsx eax, al ; 下面这个循环稍微看下就知道是字符串数值相加啦
- 00241013 |. 42 |inc edx
- 00241014 |. 03C8 |add ecx, eax
- 00241016 |. 8A02 |mov al, byte ptr [edx]
- 00241018 |. 84C0 |test al, al
- 0024101A |.^ 75 F4 \jnz short 00241010
- 0024101C |> B8 4FECC44E mov eax, 4EC4EC4F ;依然是个取余操作,详情参考前面注释
- 00241021 |. F7E9 imul ecx
- 00241023 |. C1FA 02 sar edx, 2
- 00241026 |. 8BC2 mov eax, edx
- 00241028 |. C1E8 1F shr eax, 1F
- 0024102B |. 03C2 add eax, edx
- 0024102D |. 6BC0 0D imul eax, eax, 0D
- 00241030 |. 2BC8 sub ecx, eax ; 这里得到了余数
- 00241032 |. 53 push ebx
- 00241033 |. 56 push esi
- 00241034 |. 8BF1 mov esi, ecx
- 00241036 |. 8D04B5 000000>lea eax, dword ptr [esi*4]
- 0024103D |. 83B8 6C332400>cmp dword ptr [eax+24336C], 0 ; 看全局数组某个位置是否为空
- 00241044 |. 8BD6 mov edx, esi
- 00241046 |. 74 58 je short 002410A0 ; 下面循环貌似有点复杂,先看发现空位后的操作
- 00241048 |. EB 06 jmp short 00241050
- 0024104A | 8D9B 00000000 lea ebx, dword ptr [ebx]
- 00241050 |> 8B80 6C332400 /mov eax, dword ptr [eax+24336C] ; 搜索到的字符串地址
- 00241056 |. 8BCF |mov ecx, edi ; 字符串寄存器又换成ecx了
- 00241058 |> 8A18 |/mov bl, byte ptr [eax]
- 0024105A |. 3A19 ||cmp bl, byte ptr [ecx]
- 0024105C |. 75 1A ||jnz short 00241078
- 0024105E |. 84DB ||test bl, bl
- 00241060 |. 74 12 ||je short 00241074 ; 发现相等并等于0字符后跳出并检查是否为所求字符串
- 00241062 |. 8A58 01 ||mov bl, byte ptr [eax+1]
- 00241065 |. 3A59 01 ||cmp bl, byte ptr [ecx+1]
- 00241068 |. 75 0E ||jnz short 00241078
- 0024106A |. 83C0 02 ||add eax, 2
- 0024106D |. 83C1 02 ||add ecx, 2
- 00241070 |. 84DB ||test bl, bl
- 00241072 |.^ 75 E4 |\jnz short 00241058
- 00241074 |> 33C0 |xor eax, eax
- 00241076 |. EB 05 |jmp short 0024107D
- 00241078 |> 1BC0 |sbb eax, eax
- 0024107A |. 83D8 FF |sbb eax, -1
- 0024107D |> 85C0 |test eax, eax
- 0024107F |. 74 1F |je short 002410A0
- 00241081 |. 8D42 01 |lea eax, dword ptr [edx+1] ; 下标后移一个位置后取余
- 00241084 |. 99 |cdq
- 00241085 |. B9 0D000000 |mov ecx, 0D
- 0024108A |. F7F9 |idiv ecx
- 0024108C |. 3BD6 |cmp edx, esi
- 0024108E |. 74 49 |je short 002410D9 ; 意思就是取余后仍然等于原来那个位置,那么查找失败返回0
- 00241090 |. 8D0495 000000>|lea eax, dword ptr [edx*4]
- 00241097 |. 83B8 6C332400>|cmp dword ptr [eax+24336C], 0
- 0024109E |.^ 75 B0 \jnz short 00241050 ; 发现下一个非空位,继续搜索
- 002410A0 |> 8B3495 6C3324>mov esi, dword ptr [edx*4+24336C]
- 002410A7 |. 8BCF mov ecx, edi ; 之后ecx指向搜索的字符串
- 002410A9 |. 8BC6 mov eax, esi
- 002410AB |. EB 03 jmp short 002410B0 ; 跳转之后的基本都是strcmp函数的代码,看来这个库函数是汇编实现还是内联的。。效率确实没得说
- 002410AD | 8D49 00 lea ecx, dword ptr [ecx]
- 002410B0 |> 8A10 /mov dl, byte ptr [eax]
- 002410B2 |. 3A11 |cmp dl, byte ptr [ecx]
- 002410B4 |. 75 28 |jnz short 002410DE
- 002410B6 |. 84D2 |test dl, dl
- 002410B8 |. 74 12 |je short 002410CC
- 002410BA |. 8A50 01 |mov dl, byte ptr [eax+1]
- 002410BD |. 3A51 01 |cmp dl, byte ptr [ecx+1]
- 002410C0 |. 75 1C |jnz short 002410DE
- 002410C2 |. 83C0 02 |add eax, 2
- 002410C5 |. 83C1 02 |add ecx, 2
- 002410C8 |. 84D2 |test dl, dl
- 002410CA |.^ 75 E4 \jnz short 002410B0
- 002410CC |> 33C0 xor eax, eax ; 看着这么多指令,其实就是返回找到的那个元素的地址
- 002410CE |. F7D8 neg eax
- 002410D0 |. 1BC0 sbb eax, eax
- 002410D2 |. F7D0 not eax
- 002410D4 |. 23C6 and eax, esi
- 002410D6 |. 5E pop esi
- 002410D7 |. 5B pop ebx
- 002410D8 |. C3 retn
- 002410D9 |> 5E pop esi
- 002410DA |. 33C0 xor eax, eax
- 002410DC |. 5B pop ebx
- 002410DD |. C3 retn
- 002410DE |> 1BC0 sbb eax, eax ; 返回0
- 002410E0 |. 83D8 FF sbb eax, -1
- 002410E3 |. F7D8 neg eax
- 002410E5 |. 1BC0 sbb eax, eax ; 这里算出eax==FFFFFFFF
- 002410E7 |. F7D0 not eax
- 002410E9 |. 23C6 and eax, esi
- 002410EB |. 5E pop esi
- 002410EC |. 5B pop ebx
- 002410ED \. C3 retn
惯例,OD跟踪,往下翻,有个jmp main指令,很明显就是它啦,F7跟进去,显示如下代码
01381170 >/$ 83EC 18 sub esp, 18 ; 首先分配临时存储空间
01381173 |. A1 00303801 mov eax, dword ptr [__security_cookie]
01381178 |. 33C4 xor eax, esp
0138117A |. 894424 14 mov dword ptr [esp+14], eax
0138117E |. 33C0 xor eax, eax
01381180 |. 53 push ebx
01381181 |. 8B1D A8203801 mov ebx, dword ptr [<&MSVCR90.fflush>] ; MSVCR90.fflush
01381187 |. 55 push ebp
01381188 |. 8B2D AC203801 mov ebp, dword ptr [<&MSVCR90.__iob_func>] ; MSVCR90.__p__iob
0138118E |. 56 push esi
0138118F |. 8B35 B0203801 mov esi, dword ptr [<&MSVCR90.scanf>] ; MSVCR90.scanf
01381195 |. A3 6C333801 mov dword ptr [ht], eax ; 初始化全局变量的指针数组
.....................
......................
013811DE |. 57 push edi
013811DF |. 90 nop
013811E0 |> 8D4424 14 /lea eax, dword ptr [esp+14] ; eax指向分配存储空间中最后一个变量
013811E4 |. 50 |push eax
013811E5 |. 68 04213801 |push 01382104 ; ASCII "%s"
013811EA |. FFD6 |call esi ; scanf("%s",esp+14)
013811EC |. 8D7C24 1C |lea edi, dword ptr [esp+1C] ; 其实这个esp+1c就是上面那个esp+14,详细可以查查C的调用约定
013811F0 |. E8 FBFEFFFF |call insert ; 额。。这个我们先不管,先把主函数整体给反汇编出来
013811F5 |. FFD5 |call ebp ; fflush
013811F7 |. 50 |push eax
013811F8 |. FFD3 |call ebx
013811FA |. 83C4 0C |add esp, 0C ; 堆栈平衡跑这来了,服了
013811FD |. 836C24 10 01 |sub dword ptr [esp+10], 1 ; 其实就是上面那个mov dword ptr [esp+c],3,看到没
01381202 |.^ 75 DC \jnz short 013811E0 ; if [esp+10]==1 break;
01381204 |. 8B1D A0203801 mov ebx, dword ptr [<&MSVCR90.printf>] ; MSVCR90.printf
0138120A |. 68 08213801 push 01382108 ; /format = "search:"
0138120F |. FFD3 call ebx ; \printf
01381211 |. 8BCF mov ecx, edi
01381213 |. 51 push ecx
01381214 |. 68 04213801 push 01382104 ; ASCII "%s"
01381219 |. FFD6 call esi ; scanf调用
0138121B |. E8 E0FDFFFF call search
01381220 |. 50 push eax ; 从这里可以看出eax的返回值是个字符串指针
01381221 |. 68 10213801 push 01382110 ; ASCII "%s",LF
01381226 |. FFD3 call ebx
01381228 |. 83C4 14 add esp, 14 ; 还是平衡堆栈
0138122B |. BE 6C333801 mov esi, offset ht ; ht是个全局变量
01381230 |. 5F pop edi
01381231 |> 8B16 /mov edx, dword ptr [esi]
01381233 |. 52 |push edx
01381234 |. 68 10213801 |push 01382110 ; ASCII "%s",LF
01381239 |. FFD3 |call ebx
0138123B |. 83C6 04 |add esi, 4 ; 由此可见全局变量是每个元素4字节的数组
0138123E |. 83C4 08 |add esp, 8
01381241 |. 81FE A0333801 |cmp esi, offset _adjust_fdiv
01381247 |.^ 7C E8 \jl short 01381231
01381249 |. 68 14213801 push 01382114 ; /command = "pause"
0138124E |. FF15 A4203801 call dword ptr [<&MSVCR90.system>] ; \system
01381254 |. 8B4C24 24 mov ecx, dword ptr [esp+24]
01381258 |. 83C4 04 add esp, 4
0138125B |. 5E pop esi
0138125C |. 5D pop ebp
0138125D |. 5B pop ebx
0138125E |. 33CC xor ecx, esp
01381260 |. 33C0 xor eax, eax
01381262 |. E8 04000000 call __security_check_cookie
01381267 |. 83C4 18 add esp, 18
0138126A \. C3 retn
下面是insert函数,简单的将字符串每个字节相加,得到的数再取余数,然后看能不能插入hash表,不过有个地方代码很古怪,作用肯定是求余啦,只是。。。
012810F0 >/$ 8A07 mov al, byte ptr [edi] ; 这里edi就是指向输入的字符啦
012810F2 |. 33C9 xor ecx, ecx
012810F4 |. 8BD7 mov edx, edi ; 随时关注edi的动向哦~~~
012810F6 |. 84C0 test al, al
012810F8 |. 74 12 je short 0128110C
012810FA |. 8D9B 00000000 lea ebx, dword ptr [ebx] ; 前面用到的寄存器在这都有效。。。
01281100 |> 0FBEC0 /movsx eax, al ; movsx:此乃带符号扩展
01281103 |. 42 |inc edx
01281104 |. 03C8 |add ecx, eax
01281106 |. 8A02 |mov al, byte ptr [edx]
01281108 |. 84C0 |test al, al
0128110A |.^ 75 F4 \jnz short 01281100 ; 仔细分析这一段代码就是把每个字符的Ascii数值相加放入ecx
0128110C |> B8 4FECC44E mov eax, 4EC4EC4F ; 除法,取模运算的优化,定点表示法(即4EC4EC4F为除数的倒数小数位的1倍或2的n次方倍的16进制表示)
01281111 |. F7E9 imul ecx ;指令执行后eax为商的小数部分,edx为商的整数部分(可能是2的n次方倍)
01281113 |. C1FA 02 sar edx, 2 ; 带符号右移4位,由此可以看出商为真正的商的4倍
01281116 |. 8BC2 mov eax, edx
01281118 |. C1E8 1F shr eax, 1F ;取符号位(适应负数情况)
0128111B |. 03C2 add eax, edx ;加上符号位
0128111D |. 6BC0 0D imul eax, eax, 0D ; 三操作数乘法指令,以前还真没见过 eax=eax*0D 如是
01281120 |. 2BC8 sub ecx, eax ; 执行后ecx即为余数,(x%y=x-(x/y)*y) ,还不明白可以去看百度文库的代码逆向文章其中有除法,取模的优化详解~~
01281122 |. 833C8D 6C3328>cmp dword ptr [ecx*4+ht], 0
0128112A |. 56 push esi
0128112B |. 8BF1 mov esi, ecx
0128112D |. 74 1C je short 0128114B ; 如果为NULL
0128112F |. 90 nop
01281130 |> 8D46 01 /lea eax, dword ptr [esi+1] ; ht数组的下一个下标
01281133 |. 99 |cdq
01281134 |. BE 0D000000 |mov esi, 0D
01281139 |. F7FE |idiv esi
0128113B |. 8BF2 |mov esi, edx
0128113D |. 3BF1 |cmp esi, ecx
0128113F |. 74 2A |je short 0128116B ; 插入失败
01281141 |. 833CB5 6C3328>|cmp dword ptr [esi*4+ht], 0
01281149 |.^ 75 E5 \jnz short 01281130 ; 嗯,这里还是没有空位,继续找吧
0128114B |> 6A 01 push 1 ; /size = 1
0128114D |. FF15 B4202801 call dword ptr [<&MSVCR90.malloc>] ; \malloc
01281153 |. 83C4 04 add esp, 4
01281156 |. 8904B5 6C3328>mov dword ptr [esi*4+ht], eax
0128115D |. 8BCF mov ecx, edi
0128115F |. 8BD0 mov edx, eax
01281161 |> 8A01 /mov al, byte ptr [ecx] ; 简单地将字符拷贝到新分配的内存中
01281163 |. 8802 |mov byte ptr [edx], al
01281165 |. 41 |inc ecx
01281166 |. 42 |inc edx
01281167 |. 84C0 |test al, al
01281169 |.^ 75 F6 \jnz short 01281161
0128116B |> 5E pop esi
0128116C \. C3 retn
这是search函数
00241000 /$ 8A07 mov al, byte ptr [edi] ; 此处的edi就是那个存字符的缓冲区也是要搜索的
00241002 |. 33C9 xor ecx, ecx
00241004 |. 8BD7 mov edx, edi
00241006 |. 84C0 test al, al
00241008 |. 74 12 je short 0024101C ; 如果字符串结尾
0024100A |. 8D9B 00000000 lea ebx, dword ptr [ebx] ; 此处是printf函数地址,可以在主函数找到。。顺便感叹下这寄存器窜的
00241010 |> 0FBEC0 /movsx eax, al ; 下面这个循环稍微看下就知道是字符串数值相加啦
00241013 |. 42 |inc edx
00241014 |. 03C8 |add ecx, eax
00241016 |. 8A02 |mov al, byte ptr [edx]
00241018 |. 84C0 |test al, al
0024101A |.^ 75 F4 \jnz short 00241010
0024101C |> B8 4FECC44E mov eax, 4EC4EC4F ;依然是个取余操作,详情参考前面注释
00241021 |. F7E9 imul ecx
00241023 |. C1FA 02 sar edx, 2
00241026 |. 8BC2 mov eax, edx
00241028 |. C1E8 1F shr eax, 1F
0024102B |. 03C2 add eax, edx
0024102D |. 6BC0 0D imul eax, eax, 0D
00241030 |. 2BC8 sub ecx, eax ; 这里得到了余数
00241032 |. 53 push ebx
00241033 |. 56 push esi
00241034 |. 8BF1 mov esi, ecx
00241036 |. 8D04B5 000000>lea eax, dword ptr [esi*4]
0024103D |. 83B8 6C332400>cmp dword ptr [eax+24336C], 0 ; 看全局数组某个位置是否为空
00241044 |. 8BD6 mov edx, esi
00241046 |. 74 58 je short 002410A0 ; 下面循环貌似有点复杂,先看发现空位后的操作
00241048 |. EB 06 jmp short 00241050
0024104A | 8D9B 00000000 lea ebx, dword ptr [ebx]
00241050 |> 8B80 6C332400 /mov eax, dword ptr [eax+24336C] ; 搜索到的字符串地址
00241056 |. 8BCF |mov ecx, edi ; 字符串寄存器又换成ecx了
00241058 |> 8A18 |/mov bl, byte ptr [eax]
0024105A |. 3A19 ||cmp bl, byte ptr [ecx]
0024105C |. 75 1A ||jnz short 00241078
0024105E |. 84DB ||test bl, bl
00241060 |. 74 12 ||je short 00241074 ; 发现相等并等于0字符后跳出并检查是否为所求字符串
00241062 |. 8A58 01 ||mov bl, byte ptr [eax+1]
00241065 |. 3A59 01 ||cmp bl, byte ptr [ecx+1]
00241068 |. 75 0E ||jnz short 00241078
0024106A |. 83C0 02 ||add eax, 2
0024106D |. 83C1 02 ||add ecx, 2
00241070 |. 84DB ||test bl, bl
00241072 |.^ 75 E4 |\jnz short 00241058
00241074 |> 33C0 |xor eax, eax
00241076 |. EB 05 |jmp short 0024107D
00241078 |> 1BC0 |sbb eax, eax
0024107A |. 83D8 FF |sbb eax, -1
0024107D |> 85C0 |test eax, eax
0024107F |. 74 1F |je short 002410A0
00241081 |. 8D42 01 |lea eax, dword ptr [edx+1] ; 下标后移一个位置后取余
00241084 |. 99 |cdq
00241085 |. B9 0D000000 |mov ecx, 0D
0024108A |. F7F9 |idiv ecx
0024108C |. 3BD6 |cmp edx, esi
0024108E |. 74 49 |je short 002410D9 ; 意思就是取余后仍然等于原来那个位置,那么查找失败返回0
00241090 |. 8D0495 000000>|lea eax, dword ptr [edx*4]
00241097 |. 83B8 6C332400>|cmp dword ptr [eax+24336C], 0
0024109E |.^ 75 B0 \jnz short 00241050 ; 发现下一个非空位,继续搜索
002410A0 |> 8B3495 6C3324>mov esi, dword ptr [edx*4+24336C]
002410A7 |. 8BCF mov ecx, edi ; 之后ecx指向搜索的字符串
002410A9 |. 8BC6 mov eax, esi
002410AB |. EB 03 jmp short 002410B0 ; 跳转之后的基本都是strcmp函数的代码,看来这个库函数是汇编实现还是内联的。。效率确实没得说
002410AD | 8D49 00 lea ecx, dword ptr [ecx]
002410B0 |> 8A10 /mov dl, byte ptr [eax]
002410B2 |. 3A11 |cmp dl, byte ptr [ecx]
002410B4 |. 75 28 |jnz short 002410DE
002410B6 |. 84D2 |test dl, dl
002410B8 |. 74 12 |je short 002410CC
002410BA |. 8A50 01 |mov dl, byte ptr [eax+1]
002410BD |. 3A51 01 |cmp dl, byte ptr [ecx+1]
002410C0 |. 75 1C |jnz short 002410DE
002410C2 |. 83C0 02 |add eax, 2
002410C5 |. 83C1 02 |add ecx, 2
002410C8 |. 84D2 |test dl, dl
002410CA |.^ 75 E4 \jnz short 002410B0
002410CC |> 33C0 xor eax, eax ; 看着这么多指令,其实就是返回找到的那个元素的地址
002410CE |. F7D8 neg eax
002410D0 |. 1BC0 sbb eax, eax
002410D2 |. F7D0 not eax
002410D4 |. 23C6 and eax, esi
002410D6 |. 5E pop esi
002410D7 |. 5B pop ebx
002410D8 |. C3 retn
002410D9 |> 5E pop esi
002410DA |. 33C0 xor eax, eax
002410DC |. 5B pop ebx
002410DD |. C3 retn
002410DE |> 1BC0 sbb eax, eax ; 返回0
002410E0 |. 83D8 FF sbb eax, -1
002410E3 |. F7D8 neg eax
002410E5 |. 1BC0 sbb eax, eax ; 这里算出eax==FFFFFFFF
002410E7 |. F7D0 not eax
002410E9 |. 23C6 and eax, esi
002410EB |. 5E pop esi
002410EC |. 5B pop ebx
002410ED \. C3 retn
总结:
发现编译器还是满厉害的,2个小函数直接被优化掉放入调用函数的代码里了,这还只是无优化版本,库也估计也有很多是反汇编实现而且是内联的
有一点比较麻烦的就是C函数的调用约定导致堆栈平衡有点混乱,说不定就突然冒出个add esp,xx不明所以,还导致变量的使用由于堆栈原因比较难看,尤其是寄存器还跨函数使用。。。还得到前面找这个寄存器存的是什么数据,还好windows调用约定是函数自己平衡堆栈,规律性来说应该是要强些的
后来试了下优化选项为o2,结果发现和无优化选项的代码一模一样,表示有点失望。。
PS:学着别人自己做的逆向笔记。。。质量不怎么样,发现自己真不会写笔记,光看自己的解说就。。。不过还是都传上来好了
----------------------------------------------------------------------
逆向之选择排序
这次是直接在维基复制来的代码,就单分析排序的函数
- // selection sort function module in C
- void selectionSort(int data[], int count)
- {
- int i, j, min, temp;
- for (i = 0; i < count - 1; i++) {
- /* find the minimum */
- min = i;
- for (j = i+1; j < count; j++)
- if (data[j] < data[min])
- min = j;
- /* swap data[i] and data[min] */
- if(min != i) {
- temp = data[i];
- data[i] = data[min];
- data[min] = temp;
- }
- }
- }
- 下面是本函数的汇编版本,无优化哦~~个人感觉这里的循环比较难还原...也不知道是因为受源码是2个for的影响还是......
- 总之如果用IDA反编译下的话就会变成判断比较复杂的do while + for的双循环......还是得多加练习啊
- 011E1000 >/$ 83EC 08 sub esp, 8 ; 之前esp+8是要排序数据,而edx=esp+8
- 011E1003 |. 53 push ebx
- 011E1004 |. 55 push ebp
- 011E1005 |. 56 push esi
- 011E1006 |. 57 push edi
- 011E1007 |. 33DB xor ebx, ebx
- 011E1009 |. 8DA424 000000>lea esp, dword ptr [esp]
- 011E1010 |> 8D43 01 /lea eax, dword ptr [ebx+1] ; eax从1开始增长
- 011E1013 |. 83F8 06 |cmp eax, 6
- 011E1016 |. 8BFB |mov edi, ebx
- 011E1018 |. 894424 10 |mov dword ptr [esp+10], eax ; esp+10就是分配的临时变量空间
- 011E101C |. 7D 43 |jge short 011E1061
- 011E101E |. 8D349D 000000>|lea esi, dword ptr [ebx*4]
- 011E1025 |. 897424 14 |mov dword ptr [esp+14], esi ; 记住了,esp+14存的是要排序数组的偏移
- 011E1029 |. 8DA424 000000>|lea esp, dword ptr [esp]
- 011E1030 |> 8D0C85 000000>|/lea ecx, dword ptr [eax*4] ; 根据各个跳转和前面那些准备工作的情况,猜测这里应该是进入了循环内部
- 011E1037 |. 8B2C11 ||mov ebp, dword ptr [ecx+edx]
- 011E103A |. 3B2C16 ||cmp ebp, dword ptr [esi+edx] ; 当前数据和后一个数据比较,小于的话继续比较下一个
- 011E103D |. 7D 04 ||jge short 011E1043
- 011E103F |. 8BF8 ||mov edi, eax ; 找到的数的下标
- 011E1041 |. 8BF1 ||mov esi, ecx ; 找到的数的偏移
- 011E1043 |> 40 ||inc eax
- 011E1044 |. 83F8 06 ||cmp eax, 6
- 011E1047 |.^ 7C E7 |\jl short 011E1030
- 011E1049 |. 3BFB |cmp edi, ebx
- 011E104B |. 74 10 |je short 011E105D ; 找到的数等于当前数
- 011E104D |. 8B4424 14 |mov eax, dword ptr [esp+14] ; 当前偏移存储到eax
- 011E1051 |. 8B34BA |mov esi, dword ptr [edx+edi*4] ; 找到的数存到esi
- 011E1054 |. 8B0C10 |mov ecx, dword ptr [eax+edx] ; 下面3指令将2数交换位置
- 011E1057 |. 893410 |mov dword ptr [eax+edx], esi
- 011E105A |. 890CBA |mov dword ptr [edx+edi*4], ecx
- 011E105D |> 8B4424 10 |mov eax, dword ptr [esp+10]
- 011E1061 |> 8BD8 |mov ebx, eax
- 011E1063 |. 83FB 05 |cmp ebx, 5
- 011E1066 |.^ 7C A8 \jl short 011E1010
- 011E1068 |. 5F pop edi
- 011E1069 |. 5E pop esi
- 011E106A |. 5D pop ebp
- 011E106B |. 5B pop ebx
- 011E106C |. 83C4 08 add esp, 8
- 011E106F \. C3 retn
// selection sort function module in C
void selectionSort(int data[], int count)
{
int i, j, min, temp;
for (i = 0; i < count - 1; i++) {
/* find the minimum */
min = i;
for (j = i+1; j < count; j++)
if (data[j] < data[min])
min = j;
/* swap data[i] and data[min] */
if(min != i) {
temp = data[i];
data[i] = data[min];
data[min] = temp;
}
}
}
下面是本函数的汇编版本,无优化哦~~个人感觉这里的循环比较难还原...也不知道是因为受源码是2个for的影响还是......
总之如果用IDA反编译下的话就会变成判断比较复杂的do while + for的双循环......还是得多加练习啊
011E1000 >/$ 83EC 08 sub esp, 8 ; 之前esp+8是要排序数据,而edx=esp+8
011E1003 |. 53 push ebx
011E1004 |. 55 push ebp
011E1005 |. 56 push esi
011E1006 |. 57 push edi
011E1007 |. 33DB xor ebx, ebx
011E1009 |. 8DA424 000000>lea esp, dword ptr [esp]
011E1010 |> 8D43 01 /lea eax, dword ptr [ebx+1] ; eax从1开始增长
011E1013 |. 83F8 06 |cmp eax, 6
011E1016 |. 8BFB |mov edi, ebx
011E1018 |. 894424 10 |mov dword ptr [esp+10], eax ; esp+10就是分配的临时变量空间
011E101C |. 7D 43 |jge short 011E1061
011E101E |. 8D349D 000000>|lea esi, dword ptr [ebx*4]
011E1025 |. 897424 14 |mov dword ptr [esp+14], esi ; 记住了,esp+14存的是要排序数组的偏移
011E1029 |. 8DA424 000000>|lea esp, dword ptr [esp]
011E1030 |> 8D0C85 000000>|/lea ecx, dword ptr [eax*4] ; 根据各个跳转和前面那些准备工作的情况,猜测这里应该是进入了循环内部
011E1037 |. 8B2C11 ||mov ebp, dword ptr [ecx+edx]
011E103A |. 3B2C16 ||cmp ebp, dword ptr [esi+edx] ; 当前数据和后一个数据比较,小于的话继续比较下一个
011E103D |. 7D 04 ||jge short 011E1043
011E103F |. 8BF8 ||mov edi, eax ; 找到的数的下标
011E1041 |. 8BF1 ||mov esi, ecx ; 找到的数的偏移
011E1043 |> 40 ||inc eax
011E1044 |. 83F8 06 ||cmp eax, 6
011E1047 |.^ 7C E7 |\jl short 011E1030
011E1049 |. 3BFB |cmp edi, ebx
011E104B |. 74 10 |je short 011E105D ; 找到的数等于当前数
011E104D |. 8B4424 14 |mov eax, dword ptr [esp+14] ; 当前偏移存储到eax
011E1051 |. 8B34BA |mov esi, dword ptr [edx+edi*4] ; 找到的数存到esi
011E1054 |. 8B0C10 |mov ecx, dword ptr [eax+edx] ; 下面3指令将2数交换位置
011E1057 |. 893410 |mov dword ptr [eax+edx], esi
011E105A |. 890CBA |mov dword ptr [edx+edi*4], ecx
011E105D |> 8B4424 10 |mov eax, dword ptr [esp+10]
011E1061 |> 8BD8 |mov ebx, eax
011E1063 |. 83FB 05 |cmp ebx, 5
011E1066 |.^ 7C A8 \jl short 011E1010
011E1068 |. 5F pop edi
011E1069 |. 5E pop esi
011E106A |. 5D pop ebp
011E106B |. 5B pop ebx
011E106C |. 83C4 08 add esp, 8
011E106F \. C3 retn
----------------------------------------------------------------------------
逆向之快速排序
下面是这次逆向分析的C源代码,优化选项是O2,不过严重怀疑O2和无优化是不是没区别对于这种小程序来说。。。
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #define MAX 100
- #define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
- void QuickSort(int p[],int start,int end)
- {
- int i,key,temp,j;
- if(start<end)
- {
- i=start;
- j=end+1;//bigest index +1 because --j
- key=p[start];//key element is the first
- for(;;)
- {
- while(i<j&&p[--j]>key) {}//find element that less than the piovt of the
- while(i<j&&p[++i]<key) {}//find element that greater than the piovt of the
- //above Circulation order should strictly Abide by
- if(i<j)
- SWAP(p[i],p[j],temp);//swap
- else
- break;
- }
- SWAP(p[i],p[start],temp);//swap piovt and i(this moment i==j)
- QuickSort(p,start,i-1);
- QuickSort(p,i+1,end);
- }
- }
- int main()
- {
- int i;
- int a[10];//={5,8,15,2,13,7,0,1,25,9};
- srand((unsigned)(time(0)));
- for(i=0;i<10;i++)
- a[i]=rand()%10;
- QuickSort(a,0,9);
- for(i=0;i<10;i++)
- printf("%3d",a[i]);
- system("pause");
- return 0;
- }
- 这里主函数就贴了,直接贴排序函数,这个函数也不知道怎么讲。。个人感觉比较难
- 而且源码的第2个递归调用直接优化掉了,如果要反出源码应该会比较难
- 00251000 >/$ 8B4424 0C mov eax, dword ptr [esp+C] ; eax存储第3个参数
- 00251004 |. 53 push ebx
- 00251005 |. 8B5C24 0C mov ebx, dword ptr [esp+C] ; ebx存储第2个参数
- 00251009 |. 3BD8 cmp ebx, eax
- 0025100B |. 7D 67 jge short 00251074
- 0025100D |. 55 push ebp
- 0025100E |. 56 push esi
- 0025100F |. 57 push edi
- 00251010 |. 8B7C24 14 mov edi, dword ptr [esp+14] ; edi存储要排序数据地址
- 00251014 |> 8B0C9F /mov ecx, dword ptr [edi+ebx*4] ; 在下面整个循环里,esi是自增下标i,eax是自减下标j
- 00251017 |. 8BF3 |mov esi, ebx
- 00251019 |. 40 |inc eax
- 0025101A |. 8D9B 00000000 |lea ebx, dword ptr [ebx]
- 00251020 |> 3BF0 |/cmp esi, eax ; 下面这2个小循环是一个类型,仔细看下就行,在不远处有个jmp其实就是个大循环
- 00251022 |. 7D 28 ||jge short 0025104C
- 00251024 |. 48 ||dec eax
- 00251025 |. 390C87 ||cmp dword ptr [edi+eax*4], ecx
- 00251028 |.^ 7F F6 ||jg short 00251020
- 0025102A |. 8D9B 00000000 ||lea ebx, dword ptr [ebx]
- 00251030 |> 3BF0 ||/cmp esi, eax
- 00251032 |. 7D 18 |||jge short 0025104C
- 00251034 |. 46 |||inc esi
- 00251035 |. 390CB7 |||cmp dword ptr [edi+esi*4], ecx
- 00251038 |.^ 7C F6 ||\jl short 00251030
- 0025103A |. 3BF0 ||cmp esi, eax
- 0025103C |. 7D 0E ||jge short 0025104C
- 0025103E |. 8B2C87 ||mov ebp, dword ptr [edi+eax*4] ; SWAP(a[b],a[c])
- 00251041 |. 8B14B7 ||mov edx, dword ptr [edi+esi*4]
- 00251044 |. 892CB7 ||mov dword ptr [edi+esi*4], ebp
- 00251047 |. 891487 ||mov dword ptr [edi+eax*4], edx
- 0025104A |.^ EB D4 |\jmp short 00251020
- 0025104C |> 8B0C9F |mov ecx, dword ptr [edi+ebx*4] ; SWAP(a[b],a[c])
- 0025104F |. 8B04B7 |mov eax, dword ptr [edi+esi*4]
- 00251052 |. 8D56 FF |lea edx, dword ptr [esi-1]
- 00251055 |. 52 |push edx
- 00251056 |. 53 |push ebx
- 00251057 |. 890CB7 |mov dword ptr [edi+esi*4], ecx
- 0025105A |. 57 |push edi
- 0025105B |. 89049F |mov dword ptr [edi+ebx*4], eax
- 0025105E |. E8 9DFFFFFF |call QuickSort
- 00251063 |. 8B4424 28 |mov eax, dword ptr [esp+28] ; eax=第3个参数
- 00251067 |. 8D5E 01 |lea ebx, dword ptr [esi+1] ; ebx=i+1
- 0025106A |. 83C4 0C |add esp, 0C
- 0025106D |. 3BD8 |cmp ebx, eax
- 0025106F |.^ 7C A3 \jl short 00251014
- 00251071 |. 5F pop edi
- 00251072 |. 5E pop esi
- 00251073 |. 5D pop ebp
- 00251074 |> 5B pop ebx
- 00251075 \. C3 retn
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 100
#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
void QuickSort(int p[],int start,int end)
{
int i,key,temp,j;
if(start<end)
{
i=start;
j=end+1;//bigest index +1 because --j
key=p[start];//key element is the first
for(;;)
{
while(i<j&&p[--j]>key) {}//find element that less than the piovt of the
while(i<j&&p[++i]<key) {}//find element that greater than the piovt of the
//above Circulation order should strictly Abide by
if(i<j)
SWAP(p[i],p[j],temp);//swap
else
break;
}
SWAP(p[i],p[start],temp);//swap piovt and i(this moment i==j)
QuickSort(p,start,i-1);
QuickSort(p,i+1,end);
}
}
int main()
{
int i;
int a[10];//={5,8,15,2,13,7,0,1,25,9};
srand((unsigned)(time(0)));
for(i=0;i<10;i++)
a[i]=rand()%10;
QuickSort(a,0,9);
for(i=0;i<10;i++)
printf("%3d",a[i]);
system("pause");
return 0;
}
这里主函数就贴了,直接贴排序函数,这个函数也不知道怎么讲。。个人感觉比较难
而且源码的第2个递归调用直接优化掉了,如果要反出源码应该会比较难
00251000 >/$ 8B4424 0C mov eax, dword ptr [esp+C] ; eax存储第3个参数
00251004 |. 53 push ebx
00251005 |. 8B5C24 0C mov ebx, dword ptr [esp+C] ; ebx存储第2个参数
00251009 |. 3BD8 cmp ebx, eax
0025100B |. 7D 67 jge short 00251074
0025100D |. 55 push ebp
0025100E |. 56 push esi
0025100F |. 57 push edi
00251010 |. 8B7C24 14 mov edi, dword ptr [esp+14] ; edi存储要排序数据地址
00251014 |> 8B0C9F /mov ecx, dword ptr [edi+ebx*4] ; 在下面整个循环里,esi是自增下标i,eax是自减下标j
00251017 |. 8BF3 |mov esi, ebx
00251019 |. 40 |inc eax
0025101A |. 8D9B 00000000 |lea ebx, dword ptr [ebx]
00251020 |> 3BF0 |/cmp esi, eax ; 下面这2个小循环是一个类型,仔细看下就行,在不远处有个jmp其实就是个大循环
00251022 |. 7D 28 ||jge short 0025104C
00251024 |. 48 ||dec eax
00251025 |. 390C87 ||cmp dword ptr [edi+eax*4], ecx
00251028 |.^ 7F F6 ||jg short 00251020
0025102A |. 8D9B 00000000 ||lea ebx, dword ptr [ebx]
00251030 |> 3BF0 ||/cmp esi, eax
00251032 |. 7D 18 |||jge short 0025104C
00251034 |. 46 |||inc esi
00251035 |. 390CB7 |||cmp dword ptr [edi+esi*4], ecx
00251038 |.^ 7C F6 ||\jl short 00251030
0025103A |. 3BF0 ||cmp esi, eax
0025103C |. 7D 0E ||jge short 0025104C
0025103E |. 8B2C87 ||mov ebp, dword ptr [edi+eax*4] ; SWAP(a[b],a[c])
00251041 |. 8B14B7 ||mov edx, dword ptr [edi+esi*4]
00251044 |. 892CB7 ||mov dword ptr [edi+esi*4], ebp
00251047 |. 891487 ||mov dword ptr [edi+eax*4], edx
0025104A |.^ EB D4 |\jmp short 00251020
0025104C |> 8B0C9F |mov ecx, dword ptr [edi+ebx*4] ; SWAP(a[b],a[c])
0025104F |. 8B04B7 |mov eax, dword ptr [edi+esi*4]
00251052 |. 8D56 FF |lea edx, dword ptr [esi-1]
00251055 |. 52 |push edx
00251056 |. 53 |push ebx
00251057 |. 890CB7 |mov dword ptr [edi+esi*4], ecx
0025105A |. 57 |push edi
0025105B |. 89049F |mov dword ptr [edi+ebx*4], eax
0025105E |. E8 9DFFFFFF |call QuickSort
00251063 |. 8B4424 28 |mov eax, dword ptr [esp+28] ; eax=第3个参数
00251067 |. 8D5E 01 |lea ebx, dword ptr [esi+1] ; ebx=i+1
0025106A |. 83C4 0C |add esp, 0C
0025106D |. 3BD8 |cmp ebx, eax
0025106F |.^ 7C A3 \jl short 00251014
00251071 |. 5F pop edi
00251072 |. 5E pop esi
00251073 |. 5D pop ebp
00251074 |> 5B pop ebx
00251075 \. C3 retn
自己看着都。。。。不是写文章的料啊诶。。