VBGood网站全文搜索 Google

搜索VBGood全站网页(全文搜索)

VB爱好者乐园(VBGood)

 找回密码
 立即注册
搜索
查看: 5761|回复: 11

关于acme_pjz的call msvcrt.dll@qsort的分析

[复制链接]
发表于 2012-10-7 11:21:55 | 显示全部楼层 |阅读模式
原贴:http://www.vbgood.com/thread-92406-1-1.html
主题:VC中的qsort源代码翻译成VB的了

下面是CallWindowProc VarPtr(m_bCode(0)), VarPtr(idxArray(nStart)), nEnd - nStart + 1, m_lpFunc, 0的od分析:

00402B89   .  8B55 D0       mov edx,dword ptr ss:[ebp-30]            ;  msvcrt.qsort
00402B8C   .  8B45 D4       mov eax,dword ptr ss:[ebp-2C]
00402B8F   .  6A 00         push 0
00402B91   .  52            push edx                                 ;  将msvcrt.qsort的地址压入
00402B92   .  40            inc eax
00402B93   .  50            push eax                                 ;  数组的大小
00402B94   .  56            push esi                                 ;  数组的首地址
00402B95   .  53            push ebx                                 ;  一段asm代码
00402B96   .  E8 C9F3FFFF   call 工程1.00401F64                      ;  USER32.CallWindowProcA


一段asm的代码:
002FE470    89E0            mov eax,esp
002FE472    E8 00000000     call 002FE477
002FE477    830424 15       add dword ptr ss:[esp],15
002FE47B    6A 04           push 4
002FE47D    FF70 08         push dword ptr ds:[eax+8]
002FE480    FF70 04         push dword ptr ds:[eax+4]
002FE483    FF50 0C         call dword ptr ds:[eax+C]
002FE486    83C4 10         add esp,10
002FE489    C2 1000         retn 10
002FE48C    6A 00           push 0
002FE48E    89E0            mov eax,esp
002FE490    8B15 38E32F00   mov edx,dword ptr ds:[2FE338]
002FE496    50              push eax
002FE497    FF35 3CE32F00   push dword ptr ds:[2FE33C]
002FE49D    8B48 0C         mov ecx,dword ptr ds:[eax+C]
002FE4A0    8B40 08         mov eax,dword ptr ds:[eax+8]
002FE4A3    FF31            push dword ptr ds:[ecx]
002FE4A5    FF30            push dword ptr ds:[eax]
002FE4A7    8B0A            mov ecx,dword ptr ds:[edx]
002FE4A9    52              push edx
002FE4AA    FF51 1C         call dword ptr ds:[ecx+1C]
002FE4AD    58              pop eax
002FE4AE    C3              retn

我们跟进USER32.CallWindowProcA:
75C52BD3 >  8BFF            mov edi,edi                              ; USER32.CallWindowProcA函数首地址
75C52BD5    55              push ebp
75C52BD6    8BEC            mov ebp,esp
75C52BD8    6A 01           push 1
75C52BDA    FF75 18         push dword ptr ss:[ebp+18]               ; 0
75C52BDD    FF75 14         push dword ptr ss:[ebp+14]               ; msvcrt.qsort
75C52BE0    FF75 10         push dword ptr ss:[ebp+10]               ; 数组大小
75C52BE3    FF75 0C         push dword ptr ss:[ebp+C]                ; 数组首地址
75C52BE6    FF75 08         push dword ptr ss:[ebp+8]                ; 一段asm代码
75C52BE9    E8 F2EEFDFF     call USER32.75C31AE0                     ; 这里要跟进去
75C52BEE    5D              pop ebp
75C52BEF    C2 1400         retn 14

跟进call USER32.75C31AE0:

75C31AE0    8BFF            mov edi,edi                          ; edi=0
75C31AE2    55              push ebp
75C31AE3    8BEC            mov ebp,esp
75C31AE5    56              push esi
75C31AE6    8B75 08         mov esi,dword ptr ss:[ebp+8]         ; 一段asm代码的首地址
75C31AE9    85F6            test esi,esi                         ; 是否为0
75C31AEB    0F84 EA2E0100   je USER32.75C449DB
75C31AF1    B8 0000FFFF     mov eax,FFFF0000
75C31AF6    8BCE            mov ecx,esi
75C31AF8    23C8            and ecx,eax                          ; 取一段asm代码首地址的高位
75C31AFA    57              push edi
75C31AFB    8B7D 10         mov edi,dword ptr ss:[ebp+10]        ; 数组的大小
75C31AFE    3BC8            cmp ecx,eax                          ; 一段asm代码首地址的高位是否等于FFFF
75C31B00  ^ 0F84 7C77FFFF   je USER32.75C29282
75C31B06    8B4D 0C         mov ecx,dword ptr ss:[ebp+C]         ; 数组的首地址
75C31B09    E8 02AA0000     call USER32.75C3C510                 ; 跟进去
75C31B0E    85C0            test eax,eax                         ; eax=0
75C31B10    0F84 CE2D0100   je USER32.75C448E4                   ; 直接跳走

