您的位置:首页 > 职场人生

SDK程序员经常写出的一段低效率代码[代码优化][原]

2007-06-07 01:23 459 查看
SDK程序员经常写出的一段低效率代码[代码优化][原]

由于新版本的 MafaLSHelper v1.0 Standard 在编写当中需要涉及到一些更加复杂的操作,将导致以前用MASM32所编写的Utils.dll函数库供不应求,所以目前需要新增一批函数!如下列表:

------------------------------------------------------------------------------------------------------
1) MStrFindA(ANSI)、MStrFindW(UNICODE);攻能:查找字符串,并返回结果串,失败为0。
2) MStrCmpA(ANSI)、MStrCmpW(UNICODE);攻能:比较字符串,和strcmp一样。
3) MStrCmpiA(ANSI)、MStrCmpiW(UNICODE);攻能:比较字符串,和strcmpi一样。
4) MStrNCmpA(ANSI)、MStrNCmpW(UNICODE);攻能:比较指定的N个字符串,和strcmpN一样。
5) MGetAbsolutePathA(ANSI)、MGetAbsolutePathW(UNICODE);攻能:从相对路径中获取绝对路径。
6) MGetRelativePathA(ANSI)、MGetRelativePathW(UNICODE);攻能:从绝对路径获取相对路径。
------------------------------------------------------------------------------------------------------

第一个函数即刻可从MStrRepA/W简化过来的。但是,众所周知社会在发展,人也一样,所以编程思想也在不断地进步,显然,代码质量也就相应的有所提高了…… 所以不是再那么简单地从MStrRepA/W简化过来了,事情变的更加地复杂,我不得不重新大规模地修改至少80%处左右的代码……
因此,为了能在编写的过程中可以更加快速的查看寄存器的变化,于是我在DLL内新增加了一个能显示当前寄存器的MessageBox。该函数前提地需要不能影响当前的所有寄存器及标志寄存器内的值。代码如下:
-----------------------------------------------------------------------------
MASM32 code:
MsgInfo PROC C pszFormat:DWORD, args:VARARG
LOCAL szBuffer[6400]:BYTE
PUSHAD
PUSHFD

LEA EAX, szBuffer
MOV BYTE PTR [EAX], 00H

LEA EAX, pszFormat
ADD EAX, 4

INVOKE wvsprintf, ADDR szBuffer, pszFormat, EAX
INVOKE MessageBox, 0, /
ADDR szBuffer, /
ctext("Test"), /
MB_OK OR MB_ICONINFORMATION
POPFD
POPAD

RET
MsgInfo ENDP

为了更大程度的优化代码,于是,我便用OllyDbg进行了如下反汇编DLL,结果MsgInfo函数出来的代码如下:

OllyDbg Code:
10001000 55 push ebp
10001001 8BEC mov ebp, esp ; 上面那条和这条可用这一条代替:enter
10001003 81C4 00E7FFFF add esp, -1900
10001009 60 pushad
1000100A 9C pushfd
1000100B 8D85 00E7FFFF lea eax, dword ptr ss:[ebp-1900]
10001011 C600 00 mov byte ptr ds:[eax], 0
10001014 8D45 08 lea eax, dword ptr ss:[ebp+8]
10001017 83C0 04 add eax, 4
1000101A 50 push eax
1000101B FF75 08 push dword ptr ss:[ebp+8]
1000101E 8D85 00E7FFFF lea eax, dword ptr ss:[ebp-1900]
10001024 50 push eax
10001025 E8 960F0000 call <jmp.&user32.wvsprintfA>
1000102A 6A 40 push 40
1000102C 68 10200010 push Utils.10002010 ; ASCII "Test"
10001031 8D85 00E7FFFF lea eax, dword ptr ss:[ebp-1900]
10001037 50 push eax
10001038 6A 00 push 0
1000103A E8 7B0F0000 call <jmp.&user32.MessageBoxA>
1000103F 9D popfd
10001040 61 popad
10001041 C9 leave ; 代替这两条指令:mov esp, ebp和pop ebp
10001042 C3 retn

大家可以看出,MASM32写的代码,几乎和反汇编出来的结果一样!很惊奇吧?J
-----------------------------------------------------------------------------

说了那么多的废话,几乎都完全脱离主题了……汗一个先,不过总得让大家知道,我是因为什么才会拿出牛刀OllyDbg来调试我的C程序的……

现在我们来看一段SDK的代码:

///////////////////////////////////////////////////////////////////////////////////////////

//; MStrFindA MASM32 原型
//MStrFindA proto pszExpression:DWORD, pszFind:DWORD, nStart:DWORD, nCount:DWORD

// C声明原型
EXPORT LPSTR MStrFindA( LPSTR pszExpression, LPCSTR pszFind, int nStart, int nCount );

#ifndef _UNICODE
#define MStrFindEx MStrFindA
#else
#define MStrFindEx MStrFindW
#endif

#define MStrFind(pszExpression,pszFind) /
MStrFindEx(pszExpression,pszFind,-1,-1);

