‘ VC开发 ’ category archive

自增操作的反汇编分析

85 views 九月 07, 04 by Timothy

在考试或者做题的时候,经常遇到这类问题,出题的老师就是爱在这点上面钻牛脚尖,那就是自增自减操作的组合运算,我个人认为,考这样的题,没多大意思,因为各个编译器不同,出来的结果也不同,而且这样有一种误导,而失去了语言学习的本质,真正的程序员,也不会写出这样的代码,除非有神经病,呵呵。但是我们还是得面对……悲哀啊。下面我用汇编来分析一下这个例子:

#include “stdio.h”
int main()
{
int i=0,n = 0;
n = (++i)+(++i)+(++i);
printf(” n = %d\n”,n);
printf(” i = %d\n”,i);
return 0;
}

我在VC++.NET下编译通过,结果为:n=9,i=3
让我用STUDIO2003.NET的调试器来分析一下:
相关反汇编代码如下:(各语句后面有我的注释)
int i=0,n = 0;
00411A4E mov dword ptr [i],0 ;i初始化为0
00411A55 mov dword ptr [n],0 ;n初始化为0
n = (++i)+(++i)+(++i);
00411A5C mov eax,dword ptr [i] ;eax=0;
00411A5F add eax,1 ;eax=eax+1,所以eax=1
00411A62 mov dword ptr [i],eax ;把1赋值给i
00411A65 mov ecx,dword ptr [i] ;把i装入ecx,此时ecx=1
00411A68 add ecx,1 ;ecx=ecx+1,此时ecx=2
00411A6B mov dword ptr [i],ecx ;把ecx赋值给i,此时i=2
00411A6E mov edx,dword ptr [i] ;把i装入edx,(edx)=2
00411A71 add edx,1 ;edx=edx+1,(edx)=3
00411A74 mov dword ptr [i],edx ;把edx的置放回i,i=3
00411A77 mov eax,dword ptr [i] ;eax=3
00411A7A add eax,dword ptr [i] ;eax=eax+i=3+3=6
00411A7D add eax,dword ptr [i] ;eax=eax+3=6+3=9
00411A80 mov dword ptr [n],eax ;n=(eax)=9
从以上反汇编过程可以看出,n=9,i=3,输出后也如此。输出的汇编代码就不贴了。
不同的编译器输出的结果可能不同,我想,可能反汇编出来的代码也不一样,所以结果自然也不一样了。从这里可以看出,通过反汇编的代码来分析,思路会清晰很多。studio2003.net的编译器,对于(++i)+(++i)+(++i);这种运算,是先算i,也即将三个++i先算出来,结果等于3,然后才算括号外面的加法,结果当然是n=3+3+3=9。

一个有趣的GDI图形测试程序

126 views 九月 07, 04 by Timothy

这是一个有趣的GDI图形测试程序,其主要功能就是获取在桌面上绘图,结果是……你的桌面会一团遭,像病毒一样,看了你会吓一跳,但是有惊无险 :)

一下程序在VC++.NET下编译通过。

#include “stdafx.h”
#include “stdlib.h”

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MessageBox(NULL,”Written by Cooldog. :) ”,”hehe…”,MB_OK);
HDC myDC;
//获取屏幕分辨率
RECT ScrRect;
GetWindowRect(GetDesktopWindow(), &ScrRect);
myDC=GetDC((HWND)0); //获取设备环境
for(long i=0;i<100000L;i++)
{
int x, y, width, height;
x=(rand()%ScrRect.right)/2-(width=rand()%3); //随机产生坐标
y=rand()%ScrRect.bottom-(height=rand()%3);
BitBlt(myDC, x, y, x+width, y+height, myDC, x+rand()%3-1, y-rand()%2, SRCCOPY); //绘图
}
ReleaseDC((HWND)0, myDC);
InvalidateRect(0, NULL, TRUE);
return 0;
}

WINAPI HOOK (修改前五个字节,JMP跳转法)

661 views 九月 07, 04 by Timothy

