第五篇:逆向之二路归并排序

版本:Release
优化选项:O2
调试工具:OD
源码:
//二路归并排序(递归实现)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX_SIZE 10

void merge(int init[],int mergesort[],int left,int mid,int right)
{
	int i=left,j=mid+1;
	int k=left;
	while(i<=mid&&j<=right)
	{
		if(init[i]<=init[j])
			mergesort[k++]=init[i++];
		else
			mergesort[k++]=init[j++];
	}
	while(i<=mid)
		mergesort[k++]=init[i++];
	while(j<=right)
		mergesort[k++]=init[j++];
	for(k=left;k<=right;k++)
		init[k]=mergesort[k];//must copy to orginal array
}

void sort(int init[],int mergesort[],int left,int right)//递归版本
{
	int mid;
	if(left<right)
	{
		mid=(left+right)/2;
		sort(init,mergesort,left,mid);
		sort(init,mergesort,mid+1,right);
		merge(init,mergesort,left,mid,right);
	}
}

int main()
{
	int i,left=0,right=MAX_SIZE-1;
	int init[MAX_SIZE],mergesort[MAX_SIZE];
	srand((unsigned)time(0));
	for(i=0;i<MAX_SIZE;i++)
		init[i]=rand()%50;
	for(i=0;i<MAX_SIZE;i++)
		printf("%4d",init[i]);
	sort(init,mergesort,left,right);
	for(i=0;i<MAX_SIZE;i++)
		printf("%4d",init[i]);
	system("pause");
	return 0;
}