75C3C510    64:A1 18000000  mov eax,dword ptr fs:[18]
75C3C516    05 CC060000     add eax,6CC
75C3C51B    85C9            test ecx,ecx                             ; 数组的首地址
75C3C51D    74 09           je short USER32.75C3C528
75C3C51F    3B48 28         cmp ecx,dword ptr ds:[eax+28]            ; 其实是比较第二个参数是否为0
75C3C522  ^ 0F84 148AFFFF   je USER32.75C34F3C
75C3C528    B2 01           mov dl,1
75C3C52A    E9 61050000     jmp USER32.75C3CA90
......
75C3CA90    8BFF            mov edi,edi                          ; edi等于数组的大小,其实就是第三个参数
75C3CA92    55              push ebp
75C3CA93    8BEC            mov ebp,esp
75C3CA95    51              push ecx                             ; 数组的首地址
75C3CA96    53              push ebx                             ; 一段asm代码的首地址
75C3CA97    56              push esi                             ; 一段asm代码的首地址
75C3CA98    64:8B35 1800000>mov esi,dword ptr fs:[18]
75C3CA9F    A1 F490C875     mov eax,dword ptr ds:[75C890F4]
75C3CAA4    8BD9            mov ebx,ecx                          ; 数组的首地址
75C3CAA6    0FB7CB          movzx ecx,bx                         ; 取数组首字节的低位
75C3CAA9    57              push edi
75C3CAAA    33FF            xor edi,edi
75C3CAAC    81C6 CC060000   add esi,6CC
75C3CAB2    8855 FC         mov byte ptr ss:[ebp-4],dl
75C3CAB5    3B48 04         cmp ecx,dword ptr ds:[eax+4]         ; 数组首字节的低位是否小于955
75C3CAB8    73 52           jnb short USER32.75C3CB0C            ; 直接跳走
......
75C3CB0C    85F6            test esi,esi
75C3CB0E    74 0D           je short USER32.75C3CB1D
75C3CB10    F746 14 0000002>test dword ptr ds:[esi+14],20000000
75C3CB17  ^ 0F85 F2FDFEFF   jnz USER32.75C2C90F
75C3CB1D    85FF            test edi,edi
75C3CB1F  ^\0F84 F2FDFEFF   je USER32.75C2C917                   ; 直接跳走
......
75C2C917    0FB645 FC       movzx eax,byte ptr ss:[ebp-4]        ; eax=1
75C2C91B    48              dec eax
75C2C91C    83F8 07         cmp eax,7
75C2C91F    77 6B           ja short USER32.75C2C98C             ; 没有跳走
75C2C921    FF2485 A0C9C275 jmp dword ptr ds:[eax*4+75C2C9A0]    ; 没有跳走
75C2C928    B8 78050000     mov eax,578
75C2C92D    50              push eax
75C2C92E    E8 D0FFFFFF     call USER32.75C2C903                 ; 跟进去,好像只是有关错误的处理
75C2C933    5F              pop edi
75C2C934    5E              pop esi
75C2C935    33C0            xor eax,eax
75C2C937    5B              pop ebx
75C2C938    8BE5            mov esp,ebp
75C2C93A    5D              pop ebp
75C2C93B    C3              retn

75C448E4    33C0            xor eax,eax
75C448E6  ^ E9 31D2FEFF     jmp USER32.75C31B1C
75C31B1C    6A 00           push 0
75C31B1E    6A 00           push 0
75C31B20    FF75 18         push dword ptr ss:[ebp+18]           ; 0
75C31B23    FF75 14         push dword ptr ss:[ebp+14]           ; msvcrt.qsort
75C31B26    57              push edi                             ; edi等于数组的大小,其实就是第三个参数
75C31B27    FF75 0C         push dword ptr ss:[ebp+C]            ; 数组首地址
75C31B2A    56              push esi                             ; 一段asm代码的首地址
75C31B2B    50              push eax                             ; 0
75C31B2C    E8 03AA0000     call USER32.75C3C534                 ; 跟进这个call
75C31B31    5F              pop edi
75C31B32    5E              pop esi
75C31B33    5D              pop ebp
75C31B34    C2 1800         retn 18