///////////////////////////////////////////////////////////////////////////////////////////

int main(int argc, char** argv)
{
TCHAR szDst[260] = TEXT("abcdef");
TCHAR szFind[260] = TEXT("f");
PTSTR pFound = NULL;

pFound = MStrFind( szDst, szFind );

_tprintf( TEXT("result of found:[%s]/n"), pFound );

return 0;
}

现在再来看看main函数的反汇编结果:

; 当前进程栈向下伸长208H个字节:260D + 260D = 520D
00401000 /$ >sub esp, 208

; 获取堆中的常量串: TEXT("abcdef")
00401006 |. >mov eax, dword ptr ds:[40704C] ; 61 62 63 64 ----> abcd
0040100B |. >mov cx, word ptr ds:[407050] ; 65 66 ----> ef
00401012 |. >mov dl, byte ptr ds:[407052] ; 00 ----> /0

;备份edi
00401018 |. >push edi

; 完成 TCHAR szDst[260] = TEXT("abcdef"); 的赋值...
00401019 |. >mov dword ptr ss:[esp+4], eax ; 填入 abcd 到第一个局部变量 szDst [第1~4字节]
0040101D |. >mov word ptr ss:[esp+8], cx ; 填入 ef 到第一个局部变量 szDst [第5~6字节]
00401022 |. >mov ecx, 3F ; 252/4=63
00401027 |. >xor eax, eax ; 清零
00401029 |. >lea edi, dword ptr ss:[esp+B] ; 串:abcdef/0 之后的地址. szDst [第8字节]
0040102D |. >mov byte ptr ss:[esp+A], dl ; 置 /0 给 szDst [第7字节]
00401031 |. >rep stosd ; 4*63=252, szDst[260]剩下的253的4字节对齐252字节进行清零
00401033 |. >stosb ; 最后一个字节253的清零

; 获取堆中的常量串:TEXT("f")
00401034 |. >mov ax, word ptr ds:[407048] ; 66 00 ----> f/0

; 1、完成 TCHAR szFind[260] = TEXT("f"); 的赋值;2、完成MStrFindA函数的参数压栈。
0040103A |. >mov ecx, 40 ; 256/4=64
0040103F |. >mov word ptr ss:[esp+108], ax ; 填入 f/0 到第二个局部变量 szFind [第1~2字节]
00401047 |. >xor eax, eax ; 清零
00401049 |. >lea edi, dword ptr ss:[esp+10A] ; 串:f/0之后的地址. szDst [第3字节]
00401050 |. >push -1 ; MStrFindA参数4:int count =-1;
00401052 |. >rep stosd ; 4*64=256, szFind[260]剩下的258的4字节对齐256字节进行清零
00401054 |. >lea ecx, dword ptr ss:[esp+10C] ; szFind[0]
0040105B |. >push -1 ; MStrFindA参数3:int start=-1;
0040105D |. >lea edx, dword ptr ss:[esp+C] ; szDst[0]
00401061 |. >push ecx ; MStrFindA参数2:PCSTR pszFind
00401062 |. >push edx ; MStrFindA参数1:PCSTR pszExpression
00401063 |. >stosw ; szFind最后一个WORD的清零

00401065 |. >call <jmp.&Utils.MStrFindA> ; CALL MStrFindA函数

; 调用_tprintf显示结果
0040106A |. >push eax ; 查看返回值
0040106B |. >push test.00407030 ; result of found:[%s]/n
00401070 |. >call test.00401096 ; _tprintf
00401075 |. >add esp, 8 ; 恢复_tprintf的参数栈

; 确定return 0的0值
00401078 |. >xor eax, eax ; return 0;

; 恢复 edi
0040107A |. >pop edi

; 恢复局部变量占用栈
0040107B |. >add esp, 208

00401081 /. >retn

///////////////////////////////////////////////////////////////////////////////////////////

经过上面的反汇编结果,我想SDK程序员应该都非常地清楚的在定义一个序列串时,如果初始化一个值给它,会有怎么样的结果!
汗不汗你?应该是满头了吧?这样还好点,最恐怖的就是出现如下面这样的代码:

TCHAR szFind[260] = TEXT("/0");

strcpy( szFind, TEXT("abc") );

我可以很直接地告诉你,第一条声明和赋值语句,会和上面反汇编的代码一样地处理(虽然它仅仅就是一个NULL),然后再进行CALL strcpy进行拷贝abc/0,怎么样?冒冷汗了吧你?所以大家以后写代码千万要小心了!在定义一个局部串时,如果真想要给他一个NULL,可以这样用:

TCHAR szFind[260];
*szFind = TEXT('/0');

你应该也猜到了吧,这行代码将转换成如下形式:
mov byte ptr ss:[esp+N个偏移], 0

嘿嘿!不会再那么傻呼呼地原原版版地进行260个字节逐个进行一一地串门了吧。

By dreamerate at home written in 2007-6-7 01:13
dreamerate@gmail.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: