kaelkeymac可以玩dota2吗用dota2吗

如果您有什么建议或想投稿,请联系 QQ:
分类 [ 学习编程 ] 下的全部文章 ▼
VS终结者原理简要说明:
VS检测作弊肯定不会放在主线程,既然是另开线程,那就好办的多,用procexp等工具查看一下VS的线程信息(用HideToolz隐藏,不然会被关闭),通过观察找到入手点,找到线程启动地址以后,分析就好办的多了...
Sleep掉VS反作弊模块的线程,在线程中间函数(VS 3.12 地址:0x& VS3.0 地址:0x)处HOOK,判断传入地址,如果为检测反作弊的函数地址则 while(1) Sleep(10000);,作用一看就明白了,线程不能retn ,不然VS会退出...
至于哪些函数是检测作弊的,这个也容易找到,搜索字符串&作弊&,搜索ReadProcessMemory,还有因为通过线程中间函数启动的只有12个线程,先HOOK一下,得到这12个函数入口地址,缩小范围在这12个函数里面找...
还有说明一下:有一个线程不能简单Sleep,不然启动魔兽1分钟左右就会掉线,所以只能在这个函数中nop掉调用检测函数的代码...
=======================================================================
上面7个函数Sleep掉
入口地址为0404B3D的函数,在处NOP五个字节
=======================================================================
上面7个函数Sleep掉
入口地址为00404B5B的函数,在出NOP五个字节
=======================================================================
把原理交待了我就可以安心潜水了,上面虽然是简要说明,但是只要是研究过VS反作弊的朋友一眼就能看懂,只要VS小规模更新,稍微改下代码就行了...
只是希望继续破解之路的朋友能免费下去,也不多说了,每个人的出发点不一样毕竟...
顺便说一下,我喜欢用OD直接在内存上写汇编代码(OD的汇编功能非常强大),写好后再拷贝出16进制数值,用程序WriteProcessMemory写进去,这样方便感觉很舒服...&&顺便贴一下我写的汇编代码,很简单的几行...
以VS3.12为例:
& /.& 55&&&&&&&&&&&&& push&&& ebp
& |.& 8BEC&&&&&&& mov&&&&& ebp, esp
& |.& 51&&&&&&&&&&&&& push&&& ecx
& |.& 51&&&&&&&&&&&&& push&&& ecx
& |.& 6A 08&&&&&&&&push&&& 8&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ; /n = 8
& |.& 8D45 F8&&&lea&&&&& &eax, dword ptr [ebp-8]&&&&&; |
入口处JMP走&&改为:
& ^\E9 B3FCFFFF&&&& jmp&&&&
&&& 6A 08&&&&&&&&&& push&&& 8
&&& CC&&&&&&&&&&&&& int3
&&& CC&&&&&&&&&&&&& int3
&&& 8B5C24 04&&&&&& mov&&&& ebx, dword ptr [esp+4]
0045F2FC&&& 8B03&&&&&&&&&&& mov&&&& eax, dword ptr [ebx]
0045F2FE&&& 3D 9D134000&&&& cmp&&&& eax, 0040139D&&&;比较函数地址& 是 就 JMP到Sleep处&&
&&& 74 34&&&&&&&&&& je&&&&& short &&&&&&&&&&&&&&&&&&&
&&& 3D DB164000&&&& cmp&&&& eax, 004016DB
0045F30A&&& 74 2D&&&&&&&&&& je&&&&& short
0045F30C&&& 3D F8304000&&&& cmp&&&& eax,
&&& 74 26&&&&&&&&&& je&&&&& short
&&& 3D &&&& cmp&&&& eax,
&&& 74 1F&&&&&&&&&& je&&&&& short
0045F31A&&& 3D C3474000&&&& cmp&&&& eax,
0045F31F&&& 74 18&&&&&&&&&& je&&&&& short
&&& 3D C2394000&&&& cmp&&&& eax,
&&& 74 11&&&&&&&&&& je&&&&& short
&&& 3D A2314000&&&& cmp&&&& eax,
0045F32D&&& 74 0A&&&&&&&&&& je&&&&& short
0045F32F&&& 55&&&&&&&&&&&&& push&&& ebp
&&& 8BEC&&&&&&&&&&& mov&&&& ebp, esp
&&& 51&&&&&&&&&&&&& push&&& ecx
&&& 51&&&&&&&&&&&&& push&&& ecx
&&& E9 0C030000&&&& jmp&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&& ;JMP 回& push 8 处
&&& 68 &&&& push&&& 2710&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&& ;Sleep
0045F33E&&& FF15 606E5600&& call&&& dword ptr [566E60]&&&&&&&&&&&&; kernel32.Sleep
& ^ EB F3&&&&&&&&&& jmp&&&& short &&&&&&&&&&&&&&&&&&&&&&&& ;JMP 到Sleep&
关于aobscan的实现原理我发现这里好多人用的语言都不一样,所以我尽量就不针对某种语言来讲了。(我写的C代码)首先,获得进程PID。可以根据标题获得,也可以根据进程名获得。各有各的好处吧。还有窗口类名哈。例如:
HWND hwnd = FindWindow("MainWindow", NULL);
GetWindowThreadProcessId(hwnd, &dwPid);
//return dwP
}第二步,获得进程相关信息,例如内存大小。
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
PROCESS_MEMORY_COUNTERS
pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS);
::GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc));
//printf("%d\n%d\n",dwPid,pmc.WorkingSetSize/);第三步,遍历程序内存。因为上一步已经获得内存大小了,所以一个循环。(获得内存数据之前,是否检查一下内存属性呢?我觉得应该需要,但是我这里只讲讲原理,就省掉了)另外据说Windows一个内存页就是4kb,所以写成这样:
char key[] = {0x80, 0x7f, 0x49, 0x00};//查找的数据以及长度
int len = 4;
PBYTE pAddress = NULL;
int i = 0;
int n = 0;
for (; i < pmc.WorkingSetS i += 4096)
BYTE arBytes[4096];
if (!::ReadProcessMemory(hProcess, (LPVOID)i, arBytes, 4096, NULL))
if (memstr(key, len, (char*)arBytes, 4096) != 0)
printf("%d
%d\n", memstr(key, len, (char*)arBytes, 4096), arBytes);
n = memstr(key, len, (char*)arBytes, 4096) - (unsigned char*)arB
printf("%x
%d", i, n);现在i变量中的地址,就是我们查找的数据的地址了。附带一个最简单的menstr函数,几乎没有优化哈。unsigned char *memstr(char * dst , int dst_len, char *src , int src_len ){
char *cp =
if (src_len < dst_len)
return NULL;
for (i = 0; i <= src_len - dst_ i++)
if (memcmp(cp , dst , dst_len) == 0)
return (unsigned char *)
C++实现的完整aobscan,速度很快,貌似有点Bug,需要修正。完整的aobscan实现,我在搜索部分使用了一个高速搜索算法。#include #include #include #include /*这是一个很低效的算法*/unsigned char *memstr(char * dst , int dst_len, char *src , int src_len ){
char *cp =
if (src_len < dst_len)
return NULL;
for (i = 0; i <= src_len - dst_ i++)
if (memcmp(cp , dst , dst_len) == 0)
return (unsigned char *)
NULL;}/*sunday算法*/#define MAX_CHAR_SIZE 257long *setCharStep(const unsigned char *subStr, long subStrLen){
static long charStep[MAX_CHAR_SIZE];
for (i = 0; i < MAX_CHAR_SIZE; i++)
charStep[i] = subStrLen + 1;
for (i = 0; i < subStrL i++)
charStep[(unsigned char)subStr[i]] = subStrLen -
return charS}/*
算法核心思想,从左向右匹配,遇到不匹配的看大串中匹配范围之外的右侧第一个字符在小串中的最右位置
根据事先计算好的移动步长移动大串指针,直到匹配*/long sundaySearch(const unsigned char *mainStr, const unsigned char *subStr, long *charStep, long mainStrLen, int subStrLen){
long main_i = 0;
long sub_j = 0;
while (main_i < mainStrLen)
//保存大串每次开始匹配的起始位置,便于移动指针
long tem = main_i;
while (sub_j < subStrLen)
if (mainStr[main_i] == subStr[sub_j])
//如果匹配范围外已经找不到右侧第一个字符,则匹配失败
if (tem + subStrLen > mainStrLen)
return -1;
//否则 移动步长 重新匹配
unsigned char firstRightChar = mainStr[tem + subStrLen];
main_i += charStep[(unsigned char)firstRightChar];
sub_j = 0;
//退出本次失败匹配 重新一轮匹配
if (sub_j == subStrLen)
return main_i - subStrL
return -1;}unsigned char getHex(unsigned char hex){
if (hex >= '0' &#038;& hex <= '9') return hex - '0';
if (hex >= 'A' &#038;& hex <= 'F') return hex - 'A' + 10;
if (hex >= 'a' &#038;& hex <= 'f') return hex - 'a' + 10;
return 0;}int GetHexValue(char *src){
static char temp[1024];
for (i = 0, j = 0; src[i] != 0; i++)
if ((src[i] = 'A') || (src[i] = 'a') || (src[i] = '0'))
if (src[i] != ' ')
temp[j++] = src[i];
temp[j] = 0;
src[0] = 0;
for (i = 0, j = 0, flag = 1; temp[i] != 0; i++)
char ch = getHex(temp[i]);
if (ch != -1)
if (flag == 1) src[j] = ch << 4;
else src[j++] +=
flag *= -1;
src[j] = 0;}DWORD ReadPage(HANDLE m_hProcess, DWORD dwBaseAddr, char* Value){
//读取1页内存
BYTE arBytes[4096];
if (!::ReadProcessMemory(m_hProcess, (LPVOID)dwBaseAddr, arBytes, 4096, NULL))
//此页不可读
return (DWORD) - 1;
//unsigned char key[] = {0x80, 0x7f, 0x49, 0x00};
unsigned char Value2[1024];
strcpy((char*)Value2, Value);
int len = GetHexValue((char*)Value2);
//getchar();
//注释这两行是低效的算法
//char key[] = {0x80, 0x7f, 0x49, 0x00};
//int len = 4;
//if (memstr(key, len, (char*)arBytes, 4096) != 0) return memstr(key, len, (char*)arBytes, 4096) - (unsigned char*)arB
//else return -1;
//开始sunday算法
long *charStep = setCharStep(Value2, len);
return sundaySearch(arBytes, Value2, charStep, 4096, len);
return (DWORD) - 1;
//不会执行到此处}DWORD aobscan(DWORD dwPid, char* Value){
if (dwPid == 0) return (DWORD) - 1;
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (hProcess != NULL)
//获得内存大小
PROCESS_MEMORY_COUNTERS
pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS);
::GetProcessMemoryInfo( hProcess, &#038;pmc, sizeof(pmc));
//遍历内存
for (int i = 0; i < pmc.WorkingSetS i += 4096)
DWORD dwValue = ReadPage(hProcess, i, Value);
if (dwValue != -1)
printf("Found:0x%X\n", i + dwValue);
return i + dwV
::CloseHandle(hProcess);
printf("Nothing Found!\n");
return (DWORD) - 1;}DWORD GetGameID(){
HWND hwnd = FindWindow("MainWindow", NULL);
GetWindowThreadProcessId(hwnd, &#038;dwPid);
return dwP
return 0;}int main(){
double begin = clock();
aobscan(GetGameID(), "807f49 00");
printf("time:%.0fms", clock() - begin);
getchar();}
VB实现CE的AobScan功能,仿CE字节组内存搜索.'这里的东西写模块里面,具体怎么写,我不告诉你
Private&Declare&Function&GetWindowThreadProcessId&Lib&"user32"&(ByVal&hwnd&As&Long,&lpdwProcessId&As&Long)&As&Long
Private&Declare&Function&FindWindow&Lib&"user32"&Alias&"FindWindowA"&(ByVal&lpClassName&As&String,&ByVal&lpWindowName&As&String)&As&Long
Public&Declare&Function&OpenProcess&Lib&"kernel32"&(ByVal&dwDesiredAccess&As&Long,&ByVal&bInheritHandle&As&Long,&ByVal&dwProcessId&As&Long)&As&Long
Private&Declare&Function&GetProcessMemoryInfo&Lib&"PSAPI.DLL"&(ByVal&hProcess&As&Long,&ppsmemCounters&As&PROCESS_MEMORY_COUNTERS,&ByVal&cb&As&Long)&As&Long
Public&Declare&Function&CloseHandle&Lib&"kernel32"&(ByVal&hObject&As&Long)&As&Long
Public&Declare&Function&VirtualQueryEx&Lib&"kernel32"&(ByVal&hProcess&As&Long,&ByVal&lpAddress&As&Long,&lpBuffer&As&MEMORY_BASIC_INFORMATION,&ByVal&dwLength&As&Long)&As&Long
Public&Declare&Function&ReadProcessMemory&Lib&"kernel32"&(ByVal&hProcess&As&Long,&ByVal&lpBaseAddress&As&Any,&lpBuffer&As&Any,&ByVal&nSize&As&Long,&lpNumberOfBytesWritten&As&Long)&As&Long
Public&Type&MEMORY_BASIC_INFORMATION
BaseAddress&As&Long
AllocationBase&As&Long
AllocationProtect&As&Long
RegionSize&As&Long
State&As&Long
Protect&As&Long
lType&As&Long
Type&PROCESS_MEMORY_COUNTERS
cb&As&Long
PageFaultCount&As&Long
PeakWorkingSetSize&As&Long
WorkingSetSize&As&Long
QuotaPeakPagedPoolUsage&As&Long
QuotaPagedPoolUsage&As&Long
QuotaPeakNonPagedPoolUsage&As&Long
QuotaNonPagedPoolUsage&As&Long
PagefileUsage&As&Long
PeakPagefileUsage&As&Long
Public&Function&GetPid(lpClassName&As&String,&lpWindowName&As&String)&As&Long
GetWindowThreadProcessId&FindWindow(lpClassName,&lpWindowName),&GetPid
End&Function
Public&Function&GetMemoryByPID(ByVal&Pid&As&Integer)&As&String
Dim&tPMC&As&PROCESS_MEMORY_COUNTERS
Dim&lProcessID
Dim&hProcess
lProcessID&=&Pid
hProcess&=&OpenProcess(&#038;H1F0FFF,&False,&lProcessID)
If&(GetProcessMemoryInfo(hProcess,&tPMC,&Len(tPMC))&&&&0)&Then
GetMemoryByPID&=&Hex(tPMC.WorkingSetSize)
CloseHandle&hProcess
End&Function'程序窗体定义一个局部变量
Dim&GamePid&As&String
Dim&Rst(2000000)&As&Long
Private&Sub&Form_Load()
GamePid&=&GetPid(vbNullString,&"程序名写到这里,你知道的!")
'把字节数组转换的函数
Function&Fz(Str&As&String)&As&String
Dim&a&As&String
a&=&Replace(Str,&"&",&"")
Dim&i&As&Integer
Dim&b&As&String
For&i&=&Len(a)&To&2&Step&-2
b&=&b&&&Mid(a,&i&-&1,&2)
End&FunctionFunction&AobScan(Pid&As&String,&ZJSZ&As&String)&As&String
ReDim&da(1023)&As&Byte
Dim&z&As&Long
Dim&zr&As&Long
Dim&Srge&As&Long
Dim&hpid&As&Long
Dim&Minf&As&MEMORY_BASIC_INFORMATION
Dim&Mbsize&As&Long
Dim&Dda(100)&As&Byte
Dim&Zfr&As&Long
Dim&Zed&As&Long
Dim&Siz&As&Integer
Dim&Csiz&As&Integer
Dim&Shsiz&As&Integer
Dim&Mlng&As&Long
Mbsize&=&Len(Minf)
Zed&=&CLng("&#038;H"&&&GetMemoryByPID(GamePid))
LRsc&=&Rsc
mstr&=&Fz(ZJSZ)
'循环看数组的长度,并转换成字节数组
Dim&i&As&Integer
For&i&=&Len(mstr)&To&2&Step&-2
Dda((i&/&2)&-&1)&=&CInt("&#038;h"&&&Mid$(mstr,&Len(mstr)&-&i&+&1,&2))
hpid&=&OpenProcess(&#038;H1F0FFF,&False,&CLng(Pid))
z&=&Zfr&'设置开始内存
Do&While&z&&&Zed&-&1&'判断是否小于结束内存
ret&=&VirtualQueryEx(hpid,&z,&Minf,&Mbsize)&'查询地址空间中内存地址的信息
If&ret&=&0&Then
Srge&=&1023
Srge&=&Minf.RegionSize&-&1
zr&=&Minf.BaseAddress
If&(Minf.Protect&And&4)&And&Minf.State&=&4096&Then
ReDim&da(Srge)&As&Byte
a&=&ReadProcessMemory(hpid,&zr,&da(0),&Srge&+&1,&ByVal&0&#038;)
If&a&&&&0&Then
For&zz&=&0&To&Srge&Step&Shsiz
If&Srge&-&zz&&&Siz&-&1&Then&Exit&For
For&bj&=&0&To&Siz&-&1
If&da(zz&+&bj)&&&&Dda(bj)&Then&Exit&For
If&bj&=&Siz&Then&Rsc&=&Rsc&+&1:&Rst(Rsc)&=&zr&+&zz
z&=&zr&+&Srge&+&1
CloseHandle&(hpid)
AobScan&=&Hex$(Rst(0))
End&Function
Private&Sub&Command3_Click()
&&&&&&MsgBox&AobScan(GamePid,&"1d&8e&25&00&19")
方法一:  最简单的方法,判断当前窗口大小是否跟屏幕分辨率相同,相同则为全屏状态。不过要注意桌面进程 Explorer 的处理方法二:  注册一个Appbar(桌面工具栏)是类似微软视窗系统的任务条的窗口。它紧靠屏幕边缘,典型的桌面工具栏包括快速访问其他应用程序和窗口的按钮。系统会防止其他应用程序使用被appbar占用的区域。在任何时刻桌面都可以同时共存多个appbar。使用的API: SHAppBarMessage (原型如下:)
WINSHELLAPI UINT APIENTRY SHAppBarMessage( DWORD dwMessage, PAPPBARDATA pData);
  这个API可以向系统发送一个appbar message(也就是dwMessage,有很多消息,可以查阅MSDN),然后系统通过pData返回你想知道的信息,这里我们主要用这个API来注册一个新的appbar。这里还需要关注的是APPBARDATA这个结构体。检测全屏的具体实现代码如下:
APPBARDATAmemset(&#038;abd, 0, sizeof(abd));// Specify the structure size and handle to the appbar.abd.cbSize = sizeof(APPBARDATA);abd.hWnd = hwndAccessBabd.uCallbackMessage = MSG_APPBAR_MSGID;!::SHAppBarMessage(ABM_NEW, &#038;abd);
  注意MSG_APPBAR_MSGID这个,这是你自己定义的消息ID,当有全屏创建或者取消的时候,会给句柄为hwndAccessBar的窗口发送消息ID为MSG_APPBAR_MSGID的消息,具体到全屏消息,此时WPARAM为ABN_FULLSCREENAPP,而LPARAM则能够判断当前是有窗口全屏了还是有窗口取消全屏了,(BOOL) lParam为TRUE表示有窗口全屏了,而(BOOL) lParam为FALSE则表示有窗口取消全屏状态了。代码如下:
LRESULT CWinHook::WindowProc(UINT msg, WPARAM wp, LPARAM lp)&& {&&&&if (MSG_APPBAR_MSGID == msg)&&&&{&&&&&&&&switch((UINT)wp)&&&&&&&&{&&&&&&&&case ABN_FULLSCREENAPP:&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (TRUE == (BOOL)lp)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&TRACE(TEXT("一个窗口全屏了\n"));&&&&&&&&&&&&&&&&&&&&KAppBarMsg::m_bFullScreen = TRUE;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&else&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&TRACE(TEXT("一个窗口取消全屏了\n"));&&&&&&&&&&&&&&&&&&&&KAppBarMsg::m_bFullScreen = FALSE;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&default:&&&&&&&&&&&&&&&&&&&&}&&&&}&&&&return CSubclassWnd::WindowProc(msg, wp, lp);}
附注:后来发现vista下面没有XP下灵敏,不知道怎么回事,vista下偶尔会失败,很奇怪。
1.什么是DEPDEP,全称是Data Excution Protection,中名叫数据执行保护,是XP+sp2,Win2K03+sp1中加入的对内存的一种保护,用来防止恶意程序对系统的攻击,如溢出。现在只有两种设置方式:一、是只为系统关键进程和服务提供DEP保护,这也是默认选项。二、是为所有程序和服务提供DEP保护,除去用户手动指定的程序。其设置在"我的电脑"->右键菜单"属性"->"高级"->"性能 - 设置"->"数据执行保护"2.DEP能保护什么?个人认为DEP就是专门为防止溢出设计的,当然这么说是有点狭隘了,毕竟这种机制完善了CPU的内存管理机制。感觉每一个指令执行之前都进行内存页属性的检测有点太费资源了。一句话,DEP可以使指定的内存页不具有可执行属性。这样一来,如果指定栈所在的内存页不可执行,那么,当我们要栈上溢出时,我们的Shellcode将难以被执行。所以,DEP保护的就是内存,保护指定的内存上的代码不能被执行,这样就可以达到反溢出的目的。当然,这是微软的一厢情愿罢了。因为越过这个限制也并不是一件难事。3.可以绕过DEP吗?如果可以,如何绕过呢?答案是肯定的,可以绕过。即使是硬件上的DEP保护也是可以的。有一个API,改变指定内存页的属性的,VirtualProtect(),当然,还有其它的API,如VirtualProtectEx(),ZwProtectVirtulMemory(),不过都是封闭在VirtualProtect()中。所以,我们溢出的时候,把返回地址设计为这个API的地址,再精心构造一个栈为调用这个API的栈,就可以改变当前栈的内存页的属性,使其从"不可执行"变成"可执行".这个过程的示例如下面的一段代码
_test proc ;push 04 ;invoke VirtualProtect,esp,30h,PAGE_EXECUTE_READWRITE,esp ;pop eax mov dword ptr [esp+18h],4 mov eax,esp add eax,18h mov dword ptr [esp+14h],lpOldProtection mov dword ptr [esp+10h],40h;dwNewProtection mov dword ptr [esp+0ch],30h;dwRegionSize mov dword ptr [esp+8],dwStartAddress mov dword ptr [esp],VirtualPfunc addr mov eax,esp add eax,1ch mov dword ptr [esp+4],return address from VirtualProtect mov dword ptr [esp+1ch],h;our shellcode ret_test endp
4.DEP在内核中到底是如何实现的?这个问题我曾经费不了少时间去找答案,从内存操作的API上来看,有标准内存管理API,虚拟内存管理API,堆管理API,内存映射文件API从内存管理的结构上来看,有VAD,有PFN,有PTE,PDE,有段一开始我认为windows可能会在任何一个层面上做文章,可能是VAD,也可能是PFN,也可能是PTE并且我认为VAD的可能性比较大,因为PTE没有相关的bit位表示此页有没有可执行属性。PFN也没有。VAD倒是有相关的位表示页的可执行属性。经过一点点的测试和排除,发现VAD与此并没有关系,用VirtualProtect()改变页的属性时,此页对应的VAD的flag位竟然毫无变化。那么只剩下PFN和PTE了,发现这个API调用前后,PFN的restore pte这个字段有变化,PTE的低双字却没有一点变化,高双字我时候我没有关心,我一直认为高双字是用于寻址4G以外的物理内存地址的。然后我手动把PFN的restore pte改变成上面提到的API改成的值,但是结果却让人失望,我拷入shellcode的页还是不可执行。尽管这时,我还是没有意识到PTE的高双字发生的变化,并为此付出了代价,那就是二夜一天的对VirtualProtect()相关API的反汇编。VirtualProtect()调用了VirtualProtectEx()VirtualProtectEx()调用了ZwProtectVirtualMemory()ZwProtectVirtualMemory()通过sysenter进入内核,EAX中存放的服务号是0x89,对应的服务是NtProtecVirtualMemory()NtProtectVirtualMemory()又调用了MiProtectVirtualMemory()在MiProtectVirtualMemory()内部,计算出要改变其属性的内存页的PTE的地址,新的属性,然后调用MiFlushTbAndCapture()改变PTE的属性,但是我当时也只是看到把PTE的属性从067变成了027,和可执行属性还是没有关系,然后我再深入到MiFlushTbAndCapture()中,发现它主要又是调用KeFlushSingleTb()来改变指定PTE的属性的,深入到KeFlushSingleTb()内部,它主要是调用KeInterlockedSwapPte()来改变指定PTE的属性。而KeInterlockedSwapPte()的内部是比较简单的,来看看它的反汇编代码:
nt!KeInterlockedSwapPte:
esib5c2410
ebx,dword ptr [esp+10h] ;ebx=新的PTE值所在变量的地址b74240c
esi,dword ptr [esp+0Ch] ;esi=PTE地址b4b04
ecx,dword ptr [ebx+4]ecx=新PTE值高双字b1b
ebx,dword ptr [ebx]ebx=新PTE值低双字b5604
edx,dword ptr [esi+4]edx=旧PTE值高双字b06
eax,dword ptr [esi]eax=旧PTE值低双字fc70e
cmpxchg8b qword ptr [esi]
看到关键点了吧,就是一个cmpxch8b指令,这个指令是干什么的呢?执行的操作:edx,eax与DST相比较如果 (edx,eax)=(dst)则 ZF=1,(dst)<-(ecx,ebx)否则 ZF=0,(edx,eax)<-dst很简单,如果新的PTE属性和旧的不等,把PTE属性设置为新的属性。如果相等,则实际上等于不进行操作。从这里我才发现,他把PTE的高双字设置为0了,以前的值是0x.所以,DEP是通过PTE的高双字的最高bit即bit63来实现的,这个位置位了,表示此页不可执行。没有置位,表示此页可以执行。而win2k下面的页目录和页表项只有32个bit,所以不可能提供DEP的这个保护位,因此DEP只有在64bit的PTE上才能实现。而只有cr4的bit5即PAE启用的时候,PTE才为64bit。所以,可以这么说吧,intel的奔腾CPU是早就有PAE属性位的,可以支持64位的页表项,而windows系统只有win2k的某个版本,winxp和win2003的某个server pack版本的内核才支持64的页表项。不管怎样,PTE的第63位控制着页的可执行属性,我后来查了IA,在IA的修正说明中,才提到这一点,并把这个位叫做EXB,却对此位的作用一字为提。但是我们是不能在ring3下操作PTE的,所以,绕过DEP还是得用return-to-lib的经典方式返回到VirtualProtect()来改变当前栈的属性。
Private Sub ZipOrRar()
'将C盘的test文件夹压缩为test.rar文件
Shell App.Path + "\WinRar.exe M C:\test.rar C:\test"End SubPrivate Sub UnZipOrRar()
'将test.rar解压缩在C盘下
Shell App.Path + "\WinRar.exe X C:\test.rar C:\"End Sub
BYTE bVersion = (BYTE)GetVersion(); if (bVersion >= 6) {
printf("主版本号:%X
: 当前系统 >= Vista\n",bVersion); }else{
printf("主版本号:%X
: 当前系统 < Vista\n",bVersion); }
'Return the address of the specified ordinal method on the oCallback object, 1 = last private method, 2 = second last private method, etcPrivate Function zAddressOf(ByVal oCallback As Object, ByVal nOrdinal As Long) As Long
' Note: used both in subclassing and hooking routines
'Value we expect to find pointed at by a vTable method entry
Dim nAddr As Long
'Address of the vTable
'Loop index
'Loop limit
RtlMoveMemory VarPtr(nAddr), ObjPtr(oCallback), <font color="#
'Get the address of the callback object's instance
If Not zProbe(nAddr + &#038;H1C, i, bSub) Then
'Probe for a Class method
If Not zProbe(nAddr + &#038;H6F8, i, bSub) Then
'Probe for a Form method
' \\LaVolpe - Added propertypage offset
If Not zProbe(nAddr + &#038;H710, i, bSub) Then
'Probe for a PropertyPage method
If Not zProbe(nAddr + &#038;H7A4, i, bSub) Then
'Probe for a UserControl method
Exit Function
i = i + <font color="#
'Bump to the next entry
J = i + <font color="#24
'Set a reasonable limit, scan 256 vTable entries
Do While i < J
RtlMoveMemory VarPtr(nAddr), i, <font color="#
'Get the address stored in this vTable entry
If IsBadCodePtr(nAddr) Then
'Is the entry an invalid code address?
RtlMoveMemory VarPtr(zAddressOf), i - (nOrdinal * <font color="#), <font color="#
'Return the specified vTable entry address
'Bad method signature, quit loop
RtlMoveMemory VarPtr(bVal), nAddr, <font color="#
'Get the byte pointed to by the vTable entry
'If the byte doesn't match the expected value...
RtlMoveMemory VarPtr(zAddressOf), i - (nOrdinal * <font color="#), <font color="#
'Return the specified vTable entry address
'Bad method signature, quit loop
i = i + <font color="#
'Next vTable entry
LoopEnd Function'Probe at the specified start address for a method signaturePrivate Function zProbe(ByVal nStart As Long, ByRef nMethod As Long, ByRef bSub As Byte) As Boolean
Dim nLimit
Dim nEntry
nAddr = nStart
'Start address
nLimit = nAddr + <font color="#
'Probe eight entries
Do While nAddr < nLimit
'While we've not reached our probe depth
RtlMoveMemory VarPtr(nEntry), nAddr, <font color="#
'Get the vTable entry
<font color="# Then
'If not an implemented interface
RtlMoveMemory VarPtr(bVal), nEntry, <font color="#
'Get the value pointed at by the vTable entry
If bVal = </font
>&#038;H33 Or bVal = &#038;HE9 Then
'Check for a native or pcode method signature
nMethod = nAddr
'Store the vTable entry
bSub = bVal
'Store the found method signature
zProbe = True
'Indicate success
nAddr = nAddr + <font color="#
'Next vTable entry
LoopEnd Function
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As LongPrivate Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As LongPrivate Const SYNCHRONIZE = &#038;H100000Private Const STANDARD_RIGHTS_REQUIRED = &#038;HF0000Private Const PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &#038;HFFF)Private Declare Function NtSuspendProcess Lib "ntdll.dll" (ByVal hProc As Long) As LongPrivate Declare Function NtResumeProcess Lib "ntdll.dll" (ByVal hProc As Long) As LongPrivate Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As LongPrivate hProcess As LongPrivate Sub cmdSuspend_Click()
If IsNumeric(txtPid.Text) Then
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, CLng(txtPid.Text))
If hProcess
<font color="# Then NtSuspendProcess hProcess
CloseHandle hProcessEnd SubPrivate Sub cmdResume_Click()
If IsNumeric(txtPid.Text) Then
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, CLng(txtPid.Text))
If hProcess
<font color="# Then NtResumeProcess hProcess
CloseHandle hProcessEnd SubPrivate Sub cmdTerminate_Click()
If IsNumeric(txtPid.Text) Then
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, CLng(txtPid.Text))
If hProcess
<font color="# Then TerminateProcess hProcess, <font color="#
End IfEnd Sub
THEME DESIGN BY JEZZZZ & MUGEE}

我要回帖

更多关于 mac可以玩dota2吗 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信