portraiture教程-windows7版本

memcpy
2023年4月4日发(作者:rbcentry dll)

部分C库函数重写以及反汇编分析之memcpy()

为了打牢基本功,重写部分C库函数(参考C库与别⼈的代码,并给出了测试代码),并对部分进⾏反汇编分析(⽤VC⾃带反汇编和

OD)。在写程序过程中,会仔细验证很多以前模棱两可的知识点。

1.

/*从源src所指的内存地址的起始位置开始拷贝n个字节到⽬标dest所指的内存地址的起始位置中

和destin所指内存区域不能重叠,函数返回指向destin的指针。

2.与strcpy相⽐,memcpy并不是遇到'0'就结束,⽽是⼀定会拷贝完n个字节。

和destin都不⼀定是数组,任意的可读写的空间均可

*/

#include"stdafx.h"

#include

voidpmemcpy(void*dest,void*src,intn);

intmain(intargc,char*argv[])

{

//printf("HelloWorld!n");

char*a1="abc0def";

chara2[6];

printf("a1=%s,a2=%sn",a1,a2);

pmemcpy(a2,a1,5);

for(inti=0;i<6;i++)

{

printf("%c",a2[i]);

}

printf("n");

return0;

}

voidpmemcpy(void*dest,void*src,intn)

{

ASSERT((dest!=NULL)&&(src!=NULL));//assert宏的原型定义在中,其作⽤是如果它的条件返回错误,则终⽌程序执⾏

char*tmp_dest=(char*)dest;

char*tmp_src=(char*)src;

while(n--)

{

*tmp_dest=*tmp_src++;

tmp_dest++;

}

}

ps:对于a2[6]的初始化,a2[6]={0},将a2[0]初始化为0后,其余的各位也⾃动补0初始化,⽤printf("%s",a2)打印将不显⽰出。但是很奇

怪printf("%s",a2[0]);打印出来。按理说a2与a2[0]应该是指向同⼀处地址;为什么打印结果不同呢。

反汇编分析:

debug⽅式编译,VC⾃带反汇编⼯具分析:

17:intmain(intargc,char*argv[])

15:{

00401020pushebp//保护启动函数的ebp值,将其⼊栈

00401021movebp,esp//ebp、esp同时指向栈底

00401023subesp,50h//esp-50h,留出main函数栈空间(分配给变量)

00401026pushebx

00401027pushesi

00401028pushedi//将ebx、esi、edi⼊栈

00401029leaedi,[ebp-50h]//通过ebp寻址

0040102Cmovecx,14h//为下⾯初始化刚刚留出的栈空间做准备,ecx作为循环填充的次数,50h/4=14h;

00401031moveax,0CCCCCCCCh//要填充的值

00401036repstosdwordptr[edi]//进⾏填充

char*a1="abc0def";

00401038movdwordptr[ebp-4],offsetstring"abc0def"(00422034)//00422034为“abc0def”字符串的索引地

18:chara2[6];

19:printf("a1=%s,a2=%sn",a1,a2);

0040103Fleaeax,[ebp-0Ch]//通过ebp-0ch索引变量a2,放⼊eax中

00401042pusheax//将变量eax(a2)⼊栈(函数main的栈)(参数⼊栈顺序为从右往左)

00401043movecx,dwordptr[ebp-4]

00401046pushecx//同上将参数a1⼊栈

00401047pushoffsetstring"a1=%s,a2=%sn"(00422024)//通过字符串索引将第⼀个参数⼊栈

0040104Ccallprintf(004011b0)//调⽤函数(跟进函数printf内部)

00401051addesp,0Ch//堆栈平衡原理,调⽤者⾃⼰清理堆栈

20:pmemcpy(a2,a1,5);//⼜是⼀个函数调⽤,不解释,参考上⾯

00401054push5

00401056movedx,dwordptr[ebp-4]

00401059pushedx

0040105Aleaeax,[ebp-0Ch]

0040105Dpusheax

0040105Ecall@ILT+0(pmemcpy)(00401005)

00401063addesp,0Ch

21:for(inti=0;i<6;i++)

00401066movdwordptr[ebp-10h],0//初始化变量i

0040106Djmpmain+58h(00401078)//跳转去00401078地址

0040106Fmovecx,dwordptr[ebp-10h]//将i存到ecx中

00401072addecx,1//i+1

00401075movdwordptr[ebp-10h],ecx//i+1后的值存回变量地址中

00401078cmpdwordptr[ebp-10h],6//将I与6进⾏⽐较

0040107Cjgemain+76h(00401096)//>=则跳

22:{

23:printf("%c",a2[i]);//同上,不解释.....

0040107Emovedx,dwordptr[ebp-10h]

00401081movsxeax,byteptr[ebp+edx-0Ch]

00401086pusheax

00401087pushoffsetstring"%c"(00422020)

0040108Ccallprintf(004011b0)

00401091addesp,8

24:}

00401094jmpmain+4Fh(0040106f)

25:printf("n");

00401096pushoffsetstring"n"(0042201c)

0040109Bcallprintf(004011b0)

004010A0addesp,4

26:return0;

004010A3xoreax,eax

27:}

