保护模式:
基于 X86 微处理器 (80836) 处理器有 3 种工作模式:
实模式,保护模式,虚拟 86 模式。
实模式和虚拟 86 模式是为了和 8086 处理器兼容而设置的,而保护模式是 80836 处理器的主要工作模式。
而 windows 操作系统就在此模式之下运行。
虚拟内存:
在保护模式下, 80836 所有 32 根地址线都是可以寻址的,处理器寻址范围是
0x00000000~0xFFFFFFFF(232 ,4GB) 所以 32 位 windows 操作系统可寻址 4GB 的地址空间 .
而机器的 RAM 不可能是 4GB ,主要靠 CPU 支持, CPU 在保护模式下支持虚拟存储,既为虚拟内存 。它可以帮助操作系统将磁盘空间作为内存使用。
在磁盘空进应用这一机制的文件叫做页文件
通常情况下, Windows 将 4G 的前半部分留给进程作为私有存储,而自己使用另一半 2G 来存储操作系统内部使用的数据。
进程的创建
操作系统通过 CreateProcess 函数来创建进程。
STARTUPINFO :
进程创建后,会分配一个此类型的变量。包含父进程传递给子进程的一些信息
PROCESS_INFOMATION :
存储当前进程的信息
创建进程示例:
char szFileName[] = { "D:\\myeclipse6\\workspace \\02Test\\Debug\\02Test.exe " }; STARTUPINFO si = { sizeof (si) }; PROCESS_INFORMATION pi; :: CreateProcessA ( // 创建线程 NULL, // 不指定文件名 szFileName, // 命令行参数 NULL, // 默认进程安全性 NULL, // 默认线程安全性 FALSE, // 不可以被子进程继承 CREATE_NEW_CONSOLE, // 为新进程创建一个新的控制台窗口 NULL, // 使用本进程环境变量 NULL, // 使用本进程驱动器和目录 &si, &pi); |
内存区域操作:
Windows 以 4KB 为单位为应用程序分配内存,其采用分页机制 来管理内存。每页大小是 4KB ,目的是按页来搜索目标内存,可以提高搜索效率 .
练习程序代码:
测试程序 Test.cpp
/*
* test.cpp
*
* Created on: 2009-12-22
* Author: Zhangwenbo
*/
#include <stdio.h>
int g_nNum;
int main(){
int i=198;
g_nNum=1003;
while(1){
printf("i=%d,addr=%08lX;g_nNum=%d,addr=%08lX\n",
++i,&i,--g_nNum,&g_nNum);
}
return 0;
}
内存操作代码:
/*
* Memrepair.cpp
*
* Created on: 2009-12-22
* Author: Zhangwenbo
*/
#include <stdio.h>
#include <windows.h>
BOOL FindFirst(DWORD dwValue); //在目标空间进行第一次查找
BOOL FindNext(DWORD dwValue); //在目标空间进行第二次,三次查找
DWORD g_arList[1024]; //地址列表
int g_nListCnt; //有效地址个数
HANDLE g_hProcess; //目标进程句柄
/**
* 比较内存页中的数据
*/
BOOL CompareAPage(DWORD dwBaseAddr, DWORD dwValue) {
//读取一页内存 4KB为单位
BYTE arBytes[4096];
if (!::ReadProcessMemory(g_hProcess, (LPVOID) dwBaseAddr, arBytes, 4096, NULL)) {
return FALSE;//此页不可读
}
//在这一页内存里面查找
DWORD* pdw;
for (int i = 0; i < (int) 4* 1024 - 3 ; i++) {
pdw = (DWORD*) &arBytes[i];
if (pdw[0] == dwValue) {//等于要查找的值
if (g_nListCnt >= 1024)
return FALSE;
//添加到全局变量中
g_arList[g_nListCnt++] = dwBaseAddr + i;
}
}
return TRUE;
}
/**
* 进行下次查找
*/
BOOL FindNext(DWORD dwValue) {
//保存m_arList数组中有效地址的个数,初始化新的m_nListCnt的值
int nOrgCnt = g_nListCnt;
g_nListCnt = 0;
//从m_arList数组记录的地址处查找
BOOL bRet = FALSE;
DWORD dwReadValue;
for (int i = 0; i < nOrgCnt; i++) {
if (::ReadProcessMemory(g_hProcess, (LPVOID) g_arList[i], &dwReadValue, sizeof(DWORD), NULL)) {
if (dwReadValue == dwValue) {
g_arList[g_nListCnt++] = g_arList[i];
return TRUE;
}
}
}
return bRet;
}
/**
* 第一次在指定空间查找
*/
BOOL FindFirst(DWORD dwValue) {
//1GB
const DWORD dwOneGB = 1024* 1024* 1024 ;
//4KB
const DWORD dwOnePage = 4* 1024 ;
if (g_hProcess == NULL)
return FALSE;
//查看操作系统类型
DWORD dwBase;
OSVERSIONINFO vi = { sizeof(vi) };
::GetVersionExA(&vi);
//确定从哪个地址开始搜索
if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
dwBase = 4* 1024* 1024 ; //WINDOW98系列 4mb
}else {
dwBase=640*1024;//64kb windowsNT系列
}
//在开始地址到2GB的地址空间查找 递增1页大小(4kb)
for(;dwBase<2*dwOneGB;dwBase+=dwOnePage) {
//比较一页大小的内存
CompareAPage(dwBase,dwValue);
}
return TRUE;
}
/**
* 打印列表
*/
void ShowList() {
for (int i = 0; i < g_nListCnt; i++) {
printf("%08lX\n", g_arList[i]);
}
}
/**
* 改写内存值
*/
BOOL WriteMemory(DWORD dwAddr,DWORD dwValue){
return ::WriteProcessMemory(g_hProcess,(LPVOID)dwAddr,&dwValue,sizeof(DWORD),NULL);
}
int main() {
//启动02Test进程
char szFileName[] = {
"D:\\myeclipse6\\workspace\\02Test\\Debug\\02Test.exe" };
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
//创建线程
::CreateProcessA(NULL, szFileName, NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
NULL, NULL, &si, &pi);
//关闭线程句柄,我们不使用此句柄
::CloseHandle(pi.hThread);
//获取目标进程句柄
g_hProcess = pi.hProcess;
//输入要修改的值
int iVal;
printf("输入值:");
scanf("%d", &iVal);
//进行第一次查找
FindFirst(iVal);
//打印出搜查结果
ShowList();
while (g_nListCnt > 1) {
printf("输入值:");
scanf("%d", &iVal);
//进行下次查找
FindNext(iVal);
ShowList();
printf("输入新值:");
scanf("%d", &iVal);
if(WriteMemory(g_arList[0],iVal)){
printf("修改成功!");
}
}
::CloseHandle(g_hProcess);
return 0;
}
DWORD 是什么?
1 个二进制位称为 1 个 bit , ( 1 位)
8 个二进制位称为 1 个 Byte ,( 1 字节)
2 个字节 (2Byte=2*8bit) 就是 1 个 Word ( 1 字, 16 位),
则 DWORD ( DOUBLE WORD )就是双字的意思,两个字( 32 位)