逆向之堆排序 ,逆向之二路归并排序

29 篇文章 0 订阅

逆向之堆排序 


版本:Release

优化选项:O2
调试工具:OD
源码:
  1. //堆排序   
  2. #include <stdio.h>   
  3. #include <stdlib.h>   
  4. #include <time.h>   
  5.   
  6. #define MAX_SIZE 10     
  7. #define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))   
  8.   
  9. void adjust(int a[],int rootn,int n)//调整堆   
  10. {  
  11.     int temp,parent,child;  
  12.     temp=a[rootn];  
  13.     parent=rootn;  
  14.     child=2*parent;  
  15.     while(child<=n)  
  16.     {  
  17.         if(child<n&&a[child]<a[child+1])  
  18.             child++;  
  19.         if(temp>a[child])  
  20.             break;  
  21.         a[parent]=a[child];  
  22.         parent=child;  
  23.         child*=2;  
  24.     }  
  25.     a[parent]=temp;  
  26. }  
  27.   
  28. void heapsort(int a[],int n)  
  29. {  
  30.     int i,temp;  
  31.     for(i=n/2;i>0;i--)  
  32.         adjust(a,i,n);//自下而上逐层建堆   
  33.     for(i=n-1;i>0;i--)  
  34.     {  
  35.         SWAP(a[1],a[i+1],temp);//取堆顶点最大元素   
  36.         adjust(a,1,i);//调整堆   
  37.     }  
  38. }  
  39.   
  40. int main()  
  41. {  
  42.     int i;  
  43.     int a[MAX_SIZE+1];//={0,5,8,4,6,2,15,12,58,12,10};   
  44.     srand((unsigned)time(0));  
  45.     for(i=1;i<=MAX_SIZE;i++)  
  46.         a[i]=rand()%100;  
  47.     for(i=1;i<=MAX_SIZE;i++)  
  48.         printf("%4d",a[i]);  
  49.     putchar('\n');  
  50.     heapsort(a,MAX_SIZE);  
  51.     for(i=1;i<=MAX_SIZE;i++)  
  52.         printf("%4d",a[i]);  
  53.     system("pause");  
  54.     return 0;  
  55. }  
  56.   
  57. 首先把主函数架子给反出来,比较简单  
  58. 012610A0 >/$  83EC 2C       sub     esp, 2C  
  59. 012610A3  |.  56            push    esi  
  60. 012610A4  |.  57            push    edi  
  61. 012610A5  |.  6A 00         push    0  
  62. 012610A7  |.  FF15 A0202601 call    dword ptr [<&MSVCR90._time64>]   ;  MSVCR90._time64  
  63. 012610AD  |.  50            push    eax                              ; /seed  
  64. 012610AE  |.  FF15 A8202601 call    dword ptr [<&MSVCR90.srand>]     ; \srand  
  65. 012610B4  |.  8B3D AC202601 mov     edi, dword ptr [<&MSVCR90.rand>] ;  MSVCR90.rand  
  66. 012610BA  |.  83C4 08       add     esp, 8  
  67. 012610BD  |.  BE 01000000   mov     esi, 1  
  68. 012610C2  |>  FFD7          /call    edi  
  69. 012610C4  |.  99            |cdq  
  70. 012610C5  |.  B9 64000000   |mov     ecx, 64                         ;  100取余  
  71. 012610CA  |.  F7F9          |idiv    ecx  
  72. 012610CC  |.  46            |inc     esi  
  73. 012610CD  |.  83FE 0A       |cmp     esi, 0A                         ;  分配10个元素  
  74. 012610D0  |.  8954B4 04     |mov     dword ptr [esp+esi*4+4], edx    ;  第一次到这里其实esi==2,也就是说随机数存储在分配数组中下标1开始  
  75. 012610D4  |.^ 7E EC         \jle     short 012610C2  
  76. 012610D6  |.  8B3D B0202601 mov     edi, dword ptr [<&MSVCR90.printf>;  MSVCR90.printf  
  77. 012610DC  |.  BE 01000000   mov     esi, 1  
  78. 012610E1  |>  8B54B4 08     /mov     edx, dword ptr [esp+esi*4+8]    ;  这个循环是输出随机取得的数  
  79. 012610E5  |.  52            |push    edx  
  80. 012610E6  |.  68 04212601   |push    01262104                        ;  ASCII "%4d"  
  81. 012610EB  |.  FFD7          |call    edi  
  82. 012610ED  |.  46            |inc     esi  
  83. 012610EE  |.  83C4 08       |add     esp, 8  
  84. 012610F1  |.  83FE 0A       |cmp     esi, 0A                         ;  依旧是循环10次  
  85. 012610F4  |.^ 7E EB         \jle     short 012610E1  
  86. 012610F6  |.  6A 0A         push    0A                               ; /c = 0A  (Line Feed)  
  87. 012610F8  |.  FF15 A4202601 call    dword ptr [<&MSVCR90.putchar>]   ; \putchar  
  88. 012610FE  |.  83C4 04       add     esp, 4  
  89. 01261101  |.  8D4424 08     lea     eax, dword ptr [esp+8]           ;   取分配数组的地址  
  90. 01261105  |.  E8 F6FEFFFF   call    heapsort                         ;  排序函数是我们要主要分析的  
  91. 0126110A  |.  BE 01000000   mov     esi, 1  
  92. 0126110F  |.  90            nop  
  93. 01261110  |>  8B44B4 08     /mov     eax, dword ptr [esp+esi*4+8]    ;  看过前面几个循环应该不会陌生了吧,一个模式,输出排序后的数  
  94. 01261114  |.  50            |push    eax  
  95. 01261115  |.  68 04212601   |push    01262104                        ;  ASCII "%4d"  
  96. 0126111A  |.  FFD7          |call    edi  
  97. 0126111C  |.  46            |inc     esi  
  98. 0126111D  |.  83C4 08       |add     esp, 8  
  99. 01261120  |.  83FE 0A       |cmp     esi, 0A  
  100. 01261123  |.^ 7E EB         \jle     short 01261110  
  101. 01261125  |.  68 08212601   push    01262108                         ; /command = "pause"  
  102. 0126112A  |.  FF15 B4202601 call    dword ptr [<&MSVCR90.system>]    ; \system  
  103. 01261130  |.  83C4 04       add     esp, 4  
  104. 01261133  |.  5F            pop     edi  
  105. 01261134  |.  33C0          xor     eax, eax  
  106. 01261136  |.  5E            pop     esi  
  107. 01261137  |.  83C4 2C       add     esp, 2C  
  108. 0126113A  \.  C3            retn  
  109.   
  110.   
  111. 嗯。下面分析我们的排序函数,这才是重头戏嘛  
  112. 先大概浏览了下主要的跳转,发现函数调用直接插进来优化掉了没有了函数调用,本来还想从子函数入手的,既然如此就直接上吧,虽然会有点复杂  
  113. 01261000 >/$  53            push    ebx  
  114. 01261001  |.  55            push    ebp  
  115. 01261002  |.  56            push    esi  
  116. 01261003  |.  57            push    edi  
  117. 01261004  |.  BF 05000000   mov     edi, 5                           ;  姑且认为edi是数组下标吧,令edi=n  
  118. 01261009  |.  8DA424 000000>lea     esp, dword ptr [esp]  
  119. 01261010  |>  83FF 05       /cmp     edi, 5  
  120. 01261013  |.  8B1CB8        |mov     ebx, dword ptr [eax+edi*4]  
  121. 01261016  |.  8BF7          |mov     esi, edi  
  122. 01261018  |.  8D0C3F        |lea     ecx, dword ptr [edi+edi]        ;  ecx=2n  
  123. 0126101B  |.  7F 22         |jg      short 0126103F                  ;  粗略来看下面这些跳转是为了找出a[n],a[2n],a[2n+1]中较大的数  
  124. 0126101D  |.  83F9 0A       |cmp     ecx, 0A                         ;  if (2n<10)  
  125. 01261020  |>  7D 0A         |/jge     short 0126102C  
  126. 01261022  |.  8B1488        ||mov     edx, dword ptr [eax+ecx*4]  
  127. 01261025  |.  3B5488 04     ||cmp     edx, dword ptr [eax+ecx*4+4]   ;  if(a[2n]<a[2n+1])  
  128. 01261029  |.  7D 01         ||jge     short 0126102C  
  129. 0126102B  |.  41            ||inc     ecx  
  130. 0126102C  |>  8B1488        ||mov     edx, dword ptr [eax+ecx*4]  
  131. 0126102F  |.  3BDA          ||cmp     ebx, edx                       ;  if (a[n]<=a[2n+1])  
  132. 01261031  |.  7F 0C         ||jg      short 0126103F  
  133. 01261033  |.  8914B0        ||mov     dword ptr [eax+esi*4], edx     ;  a[n]=a[较大那个]  
  134. 01261036  |.  8BF1          ||mov     esi, ecx                       ;  esi=ecx,这里ecx是最大数的下标  
  135. 01261038  |.  03C9          ||add     ecx, ecx                       ;  ecx=2*ecx,继续向下搜索调整  
  136. 0126103A  |.  83F9 0A       ||cmp     ecx, 0A  
  137. 0126103D  |.^ 7E E1         |\jle     short 01261020  
  138. 0126103F  |>  4F            |dec     edi                             ;  n--  
  139. 01261040  |.  891CB0        |mov     dword ptr [eax+esi*4], ebx      ;  到这里,在看下上面涉及到了ebx的代码,观察下就可以发现a[n]==ebx,而这些代码的目的应该是找到最大数的位置,然后将a[n]替换进去  
  140. 01261043  |.  85FF          |test    edi, edi                        ;  n>0则继续循环  
  141. 01261045  |.^ 7F C9         \jg      short 01261010  
  142. 01261047  |.  BA 09000000   mov     edx, 9  
  143. 0126104C  |.  8D68 28       lea     ebp, dword ptr [eax+28]          ;  a[10]  
  144. 0126104F  |.  90            nop  
  145. 01261050  |>  8B75 00       /mov     esi, dword ptr [ebp]  
  146. 01261053  |.  8B48 04       |mov     ecx, dword ptr [eax+4]          ;  SWAP a[1],a[10]  
  147. 01261056  |.  8970 04       |mov     dword ptr [eax+4], esi          ;  a[10]  
  148. 01261059  |.  894D 00       |mov     dword ptr [ebp], ecx  
  149. 0126105C  |.  8B58 04       |mov     ebx, dword ptr [eax+4]  
  150. 0126105F  |.  B9 02000000   |mov     ecx, 2  
  151. 01261064  |.  3BCA          |cmp     ecx, edx                        ;  我们假设edx就是n吧,这样的话if(2<n)  
  152. 01261066  |.  BE 01000000   |mov     esi, 1  
  153. 0126106B  |.  7F 1E         |jg      short 0126108B  
  154. 0126106D  |>  7D 0A         |/jge     short 01261079                 ;  下面这段循环和上面一个套路,只是优化后略有不同(明明是一个函数,妹的)  
  155. 0126106F  |.  8B3C88        ||mov     edi, dword ptr [eax+ecx*4]  
  156. 01261072  |.  3B7C88 04     ||cmp     edi, dword ptr [eax+ecx*4+4]  
  157. 01261076  |.  7D 01         ||jge     short 01261079  
  158. 01261078  |.  41            ||inc     ecx  
  159. 01261079  |>  8B3C88        ||mov     edi, dword ptr [eax+ecx*4]  
  160. 0126107C  |.  3BDF          ||cmp     ebx, edi  
  161. 0126107E  |.  7F 0B         ||jg      short 0126108B  
  162. 01261080  |.  893CB0        ||mov     dword ptr [eax+esi*4], edi  
  163. 01261083  |.  8BF1          ||mov     esi, ecx  
  164. 01261085  |.  03C9          ||add     ecx, ecx  
  165. 01261087  |.  3BCA          ||cmp     ecx, edx  
  166. 01261089  |.^ 7E E2         |\jle     short 0126106D  
  167. 0126108B  |>  4A            |dec     edx                             ;  n--  
  168. 0126108C  |.  83ED 04       |sub     ebp, 4  
  169. 0126108F  |.  891CB0        |mov     dword ptr [eax+esi*4], ebx  
  170. 01261092  |.  85D2          |test    edx, edx  
  171. 01261094  |.^ 7F BA         \jg      short 01261050  
  172. 01261096  |.  5F            pop     edi  
  173. 01261097  |.  5E            pop     esi  
  174. 01261098  |.  5D            pop     ebp  
  175. 01261099  |.  5B            pop     ebx  
  176. 0126109A  \.  C3            retn  
//堆排序
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX_SIZE 10  
#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))

void adjust(int a[],int rootn,int n)//调整堆
{
	int temp,parent,child;
	temp=a[rootn];
	parent=rootn;
	child=2*parent;
	while(child<=n)
	{
		if(child<n&&a[child]<a[child+1])
			child++;
		if(temp>a[child])
			break;
		a[parent]=a[child];
		parent=child;
		child*=2;
	}
	a[parent]=temp;
}

void heapsort(int a[],int n)
{
	int i,temp;
	for(i=n/2;i>0;i--)
		adjust(a,i,n);//自下而上逐层建堆
	for(i=n-1;i>0;i--)
	{
		SWAP(a[1],a[i+1],temp);//取堆顶点最大元素
		adjust(a,1,i);//调整堆
	}
}

int main()
{
	int i;
	int a[MAX_SIZE+1];//={0,5,8,4,6,2,15,12,58,12,10};
	srand((unsigned)time(0));
	for(i=1;i<=MAX_SIZE;i++)
		a[i]=rand()%100;
	for(i=1;i<=MAX_SIZE;i++)
		printf("%4d",a[i]);
	putchar('\n');
	heapsort(a,MAX_SIZE);
	for(i=1;i<=MAX_SIZE;i++)
		printf("%4d",a[i]);
	system("pause");
	return 0;
}

首先把主函数架子给反出来,比较简单
012610A0 >/$  83EC 2C       sub     esp, 2C
012610A3  |.  56            push    esi
012610A4  |.  57            push    edi
012610A5  |.  6A 00         push    0
012610A7  |.  FF15 A0202601 call    dword ptr [<&MSVCR90._time64>]   ;  MSVCR90._time64
012610AD  |.  50            push    eax                              ; /seed
012610AE  |.  FF15 A8202601 call    dword ptr [<&MSVCR90.srand>]     ; \srand
012610B4  |.  8B3D AC202601 mov     edi, dword ptr [<&MSVCR90.rand>] ;  MSVCR90.rand
012610BA  |.  83C4 08       add     esp, 8
012610BD  |.  BE 01000000   mov     esi, 1
012610C2  |>  FFD7          /call    edi
012610C4  |.  99            |cdq
012610C5  |.  B9 64000000   |mov     ecx, 64                         ;  100取余
012610CA  |.  F7F9          |idiv    ecx
012610CC  |.  46            |inc     esi
012610CD  |.  83FE 0A       |cmp     esi, 0A                         ;  分配10个元素
012610D0  |.  8954B4 04     |mov     dword ptr [esp+esi*4+4], edx    ;  第一次到这里其实esi==2,也就是说随机数存储在分配数组中下标1开始
012610D4  |.^ 7E EC         \jle     short 012610C2
012610D6  |.  8B3D B0202601 mov     edi, dword ptr [<&MSVCR90.printf>;  MSVCR90.printf
012610DC  |.  BE 01000000   mov     esi, 1
012610E1  |>  8B54B4 08     /mov     edx, dword ptr [esp+esi*4+8]    ;  这个循环是输出随机取得的数
012610E5  |.  52            |push    edx
012610E6  |.  68 04212601   |push    01262104                        ;  ASCII "%4d"
012610EB  |.  FFD7          |call    edi
012610ED  |.  46            |inc     esi
012610EE  |.  83C4 08       |add     esp, 8
012610F1  |.  83FE 0A       |cmp     esi, 0A                         ;  依旧是循环10次
012610F4  |.^ 7E EB         \jle     short 012610E1
012610F6  |.  6A 0A         push    0A                               ; /c = 0A  (Line Feed)
012610F8  |.  FF15 A4202601 call    dword ptr [<&MSVCR90.putchar>]   ; \putchar
012610FE  |.  83C4 04       add     esp, 4
01261101  |.  8D4424 08     lea     eax, dword ptr [esp+8]           ;   取分配数组的地址
01261105  |.  E8 F6FEFFFF   call    heapsort                         ;  排序函数是我们要主要分析的
0126110A  |.  BE 01000000   mov     esi, 1
0126110F  |.  90            nop
01261110  |>  8B44B4 08     /mov     eax, dword ptr [esp+esi*4+8]    ;  看过前面几个循环应该不会陌生了吧,一个模式,输出排序后的数
01261114  |.  50            |push    eax
01261115  |.  68 04212601   |push    01262104                        ;  ASCII "%4d"
0126111A  |.  FFD7          |call    edi
0126111C  |.  46            |inc     esi
0126111D  |.  83C4 08       |add     esp, 8
01261120  |.  83FE 0A       |cmp     esi, 0A
01261123  |.^ 7E EB         \jle     short 01261110
01261125  |.  68 08212601   push    01262108                         ; /command = "pause"
0126112A  |.  FF15 B4202601 call    dword ptr [<&MSVCR90.system>]    ; \system
01261130  |.  83C4 04       add     esp, 4
01261133  |.  5F            pop     edi
01261134  |.  33C0          xor     eax, eax
01261136  |.  5E            pop     esi
01261137  |.  83C4 2C       add     esp, 2C
0126113A  \.  C3            retn


嗯。下面分析我们的排序函数,这才是重头戏嘛
先大概浏览了下主要的跳转,发现函数调用直接插进来优化掉了没有了函数调用,本来还想从子函数入手的,既然如此就直接上吧,虽然会有点复杂
01261000 >/$  53            push    ebx
01261001  |.  55            push    ebp
01261002  |.  56            push    esi
01261003  |.  57            push    edi
01261004  |.  BF 05000000   mov     edi, 5                           ;  姑且认为edi是数组下标吧,令edi=n
01261009  |.  8DA424 000000>lea     esp, dword ptr [esp]
01261010  |>  83FF 05       /cmp     edi, 5
01261013  |.  8B1CB8        |mov     ebx, dword ptr [eax+edi*4]
01261016  |.  8BF7          |mov     esi, edi
01261018  |.  8D0C3F        |lea     ecx, dword ptr [edi+edi]        ;  ecx=2n
0126101B  |.  7F 22         |jg      short 0126103F                  ;  粗略来看下面这些跳转是为了找出a[n],a[2n],a[2n+1]中较大的数
0126101D  |.  83F9 0A       |cmp     ecx, 0A                         ;  if (2n<10)
01261020  |>  7D 0A         |/jge     short 0126102C
01261022  |.  8B1488        ||mov     edx, dword ptr [eax+ecx*4]
01261025  |.  3B5488 04     ||cmp     edx, dword ptr [eax+ecx*4+4]   ;  if(a[2n]<a[2n+1])
01261029  |.  7D 01         ||jge     short 0126102C
0126102B  |.  41            ||inc     ecx
0126102C  |>  8B1488        ||mov     edx, dword ptr [eax+ecx*4]
0126102F  |.  3BDA          ||cmp     ebx, edx                       ;  if (a[n]<=a[2n+1])
01261031  |.  7F 0C         ||jg      short 0126103F
01261033  |.  8914B0        ||mov     dword ptr [eax+esi*4], edx     ;  a[n]=a[较大那个]
01261036  |.  8BF1          ||mov     esi, ecx                       ;  esi=ecx,这里ecx是最大数的下标
01261038  |.  03C9          ||add     ecx, ecx                       ;  ecx=2*ecx,继续向下搜索调整
0126103A  |.  83F9 0A       ||cmp     ecx, 0A
0126103D  |.^ 7E E1         |\jle     short 01261020
0126103F  |>  4F            |dec     edi                             ;  n--
01261040  |.  891CB0        |mov     dword ptr [eax+esi*4], ebx      ;  到这里,在看下上面涉及到了ebx的代码,观察下就可以发现a[n]==ebx,而这些代码的目的应该是找到最大数的位置,然后将a[n]替换进去
01261043  |.  85FF          |test    edi, edi                        ;  n>0则继续循环
01261045  |.^ 7F C9         \jg      short 01261010
01261047  |.  BA 09000000   mov     edx, 9
0126104C  |.  8D68 28       lea     ebp, dword ptr [eax+28]          ;  a[10]
0126104F  |.  90            nop
01261050  |>  8B75 00       /mov     esi, dword ptr [ebp]
01261053  |.  8B48 04       |mov     ecx, dword ptr [eax+4]          ;  SWAP a[1],a[10]
01261056  |.  8970 04       |mov     dword ptr [eax+4], esi          ;  a[10]
01261059  |.  894D 00       |mov     dword ptr [ebp], ecx
0126105C  |.  8B58 04       |mov     ebx, dword ptr [eax+4]
0126105F  |.  B9 02000000   |mov     ecx, 2
01261064  |.  3BCA          |cmp     ecx, edx                        ;  我们假设edx就是n吧,这样的话if(2<n)
01261066  |.  BE 01000000   |mov     esi, 1
0126106B  |.  7F 1E         |jg      short 0126108B
0126106D  |>  7D 0A         |/jge     short 01261079                 ;  下面这段循环和上面一个套路,只是优化后略有不同(明明是一个函数,妹的)
0126106F  |.  8B3C88        ||mov     edi, dword ptr [eax+ecx*4]
01261072  |.  3B7C88 04     ||cmp     edi, dword ptr [eax+ecx*4+4]
01261076  |.  7D 01         ||jge     short 01261079
01261078  |.  41            ||inc     ecx
01261079  |>  8B3C88        ||mov     edi, dword ptr [eax+ecx*4]
0126107C  |.  3BDF          ||cmp     ebx, edi
0126107E  |.  7F 0B         ||jg      short 0126108B
01261080  |.  893CB0        ||mov     dword ptr [eax+esi*4], edi
01261083  |.  8BF1          ||mov     esi, ecx
01261085  |.  03C9          ||add     ecx, ecx
01261087  |.  3BCA          ||cmp     ecx, edx
01261089  |.^ 7E E2         |\jle     short 0126106D
0126108B  |>  4A            |dec     edx                             ;  n--
0126108C  |.  83ED 04       |sub     ebp, 4
0126108F  |.  891CB0        |mov     dword ptr [eax+esi*4], ebx
01261092  |.  85D2          |test    edx, edx
01261094  |.^ 7F BA         \jg      short 01261050
01261096  |.  5F            pop     edi
01261097  |.  5E            pop     esi
01261098  |.  5D            pop     ebp
01261099  |.  5B            pop     ebx
0126109A  \.  C3            retn

总结:
逆向的时候在进入一个很多跳转的指令中时,最好大概看下循环中一些常用到的寄存器,然后可以将寄存器记在纸上,而不是向无头苍蝇一样直接冲进指令堆中,结果常常是找不着北,这样应该会有助于分析流程控制条件和实现的功能等
虽然一条条指令分析并记在纸上简单又准确我也常这样做,不过我想如果在遇到一些大,复杂的跳转循环之类的指令应该会很麻烦吧,我是这么认为。。总之有一定目的性的分析应该会更好些



-------------------------------------------------------------
  1. 版本:Release  
  2. 优化选项:O2  
  3. 调试工具:OD  
  4. 源码:  
版本:Release
优化选项:O2
调试工具:OD
源码:
  1. //二路归并排序(递归实现)   
  2. #include <stdio.h>   
  3. #include <stdlib.h>   
  4. #include <time.h>   
  5.   
  6. #define MAX_SIZE 10   
  7.   
  8. void merge(int init[],int mergesort[],int left,int mid,int right)  
  9. {  
  10.     int i=left,j=mid+1;  
  11.     int k=left;  
  12.     while(i<=mid&&j<=right)  
  13.     {  
  14.         if(init[i]<=init[j])  
  15.             mergesort[k++]=init[i++];  
  16.         else  
  17.             mergesort[k++]=init[j++];  
  18.     }  
  19.     while(i<=mid)  
  20.         mergesort[k++]=init[i++];  
  21.     while(j<=right)  
  22.         mergesort[k++]=init[j++];  
  23.     for(k=left;k<=right;k++)  
  24.         init[k]=mergesort[k];//must copy to orginal array   
  25. }  
  26.   
  27. void sort(int init[],int mergesort[],int left,int right)//递归版本   
  28. {  
  29.     int mid;  
  30.     if(left<right)  
  31.     {  
  32.         mid=(left+right)/2;  
  33.         sort(init,mergesort,left,mid);  
  34.         sort(init,mergesort,mid+1,right);  
  35.         merge(init,mergesort,left,mid,right);  
  36.     }  
  37. }  
  38.   
  39. int main()  
  40. {  
  41.     int i,left=0,right=MAX_SIZE-1;  
  42.     int init[MAX_SIZE],mergesort[MAX_SIZE];  
  43.     srand((unsigned)time(0));  
  44.     for(i=0;i<MAX_SIZE;i++)  
  45.         init[i]=rand()%50;  
  46.     for(i=0;i<MAX_SIZE;i++)  
  47.         printf("%4d",init[i]);  
  48.     sort(init,mergesort,left,right);  
  49.     for(i=0;i<MAX_SIZE;i++)  
  50.         printf("%4d",init[i]);  
  51.     system("pause");  
  52.     return 0;  
  53. }  
  54.   
  55. 首先是主函数的反汇编,主函数没什么需要注意的,就直接上代码了  
  56. 013C1100 >/$  83EC 50       sub     esp, 50  
  57. 013C1103  |.  56            push    esi  
  58. 013C1104  |.  57            push    edi  
  59. 013C1105  |.  6A 00         push    0  
  60. 013C1107  |.  FF15 A0203C01 call    dword ptr [<&MSVCR90._time64>]   ;  MSVCR90._time64  
  61. 013C110D  |.  50            push    eax                              ; /seed  
  62. 013C110E  |.  FF15 A4203C01 call    dword ptr [<&MSVCR90.srand>]     ; \srand  
  63. 013C1114  |.  8B3D A8203C01 mov     edi, dword ptr [<&MSVCR90.rand>] ;  MSVCR90.rand  
  64. 013C111A  |.  83C4 08       add     esp, 8  
  65. 013C111D  |.  33F6          xor     esi, esi  
  66. 013C111F  |.  90            nop  
  67. 013C1120  |>  FFD7          /call    edi                             ;  这个循环作用就是取得10个随机数存入数组,不多说  
  68. 013C1122  |.  99            |cdq  
  69. 013C1123  |.  B9 32000000   |mov     ecx, 32  
  70. 013C1128  |.  F7F9          |idiv    ecx  
  71. 013C112A  |.  46            |inc     esi  
  72. 013C112B  |.  83FE 0A       |cmp     esi, 0A  
  73. 013C112E  |.  8954B4 04     |mov     dword ptr [esp+esi*4+4], edx  
  74. 013C1132  |.^ 7C EC         \jl      short 013C1120  
  75. 013C1134  |.  8B3D AC203C01 mov     edi, dword ptr [<&MSVCR90.printf>;  MSVCR90.printf  
  76. 013C113A  |.  33F6          xor     esi, esi  
  77. 013C113C  |.  8D6424 00     lea     esp, dword ptr [esp]  
  78. 013C1140  |>  8B54B4 08     /mov     edx, dword ptr [esp+esi*4+8]    ;  输出10个随机数  
  79. 013C1144  |.  52            |push    edx  
  80. 013C1145  |.  68 04213C01   |push    013C2104                        ;  ASCII "%4d"  
  81. 013C114A  |.  FFD7          |call    edi  
  82. 013C114C  |.  46            |inc     esi  
  83. 013C114D  |.  83C4 08       |add     esp, 8  
  84. 013C1150  |.  83FE 0A       |cmp     esi, 0A  
  85. 013C1153  |.^ 7C EB         \jl      short 013C1140  
  86. 013C1155  |.  6A 04         push    4                                ;  下面连着几个sort调用应该是编译器优化出来的,被分成几次调用并移到主函数中  
  87. 013C1157  |.  6A 00         push    0  
  88. 013C1159  |.  8D4424 38     lea     eax, dword ptr [esp+38]          ;  临时数组地址(紧接着待排序数组)  
  89. 013C115D  |.  50            push    eax  
  90. 013C115E  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]  
  91. 013C1162  |.  51            push    ecx                              ;  待排序数组地址  
  92. 013C1163  |.  E8 48FFFFFF   call    sort  
  93. 013C1168  |.  6A 09         push    9  
  94. 013C116A  |.  6A 05         push    5  
  95. 013C116C  |.  8D5424 48     lea     edx, dword ptr [esp+48]  
  96. 013C1170  |.  52            push    edx  
  97. 013C1171  |.  8D4424 24     lea     eax, dword ptr [esp+24]  
  98. 013C1175  |.  50            push    eax  
  99. 013C1176  |.  E8 35FFFFFF   call    sort  
  100. 013C117B  |.  6A 09         push    9  
  101. 013C117D  |.  6A 04         push    4  
  102. 013C117F  |.  8D4C24 58     lea     ecx, dword ptr [esp+58]  
  103. 013C1183  |.  6A 00         push    0  
  104. 013C1185  |.  51            push    ecx  
  105. 013C1186  |.  8D7424 38     lea     esi, dword ptr [esp+38]  
  106. 013C118A  |.  E8 71FEFFFF   call    merge  
  107. 013C118F  |.  83C4 30       add     esp, 30  
  108. 013C1192  |.  33F6          xor     esi, esi  
  109. 013C1194  |>  8B54B4 08     /mov     edx, dword ptr [esp+esi*4+8]    ;  输出排序后数组  
  110. 013C1198  |.  52            |push    edx  
  111. 013C1199  |.  68 04213C01   |push    013C2104                        ;  ASCII "%4d"  
  112. 013C119E  |.  FFD7          |call    edi  
  113. 013C11A0  |.  46            |inc     esi  
  114. 013C11A1  |.  83C4 08       |add     esp, 8  
  115. 013C11A4  |.  83FE 0A       |cmp     esi, 0A  
  116. 013C11A7  |.^ 7C EB         \jl      short 013C1194  
  117. 013C11A9  |.  68 08213C01   push    013C2108                         ; /command = "pause"  
  118. 013C11AE  |.  FF15 B0203C01 call    dword ptr [<&MSVCR90.system>]    ; \system  
  119. 013C11B4  |.  83C4 04       add     esp, 4  
  120. 013C11B7  |.  5F            pop     edi  
  121. 013C11B8  |.  33C0          xor     eax, eax  
  122. 013C11BA  |.  5E            pop     esi  
  123. 013C11BB  |.  83C4 50       add     esp, 50  
  124. 013C11BE  \.  C3            retn  
  125.   
  126.   
  127. 接下来是sort函数的反汇编,也没啥难度,就是些调用,直接贴代码  
  128. 013C10B0 >/$  53            push    ebx  
  129. 013C10B1  |.  8B5C24 10     mov     ebx, dword ptr [esp+10]          ;  第3个参数  
  130. 013C10B5  |.  55            push    ebp  
  131. 013C10B6  |.  8B6C24 18     mov     ebp, dword ptr [esp+18]          ;  第4个参数  
  132. 013C10BA  |.  3BDD          cmp     ebx, ebp  
  133. 013C10BC  |.  7D 3F         jge     short 013C10FD  
  134. 013C10BE  |.  56            push    esi  
  135. 013C10BF  |.  8B7424 14     mov     esi, dword ptr [esp+14]          ;  第2个参数  
  136. 013C10C3  |.  8D042B        lea     eax, dword ptr [ebx+ebp]         ;  left+right?  
  137. 013C10C6  |.  99            cdq  
  138. 013C10C7  |.  57            push    edi  
  139. 013C10C8  |.  2BC2          sub     eax, edx  
  140. 013C10CA  |.  8BF8          mov     edi, eax  
  141. 013C10CC  |.  8B4424 14     mov     eax, dword ptr [esp+14]          ;  第一个参数  
  142. 013C10D0  |.  D1FF          sar     edi, 1                           ;  (left+right)/2  
  143. 013C10D2  |.  57            push    edi  
  144. 013C10D3  |.  53            push    ebx                              ;  left  
  145. 013C10D4  |.  56            push    esi                              ;  就是传进来的第二个参数  
  146. 013C10D5  |.  50            push    eax                              ;  第一个参数  
  147. 013C10D6  |.  E8 D5FFFFFF   call    sort  
  148. 013C10DB  |.  8B5424 24     mov     edx, dword ptr [esp+24]  
  149. 013C10DF  |.  55            push    ebp                              ;  right  
  150. 013C10E0  |.  8D4F 01       lea     ecx, dword ptr [edi+1]           ;  left+1  
  151. 013C10E3  |.  51            push    ecx  
  152. 013C10E4  |.  56            push    esi  
  153. 013C10E5  |.  52            push    edx  
  154. 013C10E6  |.  E8 C5FFFFFF   call    sort  
  155. 013C10EB  |.  55            push    ebp                              ;  right  
  156. 013C10EC  |.  57            push    edi                              ;  (left+right)/2  
  157. 013C10ED  |.  53            push    ebx                              ;  left  
  158. 013C10EE  |.  56            push    esi                              ;  第二个参数  
  159. 013C10EF  |.  8B7424 44     mov     esi, dword ptr [esp+44]          ;  第一个参数  
  160. 013C10F3  |.  E8 08FFFFFF   call    merge  
  161. 013C10F8  |.  83C4 30       add     esp, 30  
  162. 013C10FB  |.  5F            pop     edi  
  163. 013C10FC  |.  5E            pop     esi  
  164. 013C10FD  |>  5D            pop     ebp  
  165. 013C10FE  |.  5B            pop     ebx  
  166. 013C10FF  \.  C3            retn  
  167.   
  168. 接下来就是主要的排序实现函数merge的代码了,C版的是有5个参数,而汇编版只有4个参数是明显的,还有一个参数是直接用寄存器存储这个要注意下  
  169. 013C1000 >/$  53            push    ebx  
  170. 013C1001  |.  8B5C24 10     mov     ebx, dword ptr [esp+10]          ;  第4个参数(以C源码来说)  
  171. 013C1005  |.  55            push    ebp  
  172. 013C1006  |.  8B6C24 18     mov     ebp, dword ptr [esp+18]          ;  第5个参数  
  173. 013C100A  |.  57            push    edi  
  174. 013C100B  |.  8B7C24 14     mov     edi, dword ptr [esp+14]          ;  第3个参数  
  175. 013C100F  |.  3BFB          cmp     edi, ebx                         ;  cmp left,mid  
  176. 013C1011  |.  8BCF          mov     ecx, edi                         ;  这个ecx用于后面循环的下标增长  
  177. 013C1013  |.  8D53 01       lea     edx, dword ptr [ebx+1]           ;  edx=mid+1  
  178. 013C1016  |.  8BC7          mov     eax, edi                         ;  这个eax就是排序后数组中的下标  
  179. 013C1018  |.  7F 50         jg      short 013C106A  
  180. 013C101A  |.  8D9B 00000000 lea     ebx, dword ptr [ebx]  
  181.   
  182.   
  183. 013C1020  |>  3BD5          /cmp     edx, ebp  
  184. 013C1022  |.  7F 2A         |jg      short 013C104E  
  185. 013C1024  |.  8B3C8E        |mov     edi, dword ptr [esi+ecx*4]      ;  a[left]  
  186. 013C1027  |.  8B1C96        |mov     ebx, dword ptr [esi+edx*4]      ;  a[mid+1]  
  187. 013C102A  |.  3BFB          |cmp     edi, ebx  
  188. 013C102C  |.  7F 0B         |jg      short 013C1039  
  189. 013C102E  |.  8B5C24 10     |mov     ebx, dword ptr [esp+10]         ;  第二个参数(目标数组)  
  190. 013C1032  |.  893C83        |mov     dword ptr [ebx+eax*4], edi  
  191. 013C1035  |.  40            |inc     eax  
  192. 013C1036  |.  41            |inc     ecx  
  193. 013C1037  |.  EB 09         |jmp     short 013C1042  
  194. 013C1039  |>  8B7C24 10     |mov     edi, dword ptr [esp+10]  
  195. 013C103D  |.  891C87        |mov     dword ptr [edi+eax*4], ebx  
  196. 013C1040  |.  40            |inc     eax                             ;  eax==left  
  197. 013C1041  |.  42            |inc     edx                             ;  edx==mid+1  
  198. 013C1042  |>  3B4C24 18     |cmp     ecx, dword ptr [esp+18]         ;  cmp ecx,mid  
  199. 013C1046  |.  8B7C24 14     |mov     edi, dword ptr [esp+14]  
  200. 013C104A  |.^ 7E D4         \jle     short 013C1020  
  201. 上面这个隔开了的循环是主要循环,而且感觉应该是和源码有点出入  
  202. 我的反汇编还原结果:                                     源码:                                                                  
  203. while(j<=right)                                               while(i<=mid&&j<=right)        
  204. {                                                                    {  
  205.       if(init[i]<=init[j])                                               if(init[i]<=init[j])  
  206.            mergesort[k++]=init[i++];                               mergesort[k++]=init[i++];  
  207.       else                                                                 else  
  208.            mergesort[k++]=init[j++];                               mergesort[k++]=init[j++];  
  209.       if(i>mid)   break;                                      }  
  210. }  
  211. 发现了吗?在第一次进入循环的时候判断为真缺了个i<=mid,后面的是一样的,只有在第一次进入会发生这种情况  
  212. 反正我是不知道为什么。。也许在某些情况下就会发生错误呢?于是抱着编译器不可能这么不严禁的态度继续研究研究,于是发现  
  213. 这样是没有问题的,其实传入的3个参数有这样一种关系:mid=(left+right)/2;经过一些计算就可以发现当(mid+2)<=right{j<=right}时,left<=right{i<=mid}必定成立(自己可以算算),当然仅限于第一次进入循环的时候,也就是说编译器编译的时候提前发现了这种数学关系然后做了些小优化吧。感叹下写编译器的人真牛!  
  214.   
  215.   
  216. 013C104C  |.  EB 1C         jmp     short 013C106A  
  217. 013C104E  |>  3B4C24 18     cmp     ecx, dword ptr [esp+18]          ;  这和上面那个循环判断条件一样,再之下一个循环也是一个类似的判断,2个循环大体表达一个意思只是参数有所不同,仔细看看应该能发现  
  218. 013C1052  |.  7F 16         jg      short 013C106A  
  219. 013C1054  |>  8B3C8E        /mov     edi, dword ptr [esi+ecx*4]  
  220. 013C1057  |.  8B5C24 10     |mov     ebx, dword ptr [esp+10]         ;  目标数组的地址  
  221. 013C105B  |.  893C83        |mov     dword ptr [ebx+eax*4], edi      ;  将比较结果后其中一个数存入结果数组  
  222. 013C105E  |.  41            |inc     ecx  
  223. 013C105F  |.  40            |inc     eax  
  224. 013C1060  |.  3B4C24 18     |cmp     ecx, dword ptr [esp+18]  
  225. 013C1064  |.^ 7E EE         \jle     short 013C1054                  ;  这个循环大体上是 while(i<=j) b[x++]=a[j];这个样子  
  226. 013C1066  |.  8B7C24 14     mov     edi, dword ptr [esp+14]  
  227. 013C106A  |>  3BD5          cmp     edx, ebp  
  228. 013C106C  |.  7F 14         jg      short 013C1082  
  229. 013C106E  |.  8B4C24 10     mov     ecx, dword ptr [esp+10]          ;  这个循环指令有所不同,但意思是一个意思仅参数有所区别,就不多说了  
  230. 013C1072  |.  8D0481        lea     eax, dword ptr [ecx+eax*4]  
  231. 013C1075  |>  8B0C96        /mov     ecx, dword ptr [esi+edx*4]  
  232. 013C1078  |.  8908          |mov     dword ptr [eax], ecx  
  233. 013C107A  |.  42            |inc     edx  
  234. 013C107B  |.  83C0 04       |add     eax, 4  
  235. 013C107E  |.  3BD5          |cmp     edx, ebp  
  236. 013C1080  |.^ 7E F3         \jle     short 013C1075  
  237. 013C1082  |>  3BFD          cmp     edi, ebp  
  238. 013C1084  |.  7F 19         jg      short 013C109F  
  239. 013C1086  |.  8B4C24 10     mov     ecx, dword ptr [esp+10]          ;  目标数组地址  
  240. 013C108A  |.  2BEF          sub     ebp, edi                         ;  right-left  
  241. 013C108C  |.  2BCE          sub     ecx, esi                         ;  ecx==待排序数组大小  
  242. 013C108E  |.  8D04BE        lea     eax, dword ptr [esi+edi*4]       ;  a[left]  
  243. 013C1091  |.  45            inc     ebp  
  244. 013C1092  |>  8B1401        /mov     edx, dword ptr [ecx+eax]  
  245. 013C1095  |.  8910          |mov     dword ptr [eax], edx  
  246. 013C1097  |.  83C0 04       |add     eax, 4  
  247. 013C109A  |.  83ED 01       |sub     ebp, 1  
  248. 013C109D  |.^ 75 F3         \jnz     short 013C1092                  ;  这个循环模式大体上是while(right--) a[i++]=b[i++];  
  249. 013C109F  |>  5F            pop     edi  
  250. 013C10A0  |.  5D            pop     ebp  
  251. 013C10A1  |.  5B            pop     ebx  
  252. 013C10A2  \.  C3            retn  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值