75C3C534    6A 3C           push 3C
75C3C536    68 08C6C375     push USER32.75C3C608
75C3C53B    E8 E0FEFFFF     call USER32.75C3C420                 ; 不明白是做什么
75C3C540    33DB            xor ebx,ebx
75C3C542    895D E4         mov dword ptr ss:[ebp-1C],ebx
75C3C545    64:A1 18000000  mov eax,dword ptr fs:[18]
75C3C54B    8B80 08070000   mov eax,dword ptr ds:[eax+708]
75C3C551    3BC3            cmp eax,ebx
75C3C553    74 0C           je short USER32.75C3C561             ; 没跳
75C3C555    F600 04         test byte ptr ds:[eax],4
75C3C558    C745 E0 0100000>mov dword ptr ss:[ebp-20],1
75C3C55F    75 03           jnz short USER32.75C3C564            ; 没跳
75C3C561    895D E0         mov dword ptr ss:[ebp-20],ebx
75C3C564    C745 B4 2400000>mov dword ptr ss:[ebp-4C],24
75C3C56B    C745 B8 0100000>mov dword ptr ss:[ebp-48],1
75C3C572    6A 07           push 7
75C3C574    59              pop ecx
75C3C575    33C0            xor eax,eax
75C3C577    8D7D BC         lea edi,dword ptr ss:[ebp-44]
75C3C57A    F3:AB           rep stos dword ptr es:[edi]
75C3C57C    895D DC         mov dword ptr ss:[ebp-24],ebx
75C3C57F    395D E0         cmp dword ptr ss:[ebp-20],ebx
75C3C582    75 14           jnz short USER32.75C3C598            ; 没跳
75C3C584    8B55 08         mov edx,dword ptr ss:[ebp+8]
75C3C587    8D4D B4         lea ecx,dword ptr ss:[ebp-4C]
75C3C58A    FF15 0811C275   call dword ptr ds:[<&ntdll.RtlActiva>; ntdll.RtlActivateActivationContextUnsafeFast
75C3C590    E8 F4FEFFFF     call USER32.75C3C489
75C3C595    8945 DC         mov dword ptr ss:[ebp-24],eax
75C3C598    895D FC         mov dword ptr ss:[ebp-4],ebx
75C3C59B    395D DC         cmp dword ptr ss:[ebp-24],ebx
75C3C59E  ^ 0F84 FE1DFFFF   je USER32.75C2E3A2                   ; 没跳
75C3C5A4    395D 24         cmp dword ptr ss:[ebp+24],ebx
75C3C5A7  ^ 0F84 F51DFFFF   je USER32.75C2E3A2                   ; 直接跳

75C2E3A2    8B75 14         mov esi,dword ptr ss:[ebp+14]
75C2E3A5    E9 19E20000     jmp USER32.75C3C5C3

75C3C534    6A 3C           push 3C
75C3C536    68 08C6C375     push USER32.75C3C608
75C3C53B    E8 E0FEFFFF     call USER32.75C3C420                 ; 不明白是做什么
75C3C540    33DB            xor ebx,ebx
75C3C542    895D E4         mov dword ptr ss:[ebp-1C],ebx
75C3C545    64:A1 18000000  mov eax,dword ptr fs:[18]
75C3C54B    8B80 08070000   mov eax,dword ptr ds:[eax+708]
75C3C551    3BC3            cmp eax,ebx
75C3C553    74 0C           je short USER32.75C3C561             ; 没跳
75C3C555    F600 04         test byte ptr ds:[eax],4
75C3C558    C745 E0 0100000>mov dword ptr ss:[ebp-20],1
75C3C55F    75 03           jnz short USER32.75C3C564            ; 没跳
75C3C561    895D E0         mov dword ptr ss:[ebp-20],ebx
75C3C564    C745 B4 2400000>mov dword ptr ss:[ebp-4C],24
75C3C56B    C745 B8 0100000>mov dword ptr ss:[ebp-48],1
75C3C572    6A 07           push 7
75C3C574    59              pop ecx
75C3C575    33C0            xor eax,eax
75C3C577    8D7D BC         lea edi,dword ptr ss:[ebp-44]
75C3C57A    F3:AB           rep stos dword ptr es:[edi]
75C3C57C    895D DC         mov dword ptr ss:[ebp-24],ebx
75C3C57F    395D E0         cmp dword ptr ss:[ebp-20],ebx
75C3C582    75 14           jnz short USER32.75C3C598            ; 没跳
75C3C584    8B55 08         mov edx,dword ptr ss:[ebp+8]
75C3C587    8D4D B4         lea ecx,dword ptr ss:[ebp-4C]
75C3C58A    FF15 0811C275   call dword ptr ds:[<&ntdll.RtlActiva>; ntdll.RtlActivateActivationContextUnsafeFast
75C3C590    E8 F4FEFFFF     call USER32.75C3C489
75C3C595    8945 DC         mov dword ptr ss:[ebp-24],eax
75C3C598    895D FC         mov dword ptr ss:[ebp-4],ebx
75C3C59B    395D DC         cmp dword ptr ss:[ebp-24],ebx
75C3C59E  ^ 0F84 FE1DFFFF   je USER32.75C2E3A2                   ; 没跳
75C3C5A4    395D 24         cmp dword ptr ss:[ebp+24],ebx
75C3C5A7  ^ 0F84 F51DFFFF   je USER32.75C2E3A2                   ; 直接跳
75C3C5AD    68 B097C875     push USER32.75C897B0                 ; UNICODE "锭痈e"
75C3C5B2    8B75 14         mov esi,dword ptr ss:[ebp+14]
75C3C5B5    56              push esi
75C3C5B6    E8 8C000000     call USER32.75C3C647
75C3C5BB    85C0            test eax,eax
75C3C5BD  ^ 0F85 9B99FFFF   jnz USER32.75C35F5E
75C3C5C3    8B4D 0C         mov ecx,dword ptr ss:[ebp+C]         ; 一段asm代码的首地址
75C3C5C6    B8 000000C0     mov eax,C0000000
75C3C5CB    23C8            and ecx,eax
75C3C5CD    3BC8            cmp ecx,eax
75C3C5CF    0F84 45DE0100   je USER32.75C5A41A                   ; 没跳
75C3C5D5    FF75 1C         push dword ptr ss:[ebp+1C]           ; 第五个参数
75C3C5D8    FF75 18         push dword ptr ss:[ebp+18]           ; msvcrt.qsort,其实就是第四个参数
75C3C5DB    56              push esi                             ; edi等于数组的大小,其实就是第三个参数
75C3C5DC    FF75 10         push dword ptr ss:[ebp+10]           ; 数组的首地址
75C3C5DF    FF75 0C         push dword ptr ss:[ebp+C]            ; 一段asm代码的首地址
75C3C5E2    E8 DDFEFFFF     call USER32.75C3C4C4                 ; 跟进去这段代码
75C3C5E7    8945 E4         mov dword ptr ss:[ebp-1C],eax
75C3C5EA    C745 FC FEFFFFF>mov dword ptr ss:[ebp-4],-2
75C3C5F1    E8 33000000     call USER32.75C3C629
75C3C5F6    8B45 E4         mov eax,dword ptr ss:[ebp-1C]
75C3C5F9    E8 72FEFFFF     call USER32.75C3C470
75C3C5FE    C2 2000         retn 20

75C3C4C4    55              push ebp
75C3C4C5    8BEC            mov ebp,esp
75C3C4C7    56              push esi                             ; 数组的大小
75C3C4C8    57              push edi
75C3C4C9    53              push ebx                             ; 0
75C3C4CA    68 CDABBADC     push DCBAABCD                        ; 固定的一个数值
75C3C4CF    56              push esi                             ; 数组的大小
75C3C4D0    FF75 18         push dword ptr ss:[ebp+18]           ; 0
75C3C4D3    FF75 14         push dword ptr ss:[ebp+14]           ; msvcrt.qsort,其实就是第四个参数
75C3C4D6    FF75 10         push dword ptr ss:[ebp+10]           ; 数组的大小
75C3C4D9    FF75 0C         push dword ptr ss:[ebp+C]            ; 数组的首地址
75C3C4DC    64:800D CA0F000>or byte ptr fs:[FCA],1
75C3C4E4    FF55 08         call dword ptr ss:[ebp+8]            ; 这里是call asm里面的代码,跟进去

/*****************************************************************/
/**********************这里就是asm的一段代码**********************/
002FE470    89E0            mov eax,esp
002FE472    E8 00000000     call 002FE477                        ; 不是很明白这段代码的作用,好像是得到当前的esp
002FE477    830424 15       add dword ptr ss:[esp],15            ; 这里[esp]=2FE48C,就是asm里面的下一个call
                                                                 ; 其实就是修改当前指令的地址,相当于第四个参数
002FE47B    6A 04           push 4                               ; 这里应该是字长
002FE47D    FF70 08         push dword ptr ds:[eax+8]            ; 数组的大小
002FE480    FF70 04         push dword ptr ds:[eax+4]            ; 数组的首地址
002FE483    FF50 0C         call dword ptr ds:[eax+C]            ; 这里调用msvcrt.qsort,我们跟进去
002FE486    83C4 10         add esp,10
002FE489    C2 1000         retn 10
002FE48C    6A 00           push 0
002FE48E    89E0            mov eax,esp
002FE490    8B15 38E32F00   mov edx,dword ptr ds:[2FE338]
002FE496    50              push eax
002FE497    FF35 3CE32F00   push dword ptr ds:[2FE33C]
002FE49D    8B48 0C         mov ecx,dword ptr ds:[eax+C]
002FE4A0    8B40 08         mov eax,dword ptr ds:[eax+8]
002FE4A3    FF31            push dword ptr ds:[ecx]
002FE4A5    FF30            push dword ptr ds:[eax]
002FE4A7    8B0A            mov ecx,dword ptr ds:[edx]
002FE4A9    52              push edx
002FE4AA    FF51 1C         call dword ptr ds:[ecx+1C]      ; 这里调用004016F0,作用不明
002FE4AD    58              pop eax
002FE4AE    C3              retn
/*****************************************************************/

我们跟进msvcrt.qsort:

7611D3E6 >  8BFF            mov edi,edi
7611D3E8    55              push ebp
7611D3E9    8BEC            mov ebp,esp
7611D3EB    81EC 00010000   sub esp,100
7611D3F1    53              push ebx
7611D3F2    8B5D 08         mov ebx,dword ptr ss:[ebp+8]                    ; 数组的首地址
7611D3F5    56              push esi
7611D3F6    8B75 0C         mov esi,dword ptr ss:[ebp+C]                    ; 数组的大小
7611D3F9    85DB            test ebx,ebx                                    ; 数组的首地址
7611D3FB    0F84 26100100   je msvcrt.7612E427
7611D401    57              push edi
7611D402    8B7D 10         mov edi,dword ptr ss:[ebp+10]                   ; 这里应该是字长
7611D405    85FF            test edi,edi
7611D407    0F86 30AB0300   jbe msvcrt.76157F3D
7611D40D    837D 14 00      cmp dword ptr ss:[ebp+14],0                     ; 检测msvcrt.qsort的第四个参数是否为0
7611D411    0F84 26AB0300   je msvcrt.76157F3D
7611D417    83FE 02         cmp esi,2                                       ; 数组的大小是否小于2
7611D41A    72 5A           jb short msvcrt.7611D476
7611D41C    4E              dec esi                                         ; 从数组后面往前取数组的数值
7611D41D    0FAFF7          imul esi,edi
7611D420    03F3            add esi,ebx
7611D422    C745 F4 0000000>mov dword ptr ss:[ebp-C],0
7611D429    895D FC         mov dword ptr ss:[ebp-4],ebx
7611D42C    8975 F8         mov dword ptr ss:[ebp-8],esi
7611D42F    8BC6            mov eax,esi
7611D431    2BC3            sub eax,ebx
7611D433    33D2            xor edx,edx
7611D435    F7F7            div edi
7611D437    40              inc eax
7611D438    83F8 08         cmp eax,8
7611D43B    0F87 B8000000   ja msvcrt.7611D4F9
7611D441    8B45 14         mov eax,dword ptr ss:[ebp+14]                   ; 这里调用asm里面的第二个call
7611D444    50              push eax
7611D445    57              push edi
7611D446    53              push ebx
7611D447    8BC6            mov eax,esi
7611D449    E8 34000000     call msvcrt.7611D482
7611D44E    83C4 0C         add esp,0C
7611D451    8B45 F4         mov eax,dword ptr ss:[ebp-C]
7611D454    83E8 01         sub eax,1
7611D457    8945 F4         mov dword ptr ss:[ebp-C],eax
7611D45A    78 1A           js short msvcrt.7611D476
7611D45C    8B9485 78FFFFFF mov edx,dword ptr ss:[ebp+eax*4-88]
7611D463    8B8485 00FFFFFF mov eax,dword ptr ss:[ebp+eax*4-100]
7611D46A    8955 FC         mov dword ptr ss:[ebp-4],edx
7611D46D    8945 F8         mov dword ptr ss:[ebp-8],eax
7611D470    8BDA            mov ebx,edx
7611D472    8BF0            mov esi,eax
7611D474  ^ EB B9           jmp short msvcrt.7611D42F
7611D476    5F              pop edi
7611D477    5E              pop esi
7611D478    5B              pop ebx
7611D479    8BE5            mov esp,ebp
7611D47B    5D              pop ebp
7611D47C    C3              retn

由于call进msvcrt.qsort后要频繁调用asm里的第二个函数,而第二个函数又调用vb程序里的004016F0
所以一定程度上会影响msvcrt.qsort函数的效率。还有就是CallWindowProc这个函数真的很麻烦












点评

我用的VB汇编shl是修改VTable实现的,效率还好吧,一般般  发表于 2012-10-8 23:02
如果是我写ASM,我要么做人工优化,要么写一堆花指令  发表于 2012-10-8 13:33
我经常写不规范的asm,竟然被你发现了  发表于 2012-10-7 14:47
我一般都是吧ASM写到函数里面,或者给自身挂HOOK实现跳转  发表于 2012-10-7 14:33
所以想用CallWindowProc实现一个简单的shl,效率会是相当的差!  发表于 2012-10-7 14:11
 楼主| 发表于 2012-10-7 14:07:03 | 显示全部楼层
上面代码中调用004016F0其实就是
Public Function Compare(ByVal Index1 As Long, ByVal Index2 As Long, ByVal nUserData As Long) As Long
    'default implementation (???)
    If Index1 < Index2 Then Compare = -1 Else _
    If Index1 > Index2 Then Compare = 1 Else Compare = 0
End Function

就是
void qsort(void *base,size_t num,size_t width, int (__cdecl *compare )(const void *, const void *) )
的那个比较函数。

真的很折腾,搞了几天才弄明白那段怪怪的asm。

点评

c++里就是这么用的...  发表于 2012-10-8 09:20
你可以自己写一个,呵呵  发表于 2012-10-7 14:46
回复 支持 反对

使用道具 举报

发表于 2012-10-8 22:23:28 | 显示全部楼层
来 尽情的Call 吧。。。
封装到Dll里调用最爽了
  1. Public Function CallFunAddr(ByVal lpAddr As Long) As Long
  2.     '#ASM     mov ecx, DWORD PTR _lpAddr$[esp-4]
  3.     '#ASM     Call ecx
  4.     '#ASM     RET 4
  5.     CallFunAddr = lpAddr
  6. End Function
  7.                                                                     
  8. Public Function CallFunAddr1(ByVal lpAddr As Long, ByVal lParam As Long) As Long
  9.     '#ASM     mov eax, DWORD PTR _lParam$[esp-4]
  10.     '#ASM     mov ecx, DWORD PTR _lpAddr$[esp-4]
  11.     '#ASM     push eax
  12.     '#ASM     Call ecx
  13.     '#ASM     RET 8
  14.     CallFunAddr1 = lpAddr + lParam
  15. End Function
  16.                                                                     
  17. Public Function CallFunAddr2(ByVal lpAddr As Long, ByVal lParam1 As Long, ByVal lParam2 As Long) As Long
  18.     '#ASM     mov eax, DWORD PTR _lParam2$[esp-4]
  19.     '#ASM     mov ecx, DWORD PTR _lParam1$[esp-4]
  20.     '#ASM     mov edx, DWORD PTR _lpAddr$[esp-4]
  21.     '#ASM     push eax
  22.     '#ASM     push ecx
  23.     '#ASM     call   EDX
  24.     '#ASM     RET 12
  25.     CallFunAddr2 = lpAddr + lParam1 + lParam2
  26. End Function
  27.                                                                     
  28. Public Function CallFunAddr3(ByVal lpAddr As Long, ByVal lParam1 As Long, ByVal lParam2 As Long, ByVal lParam3 As Long) As Long
  29.     '#ASM     mov eax, DWORD PTR _lParam3$[esp-4]
  30.     '#ASM     mov ecx, DWORD PTR _lParam2$[esp-4]
  31.     '#ASM     mov edx, DWORD PTR _lParam1$[esp-4]
  32.     '#ASM     push eax
  33.     '#ASM     mov eax, DWORD PTR _lpAddr$[esp]
  34.     '#ASM     push ecx
  35.     '#ASM     push edx
  36.     '#ASM     call eax
  37.     '#ASM     RET 16
  38.     CallFunAddr3 = lpAddr + lParam1 + lParam2 + lParam3
  39. End Function
复制代码

点评

能不能用实例call一下msvcrt.qsort  发表于 2012-10-9 07:30
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-10-9 12:58:56 | 显示全部楼层
本帖最后由 menglv 于 2012-10-9 14:08 编辑

Option Explicit
Private Declare Function GetTickCount Lib "kernel32 " () As Long
Implements ISort2

Private Sub Command1_Click()
    Dim obj As New ISort2
    Dim i As Long
    Dim tt As Long
    Dim a(3000000) As Long
    For i = 0 To 3000000
        a(i) = 10000000 * Rnd()
    Next
    tt = GetTickCount()
    'RadixSort a
    'ShakerSort a
    obj.QuickSort a, 0, 3000000
    'ShellSort2 a, 30
    MsgBox GetTickCount() - tt
End Sub

    s = "89 E0 E8 00 00 00 00 83 04 24 15 6A 04 FF 70 08" + _
    "FF 70 04 FF 50 0C 83 C4 10 C2 10 00 6A 00 89 E0" + _
    "8B 15 ObjPtr 50 FF 35 UserData 8B 48 0C" + _
    "8B 40 08 FF 31 FF 30 8B 0A 52 FF 51 1C 58 C3"


需要耗时2590毫秒!

红色代码就是那个自定义比较函数,我们改变一下这个比较函数。
int Comp(const void* p1,const void* p2)
{
    if (*(int *)p1==*(int *)p2)
    return 0;
    if (*(int *)p1>*(int *)p2)
    return 1;
    else
    return -1;
}
函数的反汇编代码为:
002FE8E4    55                                   push    ebp
002FE8E5    89E5                               mov     ebp, esp
002FE8E7    83EC 04                          sub     esp, 4
002FE8EA    8B45 08                          mov     eax, dword ptr [ebp+8]
002FE8ED    8B55 0C                         mov     edx, dword ptr [ebp+C]
002FE8F0    8B00                               mov     eax, dword ptr [eax]
002FE8F2    3B02                               cmp     eax, dword ptr [edx]
002FE8F4    75 09                              jnz     short 002FE8FF
002FE8F6    C745 FC 0000000>        mov     dword ptr [ebp-4], 0
002FE8FD    EB 1C                             jmp     short 002FE91B
002FE8FF    8B45 08                          mov     eax, dword ptr [ebp+8]
002FE902    8B55 0C                         mov     edx, dword ptr [ebp+C]
002FE905    8B00                              mov     eax, dword ptr [eax]
002FE907    3B02                              cmp     eax, dword ptr [edx]
002FE909    7E 09                             jle     short 002FE914
002FE90B    C745 FC 0100000>       mov     dword ptr [ebp-4], 1
002FE912    EB 07                             jmp     short 002FE91B
002FE914    C745 FC FFFFFFF>         mov     dword ptr [ebp-4], -1
002FE91B    8B45 FC                         mov     eax, dword ptr [ebp-4]
002FE91E    C9                                  leave
002FE91F    C3                                  retn
函数反汇编后的hex为:
    "55 89 E5 83 EC 04 8B 45 08 8B 55 0C 8B 00 3B 02 75 09 C7 45 FC 00 00 00 00 EB 1C 8B 45 08 8B 55 " + _
    "0C 8B 00 3B 02 7E 09 C7 45 FC 01 00 00 00 EB 07 C7 45 FC FF FF FF FF 8B 45 FC C9 C3"
将反汇编的代码替换为:
    s = "89 E0 E8 00 00 00 00 83 04 24 15 6A 04 FF 70 08 " + _
    "FF 70 04 FF 50 0C 83 C4 10 C2 10 00" + _
    "55 89 E5 83 EC 04 8B 45 08 8B 55 0C 8B 00 3B 02 75 09 C7 45 FC 00 00 00 00 EB 1C 8B 45 08 8B 55 " + _
    "0C 8B 00 3B 02 7E 09 C7 45 FC 01 00 00 00 EB 07 C7 45 FC FF FF FF FF 8B 45 FC C9 C3"


需要耗时765毫秒!

其实还有更简单的代码:
int Comp(const void* p1,const void* p2)
{
    return (*(int *)p1-*(int *)p2);
}
函数的反汇编代码为:
002FE8E4    55                  push    ebp
002FE8E5    89E5              mov     ebp, esp
002FE8E7    8B4D 08        mov     ecx, dword ptr [ebp+8]
002FE8EA    8B45 0C        mov     eax, dword ptr [ebp+C]
002FE8ED    8B10              mov     edx, dword ptr [eax]
002FE8EF    8B01               mov     eax, dword ptr [ecx]
002FE8F1    29D0              sub     eax, edx
002FE8F3    5D                  pop     ebp
002FE8F4    C3                  retn
函数反汇编后的hex为:
    "55 89 E5 8B 4D 08 8B 45 0C 8B 10 8B 01 29 D0 5D C3"
将反汇编的代码替换为:
    s = "89 E0 E8 00 00 00 00 83 04 24 15 6A 04 FF 70 08 " + _
    "FF 70 04 FF 50 0C 83 C4 10 C2 10 00" + _
    "55 89 E5 8B 4D 08 8B 45 0C 8B 10 8B 01 29 D0 5D C3"
需要耗时593毫秒!

继续精简一下上面的代码:
002FE8E4    8B4C24 04       mov     ecx, dword ptr [esp+4]
002FE8E8    8B4424 08       mov     eax, dword ptr [esp+8]
002FE8EC    8B10                mov     edx, dword ptr [eax]
002FE8EE    8B01                mov     eax, dword ptr [ecx]
002FE8F0    29D0                sub     eax, edx
002FE8F2    C3                    retn
将反汇编的代码替换为:
    s = "89 E0 E8 00 00 00 00 83 04 24 15 6A 04 FF 70 08 " + _
    "FF 70 04 FF 50 0C 83 C4 10 C2 10 00" + _
    "8B 4C 24 04 8B 44 24 08 8B 10 8B 01 29 D0 C3"
需要耗时562毫秒!

这个应该是msvcrt.dll@qsort函数的极限结果吧,C语言的里的速度也应该跟这个差不多。

以上结果是在cpu E5700  3.00GHz,4G内存测试的结果。

点评

果然厉害,比msdn的qsort使用例子中的都精简。msdn上调用了stricmp int compare( const void *arg1, const void *arg2 ) { return _stricmp( * ( char** ) arg1, * ( char** ) arg2 ); }  发表于 2015-5-24 10:33
Implements这个还真不懂!我只知道你那个函数比C里的函数要慢很多!  发表于 2012-10-28 15:41
看来你还是没搞懂Implements的高级之处,如果我有两个不同类型的数组要排序,先排第一个,再排第二个,用Implements就会方便很多  发表于 2012-10-28 15:29
那个函数还是你的那个函数,只不过是用c写后再反汇编优化的结果。要写其它比较函数也可以。  发表于 2012-10-28 15:06
原来你把比较函数写死了  发表于 2012-10-28 13:49
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-10-28 10:41:10 | 显示全部楼层
我花几天研究出来的东西,好像没人懂得去欣赏。
心都凉,早知道这样就不发出来了。
独自去偷欢!

点评

你不@我们,怎么知道你发了东西呢?  发表于 2012-10-28 13:49
回复 支持 反对

使用道具 举报

发表于 2015-5-19 17:31:11 | 显示全部楼层
本帖最后由 loquat 于 2015-5-20 13:16 编辑

你修改的代码是这样吗?去掉那些复杂的参数的,对嘛
  1. Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  2. Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
  3. Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Long) As Long
  4. Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Long, ByVal lpProcName As String) As Long

  5. Private m_bCode(255) As Byte, m_hMod As Long, m_lpFunc As Long

  6. Friend Sub QuickSort(idxArray() As Long, ByVal nStart As Long, ByVal nEnd As Long)
  7. If nEnd - nStart <= 1 Then Exit Sub
  8. If m_lpFunc Then
  9.     CallWindowProc VarPtr(m_bCode(0)), VarPtr(idxArray(nStart)), nEnd - nStart + 1, m_lpFunc, 0
  10.     Exit Sub
  11. End If
  12. End Sub

  13. Private Sub Class_Initialize()
  14. Dim s As String, m As Long, i As Long
  15. m_hMod = LoadLibrary("msvcrt.dll")
  16. m_lpFunc = GetProcAddress(m_hMod, "qsort")
  17. s = "89E0E800000000830424156A04FF7008" + _
  18.     "FF7004FF500C83C410C21000" + _
  19.     "8B4C24048B4424088B108B0129D0C3"
  20. m = Len(s) \ 2
  21. For i = 0 To m - 1
  22.     m_bCode(i) = Val("&H" + Mid(s, i + i + 1, 2))
  23. Next i
  24. End Sub

  25. Private Sub Class_Terminate()
  26. FreeLibrary m_hMod
  27. End Sub
