我用vs写了一段程序,功能是将一段代码拷贝到指定内存区,然后跳到那里去执行。然而,如果那段程序不调api,可以正常跑。我调了一下LoadLibraryA,进入这个api后程序直接奔溃了,我尝试安装SEH异常处理函数来截获异常,奇怪的是竟然毫无反应。程序如下:
////////////////////////////////////////////////////////////////////////////////
//说明:改程序拷贝一段代码到新内存地址,然后跳到那个地址去执行//////////////////
////////////////////////////////////////////////////////////////////////////////
#pragma comment(linker,"/SUBSYSTEM:CONSOLE /ENTRY:entry /BASE:0x00400000")
#include <Windows.h>
#include <stdio.h>
void ShowError();
EXCEPTION_DISPOSITION
__cdecl
_except_handler( struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext )
{
// 指明是我们让流程转到我们的异常处理程序的
MessageBox(0,"发生异常","消息",0);
// 告诉操作系统重新执行出错的指令
return ExceptionContinueExecution;
}
int entry(){
DWORD ProtectOut;
DWORD opstart;//要写入的代码首地址
DWORD oplenth;//要写入的代码的长度
char* str="x.dll";
DWORD baseadr=0x00401500;
HANDLE hProcess=GetCurrentProcess();
//安装SEH
DWORD handler = (DWORD)_except_handler;
__asm
{
// 创建EXCEPTION_REGISTRATION结构:
push handler // handler函数的地址
push FS:[0] // 前一个handler函数的地址
mov FS:[0],ESP // 安装新的EXECEPTION_REGISTRATION结构
}
//设置分页属性使之变为可读写和可执行
if(!VirtualProtectEx(hProcess, (LPVOID)0x00401500, 2,PAGE_EXECUTE_WRITECOPY, &ProtectOut))
{
ShowError();
return FALSE;
}
//写入数据到0x00401500的地方
//第一个双字放LoadLibraryA的地址
DWORD pointer=(DWORD)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
if (!pointer)
{
ShowError();
return FALSE;
}
if(!WriteProcessMemory(hProcess,(void *)baseadr,&pointer,4,NULL))
{
ShowError();
return FALSE;
}
baseadr+=4;
//第二个双字放GetProcAddress的地址
pointer=(DWORD)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "GetProcAddress");
if (!pointer)
{
ShowError();
return FALSE;
}
if(!WriteProcessMemory(hProcess,(void *)baseadr,&pointer,4,NULL))
{
ShowError();
return FALSE;
}
//第三、四个双字放字符串"x.dll"
baseadr+=4;
if(!WriteProcessMemory(hProcess,(void *)baseadr,str,6,NULL))
{
ShowError();
return FALSE;
}
baseadr+=8;
str="start";
//第五、六个双字放字符串"start
if(!WriteProcessMemory(hProcess,(void *)baseadr,str,6,NULL))
{
ShowError();
return FALSE;
}
//然后将一段代码拷贝到0x00401518的内存地址
_asm{
call o
//以下这段代码拷贝到0x00401518的内存地址
pushad
pushf
push 0x00401508
call far ds:[0x00401500]
test eax,eax
jz e
//获取并调用导出函数
push 0x00401510
push eax
call far ds:[0x00401504]
test eax,eax
jz e
call far eax
e:
popf
popad
push 0x00401000
retn
o:
//计算代码长度
call p
p: pop eax
pop ebx
mov opstart,ebx
sub eax,ebx
sub eax,5
mov oplenth,eax
}
baseadr=0x00401518;
if(!WriteProcessMemory(hProcess,(void *)baseadr,(LPVOID)opstart,oplenth,NULL))
{
ShowError();
return FALSE;
}
//跳到0x00401518执行代码
_asm{
push 0x00401518
retn
}
__asm
{
// 移去我们的EXECEPTION_REGISTRATION结构
mov eax,[ESP] // 获取前一个结构
mov FS:[0], EAX // 安装前一个结构
add esp, 8 // 将我们的EXECEPTION_REGISTRATION弹出堆栈
}
end:
system("pause");
return 0;
}
void ShowError()
{
DWORD dwRet = 0;
char *lpMsgBuf = NULL;
DWORD ErrorCode = GetLastError();
dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, ErrorCode, 0x400, (LPTSTR)&lpMsgBuf, 0, NULL);
MessageBox(NULL, lpMsgBuf, NULL, MB_OK | MB_ICONINFORMATION);
LocalFree(lpMsgBuf);
}
求解!!!!!!!
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法