首先是主函数的反汇编,主函数没什么需要注意的,就直接上代码了
013C1100 >/$  83EC 50       sub     esp, 50
013C1103  |.  56            push    esi
013C1104  |.  57            push    edi
013C1105  |.  6A 00         push    0
013C1107  |.  FF15 A0203C01 call    dword ptr [<&MSVCR90._time64>]   ;  MSVCR90._time64
013C110D  |.  50            push    eax                              ; /seed
013C110E  |.  FF15 A4203C01 call    dword ptr [<&MSVCR90.srand>]     ; \srand
013C1114  |.  8B3D A8203C01 mov     edi, dword ptr [<&MSVCR90.rand>] ;  MSVCR90.rand
013C111A  |.  83C4 08       add     esp, 8
013C111D  |.  33F6          xor     esi, esi
013C111F  |.  90            nop
013C1120  |>  FFD7          /call    edi                             ;  这个循环作用就是取得10个随机数存入数组,不多说
013C1122  |.  99            |cdq
013C1123  |.  B9 32000000   |mov     ecx, 32
013C1128  |.  F7F9          |idiv    ecx
013C112A  |.  46            |inc     esi
013C112B  |.  83FE 0A       |cmp     esi, 0A
013C112E  |.  8954B4 04     |mov     dword ptr [esp+esi*4+4], edx
013C1132  |.^ 7C EC         \jl      short 013C1120
013C1134  |.  8B3D AC203C01 mov     edi, dword ptr [<&MSVCR90.printf>;  MSVCR90.printf
013C113A  |.  33F6          xor     esi, esi
013C113C  |.  8D6424 00     lea     esp, dword ptr [esp]
013C1140  |>  8B54B4 08     /mov     edx, dword ptr [esp+esi*4+8]    ;  输出10个随机数
013C1144  |.  52            |push    edx
013C1145  |.  68 04213C01   |push    013C2104                        ;  ASCII "%4d"
013C114A  |.  FFD7          |call    edi
013C114C  |.  46            |inc     esi
013C114D  |.  83C4 08       |add     esp, 8
013C1150  |.  83FE 0A       |cmp     esi, 0A
013C1153  |.^ 7C EB         \jl      short 013C1140
013C1155  |.  6A 04         push    4                                ;  下面连着几个sort调用应该是编译器优化出来的,被分成几次调用并移到主函数中
013C1157  |.  6A 00         push    0
013C1159  |.  8D4424 38     lea     eax, dword ptr [esp+38]          ;  临时数组地址(紧接着待排序数组)
013C115D  |.  50            push    eax
013C115E  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
013C1162  |.  51            push    ecx                              ;  待排序数组地址
013C1163  |.  E8 48FFFFFF   call    sort
013C1168  |.  6A 09         push    9
013C116A  |.  6A 05         push    5
013C116C  |.  8D5424 48     lea     edx, dword ptr [esp+48]
013C1170  |.  52            push    edx
013C1171  |.  8D4424 24     lea     eax, dword ptr [esp+24]
013C1175  |.  50            push    eax
013C1176  |.  E8 35FFFFFF   call    sort
013C117B  |.  6A 09         push    9
013C117D  |.  6A 04         push    4
013C117F  |.  8D4C24 58     lea     ecx, dword ptr [esp+58]
013C1183  |.  6A 00         push    0
013C1185  |.  51            push    ecx
013C1186  |.  8D7424 38     lea     esi, dword ptr [esp+38]
013C118A  |.  E8 71FEFFFF   call    merge
013C118F  |.  83C4 30       add     esp, 30
013C1192  |.  33F6          xor     esi, esi
013C1194  |>  8B54B4 08     /mov     edx, dword ptr [esp+esi*4+8]    ;  输出排序后数组
013C1198  |.  52            |push    edx
013C1199  |.  68 04213C01   |push    013C2104                        ;  ASCII "%4d"
013C119E  |.  FFD7          |call    edi
013C11A0  |.  46            |inc     esi
013C11A1  |.  83C4 08       |add     esp, 8
013C11A4  |.  83FE 0A       |cmp     esi, 0A
013C11A7  |.^ 7C EB         \jl      short 013C1194
013C11A9  |.  68 08213C01   push    013C2108                         ; /command = "pause"
013C11AE  |.  FF15 B0203C01 call    dword ptr [<&MSVCR90.system>]    ; \system
013C11B4  |.  83C4 04       add     esp, 4
013C11B7  |.  5F            pop     edi
013C11B8  |.  33C0          xor     eax, eax
013C11BA  |.  5E            pop     esi
013C11BB  |.  83C4 50       add     esp, 50
013C11BE  \.  C3            retn


接下来是sort函数的反汇编,也没啥难度,就是些调用,直接贴代码
013C10B0 >/$  53            push    ebx
013C10B1  |.  8B5C24 10     mov     ebx, dword ptr [esp+10]          ;  第3个参数
013C10B5  |.  55            push    ebp
013C10B6  |.  8B6C24 18     mov     ebp, dword ptr [esp+18]          ;  第4个参数
013C10BA  |.  3BDD          cmp     ebx, ebp
013C10BC  |.  7D 3F         jge     short 013C10FD
013C10BE  |.  56            push    esi
013C10BF  |.  8B7424 14     mov     esi, dword ptr [esp+14]          ;  第2个参数
013C10C3  |.  8D042B        lea     eax, dword ptr [ebx+ebp]         ;  left+right?
013C10C6  |.  99            cdq
013C10C7  |.  57            push    edi
013C10C8  |.  2BC2          sub     eax, edx
013C10CA  |.  8BF8          mov     edi, eax
013C10CC  |.  8B4424 14     mov     eax, dword ptr [esp+14]          ;  第一个参数
013C10D0  |.  D1FF          sar     edi, 1                           ;  (left+right)/2
013C10D2  |.  57            push    edi
013C10D3  |.  53            push    ebx                              ;  left
013C10D4  |.  56            push    esi                              ;  就是传进来的第二个参数
013C10D5  |.  50            push    eax                              ;  第一个参数
013C10D6  |.  E8 D5FFFFFF   call    sort
013C10DB  |.  8B5424 24     mov     edx, dword ptr [esp+24]
013C10DF  |.  55            push    ebp                              ;  right
013C10E0  |.  8D4F 01       lea     ecx, dword ptr [edi+1]           ;  left+1
013C10E3  |.  51            push    ecx
013C10E4  |.  56            push    esi
013C10E5  |.  52            push    edx
013C10E6  |.  E8 C5FFFFFF   call    sort
013C10EB  |.  55            push    ebp                              ;  right
013C10EC  |.  57            push    edi                              ;  (left+right)/2
013C10ED  |.  53            push    ebx                              ;  left
013C10EE  |.  56            push    esi                              ;  第二个参数
013C10EF  |.  8B7424 44     mov     esi, dword ptr [esp+44]          ;  第一个参数
013C10F3  |.  E8 08FFFFFF   call    merge
013C10F8  |.  83C4 30       add     esp, 30
013C10FB  |.  5F            pop     edi
013C10FC  |.  5E            pop     esi
013C10FD  |>  5D            pop     ebp
013C10FE  |.  5B            pop     ebx
013C10FF  \.  C3            retn

接下来就是主要的排序实现函数merge的代码了,C版的是有5个参数,而汇编版只有4个参数是明显的,还有一个参数是直接用寄存器存储这个要注意下
013C1000 >/$  53            push    ebx
013C1001  |.  8B5C24 10     mov     ebx, dword ptr [esp+10]          ;  第4个参数(以C源码来说)
013C1005  |.  55            push    ebp
013C1006  |.  8B6C24 18     mov     ebp, dword ptr [esp+18]          ;  第5个参数
013C100A  |.  57            push    edi
013C100B  |.  8B7C24 14     mov     edi, dword ptr [esp+14]          ;  第3个参数
013C100F  |.  3BFB          cmp     edi, ebx                         ;  cmp left,mid
013C1011  |.  8BCF          mov     ecx, edi                         ;  这个ecx用于后面循环的下标增长
013C1013  |.  8D53 01       lea     edx, dword ptr [ebx+1]           ;  edx=mid+1
013C1016  |.  8BC7          mov     eax, edi                         ;  这个eax就是排序后数组中的下标
013C1018  |.  7F 50         jg      short 013C106A
013C101A  |.  8D9B 00000000 lea     ebx, dword ptr [ebx]


013C1020  |>  3BD5          /cmp     edx, ebp
013C1022  |.  7F 2A         |jg      short 013C104E
013C1024  |.  8B3C8E        |mov     edi, dword ptr [esi+ecx*4]      ;  a[left]
013C1027  |.  8B1C96        |mov     ebx, dword ptr [esi+edx*4]      ;  a[mid+1]
013C102A  |.  3BFB          |cmp     edi, ebx
013C102C  |.  7F 0B         |jg      short 013C1039
013C102E  |.  8B5C24 10     |mov     ebx, dword ptr [esp+10]         ;  第二个参数(目标数组)
013C1032  |.  893C83        |mov     dword ptr [ebx+eax*4], edi
013C1035  |.  40            |inc     eax
013C1036  |.  41            |inc     ecx
013C1037  |.  EB 09         |jmp     short 013C1042
013C1039  |>  8B7C24 10     |mov     edi, dword ptr [esp+10]
013C103D  |.  891C87        |mov     dword ptr [edi+eax*4], ebx
013C1040  |.  40            |inc     eax                             ;  eax==left
013C1041  |.  42            |inc     edx                             ;  edx==mid+1
013C1042  |>  3B4C24 18     |cmp     ecx, dword ptr [esp+18]         ;  cmp ecx,mid
013C1046  |.  8B7C24 14     |mov     edi, dword ptr [esp+14]
013C104A  |.^ 7E D4         \jle     short 013C1020
上面这个隔开了的循环是主要循环,而且感觉应该是和源码有点出入
我的反汇编还原结果:                                     源码:                                                                
while(j<=right)                                               while(i<=mid&&j<=right)      
{                                                                    {
      if(init[i]<=init[j])                                               if(init[i]<=init[j])
           mergesort[k++]=init[i++];                               mergesort[k++]=init[i++];
      else                                                                 else
           mergesort[k++]=init[j++];                               mergesort[k++]=init[j++];
      if(i>mid)   break;                                      }
}
发现了吗?在第一次进入循环的时候判断为真缺了个i<=mid,后面的是一样的,只有在第一次进入会发生这种情况
反正我是不知道为什么。。也许在某些情况下就会发生错误呢?于是抱着编译器不可能这么不严禁的态度继续研究研究,于是发现
这样是没有问题的,其实传入的3个参数有这样一种关系:mid=(left+right)/2;经过一些计算就可以发现当(mid+2)<=right{j<=right}时,left<=right{i<=mid}必定成立(自己可以算算),当然仅限于第一次进入循环的时候,也就是说编译器编译的时候提前发现了这种数学关系然后做了些小优化吧。感叹下写编译器的人真牛!


013C104C  |.  EB 1C         jmp     short 013C106A
013C104E  |>  3B4C24 18     cmp     ecx, dword ptr [esp+18]          ;  这和上面那个循环判断条件一样,再之下一个循环也是一个类似的判断,2个循环大体表达一个意思只是参数有所不同,仔细看看应该能发现
013C1052  |.  7F 16         jg      short 013C106A
013C1054  |>  8B3C8E        /mov     edi, dword ptr [esi+ecx*4]
013C1057  |.  8B5C24 10     |mov     ebx, dword ptr [esp+10]         ;  目标数组的地址
013C105B  |.  893C83        |mov     dword ptr [ebx+eax*4], edi      ;  将比较结果后其中一个数存入结果数组
013C105E  |.  41            |inc     ecx
013C105F  |.  40            |inc     eax
013C1060  |.  3B4C24 18     |cmp     ecx, dword ptr [esp+18]
013C1064  |.^ 7E EE         \jle     short 013C1054                  ;  这个循环大体上是 while(i<=j) b[x++]=a[j];这个样子
013C1066  |.  8B7C24 14     mov     edi, dword ptr [esp+14]
013C106A  |>  3BD5          cmp     edx, ebp
013C106C  |.  7F 14         jg      short 013C1082
013C106E  |.  8B4C24 10     mov     ecx, dword ptr [esp+10]          ;  这个循环指令有所不同,但意思是一个意思仅参数有所区别,就不多说了
013C1072  |.  8D0481        lea     eax, dword ptr [ecx+eax*4]
013C1075  |>  8B0C96        /mov     ecx, dword ptr [esi+edx*4]
013C1078  |.  8908          |mov     dword ptr [eax], ecx
013C107A  |.  42            |inc     edx
013C107B  |.  83C0 04       |add     eax, 4
013C107E  |.  3BD5          |cmp     edx, ebp
013C1080  |.^ 7E F3         \jle     short 013C1075
013C1082  |>  3BFD          cmp     edi, ebp
013C1084  |.  7F 19         jg      short 013C109F
013C1086  |.  8B4C24 10     mov     ecx, dword ptr [esp+10]          ;  目标数组地址
013C108A  |.  2BEF          sub     ebp, edi                         ;  right-left
013C108C  |.  2BCE          sub     ecx, esi                         ;  ecx==待排序数组大小
013C108E  |.  8D04BE        lea     eax, dword ptr [esi+edi*4]       ;  a[left]
013C1091  |.  45            inc     ebp
013C1092  |>  8B1401        /mov     edx, dword ptr [ecx+eax]
013C1095  |.  8910          |mov     dword ptr [eax], edx
013C1097  |.  83C0 04       |add     eax, 4
013C109A  |.  83ED 01       |sub     ebp, 1
013C109D  |.^ 75 F3         \jnz     short 013C1092                  ;  这个循环模式大体上是while(right--) a[i++]=b[i++];
013C109F  |>  5F            pop     edi
013C10A0  |.  5D            pop     ebp
013C10A1  |.  5B            pop     ebx
013C10A2  \.  C3            retn

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值