本文一介绍用修改API头五个字节的方法在Win2k下的使用。利用Win2k为我们提供了一个强大的内存Api操作函数—VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
BOOL VirtualProtectEx(
HANDLE hProcess, // 要修改内存的进程句柄
LPVOID lpAddress, // 要修改内存的起始地址
DWORD dwSize, // 修改内存的字节
DWORD flNewProtect, // 修改后的内存属性
PDWORD lpflOldProtect // 修改前的内存属性的地址
);
BOOL WriteProcessMemory(
HANDLE hProcess, // 要写进程的句柄
LPVOID lpBaseAddress, // 写内存的起始地址
LPVOID lpBuffer, // 写入数据的地址
DWORD nSize, // 要写的字节数
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
);
BOOL ReadProcessMemory(
HANDLE hProcess, // 要读进程的句柄
LPCVOID lpBaseAddress, // 读内存的起始地址
LPVOID lpBuffer, // 读入数据的地址
DWORD nSize, // 要读入的字节数
LPDWORD lpNumberOfBytesRead // 实际读入的子节数
);
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, 因此,必须通过钩子函数和远程注入进程的方法,这样,便能挂接所有进程的API了。现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
其中Dll文件为:
HHOOK g_hHook;
HINSTANCE g_hinstDll;
FARPROC pfMessageBoxA;
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
HMODULE hModule ;
DWORD dwIdOld,dwIdNew;
BOOL bHook=false;
void HookOn();
void HookOff();
BOOL init();
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if(!init())
{
MessageBoxA(NULL,”Init”,”ERROR”,MB_OK);
return(false);
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
if(bHook) UnintallHook();
break;
}
return TRUE;
}
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
{

return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
}
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
{
g_hinstDll=LoadLibrary(“HookApi2.dll”);
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
if (!g_hHook)
{
MessageBoxA(NULL,”SET ERROR”,”ERROR”,MB_OK);
return(false);
}

return(true);
}
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
{

return(UnhookWindowsHookEx(g_hHook));
}

BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
{
hModule=LoadLibrary(“user32.dll”);
pfMessageBoxA=GetProcAddress(hModule,”MessageBoxA”);
if(pfMessageBoxA==NULL)
return false;
_asm
{
lea edi,OldMessageBoxACode
mov esi,pfMessageBoxA
cld
movsd
movsb
}
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
_asm
{
lea eax,MyMessageBoxA
mov ebx,pfMessageBoxA
sub eax,ebx
sub eax,5
mov dword ptr [NewMessageBoxACode+1],eax
}
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
dwIdOld=dwIdNew;
HookOn();//开始拦截
return(true);
}

int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
{
int nReturn=0;
HookOff();
nReturn=MessageBoxA(hWnd,”MessageBox已经被截获,呵呵!”,lpCaption,uType);
HookOn();
return(nReturn);
}
void HookOn()
{
HANDLE hProc;
dwIdOld=dwIdNew;
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
bHook=true;
}
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
{
HANDLE hProc;
dwIdOld=dwIdNew;
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
bHook=false;
}
//测试文件:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{

if(!InstallHook())
{
MessageBoxA(NULL,”Hook Error!”,”Hook”,MB_OK);
return 1;
}
MessageBoxA(NULL,”TEST”,”TEST”,MB_OK);//可以看见TEST变成我们截获后的字符串了。而且是所有进程都被截获。
if(!UninstallHook())
{
MessageBoxA(NULL,”Uninstall Error!”,”Hook”,MB_OK);
return 1;
}
return 0;
}

以上程序在WIN2K,VC7.0下调试并通过

图片:

挂接前,直接调用MessageBox函数,效果如下:

APIHOOK挂接程序界面:

MessageBox被截获后的效果:(在不同进程实现)

在这里,我重新编制了一个简单的程序进行测试,直接调用MessageBox函数,出现以下画面,表明系统所有进程的MessageBox都被挂接成功。

Page: 13 of 13 1 ... 9 10 11 12 13