voidpmemcpy(void*dest,void*src,intn)

30:{

004010F0pushebp

004010F1movebp,esp

004010F3subesp,48h

004010F6pushebx

004010F7pushesi

004010F8pushedi

004010F9leaedi,[ebp-48h]

004010FCmovecx,12h

004010FCmovecx,12h

00401101moveax,0CCCCCCCCh

00401106repstosdwordptr[edi]

31:ASSERT((dest!=NULL)&&(src!=NULL));

00401108cmpdwordptr[ebp+8],0//将第⼆个参数与0进⾏⽐较(仔细想想为什么是bep+8来索引的呢?)

0040110Cjepmemcpy+24h(00401114)//=0,则跳到00401114开始执⾏(其实就是打印⼀条出错信息,并结束程序)

0040110Ecmpdwordptr[ebp+0Ch],0//将第三个参数与0进⾏⽐较

00401112jnepmemcpy+48h(00401138)//!=则跳

00401114push0

00401116push0

00401118movsxeax,wordptr[`pmemcpy'::`2'::__LINE__Var(00424a30)]

0040111Faddeax,1

00401122pusheax

00401123pushoffsetstring"D:cxbfxe2xbaxafxcaxfdxd6xd8xd0xb4xc4xbfxc2xbcmemcpyme

00401128push2

0040112Acall_CrtDbgReport(00401380)

0040112Faddesp,14h

00401132cmpeax,1

00401135jnepmemcpy+48h(00401138)

00401137int3

00401138xorecx,ecx//应该是检验&&

0040113Atestecx,ecx

0040113Cjnepmemcpy+18h(00401108)

32:

33:char*tmp_dest=(char*)dest;

0040113Emovedx,dwordptr[ebp+8]

00401141movdwordptr[ebp-4],edx

34:char*tmp_src=(char*)src;

00401144moveax,dwordptr[ebp+0Ch]

00401147movdwordptr[ebp-8],eax

35:

36:while(n--)

0040114Amovecx,dwordptr[ebp+10h]//变量n存放到ecx

0040114Dmovedx,dwordptr[ebp+10h]//变量n存放到eax

00401150subedx,1//edx-1

00401153movdwordptr[ebp+10h],edx//将n-1存到变量n的地址中

00401156testecx,ecx//检测ecx是否为0(即n是否等于0了)

00401158jepmemcpy+88h(00401178)//n=0,则跳出循环

37:{

38:*tmp_dest=*tmp_src++;

0040115Amoveax,dwordptr[ebp-4]

0040115Dmovecx,dwordptr[ebp-8]

00401160movdl,byteptr[ecx]//将ecx中的值按字节存⼊dl寄存器中(指针取值运算)

00401162movbyteptr[eax],dl

00401164moveax,dwordptr[ebp-8]

00401167addeax,1

0040116Amovdwordptr[ebp-8],eax

39:tmp_dest++;

0040116Dmovecx,dwordptr[ebp-4]

00401170addecx,1

00401173movdwordptr[ebp-4],ecx

40:}

00401176jmppmemcpy+5Ah(0040114a)

41:}

00401178popedi/*以下都为堆栈平衡*/

00401179popesi

0040117Apopebx

0040117Baddesp,48h

0040117Ecmpebp,esp

00401180call__chkesp(00401230)

00401185movesp,ebp

00401187popebp

00401188ret

更多推荐

memcpy