好友
阅读权限40
听众
最后登录1970-1-1
|
本帖最后由 bester 于 2009-3-31 01:32 编辑
2、数据的存储空间 ------ 变量
估计大家都知道,我们程序访问的数据一般的都是存放在内存或者寄存器中。自然的,如上次课所讲的那些数据也都是存放在内存中的,那我们在程序中,如何使用这些内存空间呢?这就有了“变量”的概念。
我们在这里引用一下上一篇文字的图片:
这个图片不陌生吧~~~~
这里的00438400就是一个变量~,如果以一个字节的方式来读的话,它是一个BYTE类型的变量,它的内容是0xA1,00438401的内容就是0xA5,如果以WORD类型来读的话,00438400的内容是0xA5A1,如果以DWORD类型来读的话,00438400的内容是0x0000A5A1,想必经过上次的学习,我们已经能够理解这些小概念了!
那变量的含义也就很清楚了,变量就是内存地址。学过编程的可能觉得不理解,编程高手可能就笑我不求甚解了,所以,如果我有什么理解不对的,不深刻的,还请各位大牛指教!
稍微熟悉点程序的人,应该知道,我们的程序被分成了代码段,数据段,资源段,堆栈段等等……
上面我们说到过 变量就是地址,那反过来说,地址就是变量,似乎也是成立的!
比如: 我们的程序代码是写在内存里的,也就是说,我们的代码也可以当作变量来使用!
想想我们写程序,不就是用代码通过变量来操作数据吗?我们写的程序本身就是在内存里放着的,代码的每个字节都有一个虚拟地址与它对应,也就是说,我们的代码本身就是一些数据。
从这里来看,似乎高手们讲的什么钩子,代码自变形,甚至我们的代码是可以放在数据区执行的等等技术,似乎也不是什么谣不可及的……
想必,大家对普通的变量应该有一定的认识了,这里呢,我就给出变量在C语言中的声明和表示方法!
再C语言中,我们的变量声明格式是:
数据类型
变量名;
或者
数据类型
变量名 = 常量;
在C语言中,常见的数据类型有 int、float/double、char;
整型中又分成了,long、short等,多了我不介绍,大家自己百度一下吧~
上文中的常量就是一个具体的数值!
例如: int x = 2; // 我们定义了一个变量x它的内容是2
如果我们要定义一个连续的字符串,
比如:
char
addrName[] = “52pojie.cn\0”;
这样我们就定义了一个数组,addrName[0]中的内容就是‘5’,addrName[1]中的内容就是‘2’,addrName[6]中的内容就是’e’了,依次类推!
这个字符串它在内存中的样子大概如下:
也就是说,我们的addrName[0]就是内存中的地址0x00438AC0,addrName[1]就是内存中的地址0x00438AC1;
这里需要说明的一点,就是,所有的变量名,函数名,对象名等等,都是它所代表的内存地址的首地址!也就是说:
addrName == addrName[0] == 0x00438AC0;
好了,由于我还没有能力写基础教程,所以,这里对C变量相关的基础就说到这里,再次回到我们的主题:变量就是地址!
如果我们有一个需求,就是将我们上面声明的这个字符串变量输出出来,那我们的程序需要怎么写呢?
// test.cpp : Defines the entry point for the application.
//
#include "stdio.h"
#include <windows.h>
char
addrName[] = "52pojie.cn\0";
char
*szTitle
= "Null\0";
// Foward declarations of functions included in this code module:
int main()
{
MessageBoxA(NULL, addrName , szTitle, MB_OK);
return 0;
}
像我们搞破解的,一定不会对这个MessageBoxA函数陌生吧~~,它反汇编的样子大概是:
相关内存的帖图:
大家自己根据我提供的截图,算一下上面push后面的地址的内容想必就应该很清楚的发现,我们在程序中使用的变量就是直接使用的地址,比如:
00401008
|.
68 30604000
push
00406030
; |Text = "52pojie.cn"
这里的00406030 就是字符串52pojie.cn的首个地址,那EAX中的是什么内容啊?应该也是地址吧~~~?
我们看一下0x0040603C中的内容,也就是EAX的内容:0x00406040,再看一下0x00406040中的内容,很容易的发现,原来是“Null”,奇特吧~~~
这个就是我们C语言中说到的指针的概念,很多没有好好学C语言的朋友可能都迷糊指针的概念,我们通过这个例子就应该可以很容易的明白,指针就是变量的地址或者直接说指针就是地址的地址!
指针在C语言中的表示就是*,在汇编语言中的表示就是[],至于为什么要有指针,指针到底有什么作用,在写程序的过程中,指针的功能到底应该怎么使用,我会在以后的指针的课题中详细介绍!
这次的内容基本就到这里了,为了开阔大家的视野,不局限与传统的思路里,我给出一个把函数当作数组使用的一个例子:打印99乘法表,虽然没有什么技术含量,但是希望能给大家一个提示,起到开阔视野的作用!
#include "stdio.h"
#include "windows.h"
typedef unsigned char BYTE;
typedef VOID (CALLBACK *MYSPRINTF)(char
*, const
char
*,);
typedef VOID (CALLBACK *MYLSTRCAT)(char
*, char
*);
typedef VOID (CALLBACK *MYMSGBOX)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
MYSPRINTF mySprintf = (MYSPRINTF)GetProcAddress(LoadLibraryA("msvcr71.dll"), "sprintf");
MYLSTRCAT myStrCat = (MYLSTRCAT)GetProcAddress(LoadLibraryA("KERNEL32.dll"), "lstrcatA");
MYMSGBOX myMsgBox = (MYMSGBOX)GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");
BYTE buf[] = {
0xB8,0x00,0x12,0x00,0x00,0xE8,0xAE,0x00,0x00,0x00,0x55,0x56,0x57,0xB9,0x7F,0x00,\
0x00,0x00,0x33,0xC0,0x8D,0x7C,0x24,0x0D,0xC6,0x44,0x24,0x0C,0x00,0xC6,0x84,0x24,\
0x0C,0x02,0x00,0x00,0x00,0xF3,0xAB,0x66,0xAB,0xAA,0xB9,0xFF,0x03,0x00,0x00,0x33,\
0xC0,0x8D,0xBC,0x24,0x0D,0x02,0x00,0x00,0xBE,0x01,0x00,0x00,0x00,0xF3,0xAB,0x66,\
0xAB,0xAA,0xBF,0x01,0x00,0x00,0x00,0x3B,0xF7,0x7C,0x33,0x8B,0xEE,0xA1,0x18,0x61,\
0x40,0x00,0x55,0x57,0x56,0x8D,0x4C,0x24,0x18,0x50,0x51,0xFF,0x15,0x20,0x86,0x40,\
0x00,0x83,0xC4,0x14,0x8D,0x54,0x24,0x0C,0x8D,0x84,0x24,0x0C,0x02,0x00,0x00,0x52,\
0x50,0xFF,0x15,0x28,0x86,0x40,0x00,0x47,0x03,0xEE,0x3B,0xFE,0x7E,0xCF,0x8D,0x8C,\
0x24,0x0C,0x02,0x00,0x00,0x68,0x24,0x61,0x40,0x00,0x51,0xFF,0x15,0x28,0x86,0x40,\
0x00,0x46,0x83,0xFE,0x0A,0x7C,0xAB,0x6A,0x00,0x8D,0x94,0x24,0x10,0x02,0x00,0x00,\
0x68,0x28,0x61,0x40,0x00,0x52,0x6A,0x00,0xFF,0x15,0x24,0x86,0x40,0x00,0x5F,0x5E,\
0x5D,0x81,0xC4,0x00,0x12,0x00,0x00,0xC3\
};
BYTE AllocBuf[] = { 0x51,0x3D,0x00,0x10,0x00,0x00,0x8D,0x4C,0x24,0x08,\
0x72,0x14,0x81,0xE9,0x00,0x10,0x00,0x00,0x2D,0x00,\
0x10,0x00,0x00,0x85,0x01,0x3D,0x00,0x10,0x00,0x00,\
0x73,0xEC,0x2B,0xC8,0x8B,0xC4,0x85,0x01,0x8B,0xE1,\
0x8B,0x08,0x8B,0x40,0x04,0x50,0xC3\
};
const
char
*pConChar =
"%d*%d=%-4d\0";
const
char
*pTitle =
"九九乘法表\0";
char
*pNchar =
"\n";
void main()
{
long* pVoid = (long
*)buf;
__asm
{
CALL pVoid;
}
}
帖一下效果图吧:
|
免费评分
-
查看全部评分
|