复制代码
回复 支持 反对

使用道具 举报

发表于 2015-5-20 13:16:50 | 显示全部楼层
menglv 发表于 2012-10-28 10:41
我花几天研究出来的东西,好像没人懂得去欣赏。
心都凉,早知道这样就不发出来了。
独自去偷欢!

中间那个for循环应该还可以优化下吧

点评

那个只在程序初始化的时候才调用一次哎  发表于 2015-5-24 11:47
回复 支持 反对

使用道具 举报

发表于 2015-5-20 19:17:35 | 显示全部楼层
本帖最后由 loquat 于 2015-5-20 19:19 编辑

将Val改成CLng还可以提升一点点。。。
  1. Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  2. Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
  3. Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Long) As Long
  4. Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Long, ByVal lpProcName As String) As Long

  5. Private m_bCode(42) As Byte, m_hMod As Long, m_lpFunc As Long

  6. Friend Sub QuickSort(idxArray() As Long, ByVal nStart As Long, ByVal nEnd As Long)
  7. If nEnd - nStart <= 1 Then Exit Sub
  8. If m_lpFunc Then
  9.     CallWindowProc VarPtr(m_bCode(0)), VarPtr(idxArray(nStart)), nEnd - nStart + 1, m_lpFunc, 0
  10.     Exit Sub
  11. End If
  12. End Sub

  13. Private Sub Class_Initialize()
  14. Dim s As String, m As Long, i As Long
  15. m_hMod = LoadLibrary("msvcrt.dll")
  16. m_lpFunc = GetProcAddress(m_hMod, "qsort")
  17. s = "89E0E800000000830424156A04FF7008" + _
  18.     "FF7004FF500C83C410C21000" + _
  19.     "8B4C24048B4424088B108B0129D0C3"
  20. m = Len(s) \ 2
  21. For i = 0 To m - 1
  22.     m_bCode(i) = CLng("&H" + Mid(s, i + i + 1, 2))
  23. Next i
  24. End Sub

  25. Private Sub Class_Terminate()
  26. FreeLibrary m_hMod
  27. End Sub
复制代码
回复 支持 反对

使用道具 举报

发表于 2015-5-24 11:51:31 | 显示全部楼层
@acme_pjz
qort和qsort_s有什么区别

点评

qsort_s没有意义(一般来说_s的函数都是没有意义的逗比),不要用就对了,而且msvcrt里面没有  发表于 2015-5-24 12:01
回复 支持 反对

使用道具 举报

发表于 2015-5-24 20:37:54 | 显示全部楼层
@acme_pjz

qsort和qsort_s
https://msdn.microsoft.com/en-us/library/zes7xw0h.aspx
https://msdn.microsoft.com/en-us/library/4xc60xas.aspx

我没有测试过,但是MSDN上的确有这个函数。。。

点评

那是新版msvcrXX.dll里面的函数  发表于 2015-5-25 13:16
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

文字版|手机版|小黑屋|VBGood  

GMT+8, 2022-8-11 07:48

VB爱好者乐园(VBGood)
快速回复 返回顶部 返回列表