虽然不是什么高深的技术,但最近在搞屏蔽格式化,所以就写出来吧。虽然还有一点没有解决。屏蔽系统的格式化说白的就是钩掉Explorer.exe进程的导入库shell32.dll中的SHFormatDrive函数,但是在winxp sp2中默认对explorer.exe加入了数据执行保护,无奈现在还是没有找到办法。
我的这个向目标进程注入代码的思想就是用了在目标进程启动一个线程,导入自己的DLL执行。但是跟其他的方法还有点不一样的是,在DLL的加载的时候有一个通知事件吧,就在这里执行代码,当然代码在同一个DLL中,也用导出到目标进程了,特点是:小巧,方便,隐蔽。但是有个致命的弱点就是不能跳过winxp的数据执行保护。高手若有什么高招敬请指点。
下面列出主要代码:
主程序
// 枚举进程
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hProcessSnap == INVALID_HANDLE_VALUE){
::MessageBox(NULL,"Found processes failed","notice",MB_OK);
return 0;
}
bRet = Process32First(hProcessSnap,&pe32);
while(bRet){//szProcessName是目标进程的可执行文件名,不加路径
if(strncmp(szProcessName,pe32.szExeFile,(sizeof(szProcessName) >= sizeof(pe32.szExeFile))? sizeof(pe32.szExeFile):sizeof(szProcessName) ) ==0 ){
pid = pe32.th32ProcessID;
hTargetProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE,pid);// 取得指定目标进程句柄
break;
}
bRet = Process32Next(hProcessSnap,&pe32);
}
CloseHandle(hProcessSnap);
if(hTargetProcess !=NULL){
//从本进程的导入表中找LoadLibraryA的地址,目标进程若没有什么特别应该也会在同样的位置
pfnLoadLibraryAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"),"LoadLibraryA");
// 在目标进程中申请一个空间保存注入DLL名称,btDllName就是要加载的自定义dll名称,加路径
btPtr = (char *)VirtualAllocEx(hTargetProcess, NULL, (1 + lstrlenA(btDLLName)) * sizeof(char), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
bRet = WriteProcessMemory(hTargetProcess, btPtr, btDLLName, (1 + lstrlenA(btDLLName)) * sizeof(char), NULL);
hRemoteThread = CreateRemoteThread(hTargetProcess, NULL, 0, pfnLoadLibraryAddr,(PVOID)btPtr, 0, NULL);
if(hRemoteThread != NULL){
MessageBox(NULL,"Inject Dll success","notice",MB_OK);
hRemoteThread = NULL;
}
}
// Inject.cpp : 定义 DLL 应用程序的入口点。 //
#include "stdafx.h"
typedef DWORD (__stdcall *LPFUN)(HWND hwnd, UINT drive, UINT fmtID, UINT option);
//typedef DWORD (*LPFUNINJECT)(VOID);
// mov eax,400000h
// jmp eax
// btNewBytes数组的第1-4位d的双字为400000h
// 用于写入目标函数的内容,后面将会修改跳转地址,指向目标函数的地址
BYTE btNewBytes[8] = {0xB8,0x00,0x00,0x40,0x00,0xFF,0xE0,0x00};
BYTE btOldBytes[8]; // 保存注入前目标函数的开头内容
HMODULE hTargetModule = NULL; // 目标模块句柄
LPFUN lpFun = NULL; // 指向目标函数地址
DWORD __stdcall lpfnHook(HWND hwnd, UINT drive, UINT fmtID, UINT option) {
::MessageBox(NULL,"Format Forbidden!","notice",MB_OK);
// 取消修改
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi;
::VirtualQuery(lpFun, &mbi, sizeof(mbi));
::VirtualProtect(lpFun, 8, PAGE_READWRITE, &dwOldProtect);
::WriteProcessMemory(GetCurrentProcess(), (void*)lpFun, btOldBytes, sizeof(DWORD)*2, NULL);
::VirtualProtect(lpFun, 8, mbi.Protect, 0);
return lpFun(hwnd, drive, fmtID, option);
}
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) {
DWORD dwOldProtect; MEMORY_BASIC_INFORMATION mbi;
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
*(DWORD*)(btNewBytes + 1) = (DWORD)lpfnHook;//将btNewBytes数组的第1-4位转化为双字,存储lpfnHook函数地址
hTargetModule = GetModuleHandle("SHELL32");
while(hTargetModule == NULL){
// 等着模块有效
hTargetModule = GetModuleHandle("SHELL32");
// 还是自己加载
//hTargetModule = ::LoadLibrary("SHELL32.DLL");
}
//if(hTargetModule == NULL){
// lpFun = NULL;
// //::MessageBox(NULL, "Cannot find Shell32.dll", "notice", MB_OK);
// return FALSE;
//}
lpFun = (LPFUN)::GetProcAddress(hTargetModule, "SHFormatDrive");
if(lpFun == NULL){
::FreeLibrary(hTargetModule);
hTargetModule = NULL;
//::MessageBox(NULL, "Cannot find function SHFormatDrive", "notice", MB_OK); // 找不到函数不能加载本模块
return FALSE;
}
::VirtualQuery(lpFun, &mbi, sizeof(mbi));
::VirtualProtect(lpFun, 8, PAGE_EXECUTE_READWRITE, &dwOldProtect);
memcpy(btOldBytes, lpFun, 8);
::WriteProcessMemory(GetCurrentProcess(), (void*)lpFun, btNewBytes, sizeof(DWORD)*2, NULL);
::VirtualProtect(lpFun, 8, mbi.Protect, 0);
//将钩子函数区域改成可以执行可读写
::VirtualQuery((LPVOID)lpfnHook, &mbi, sizeof(mbi));
::VirtualProtect((LPVOID)lpfnHook,(int)((int)DllMain - (int)lpfnHook + 1024), PAGE_EXECUTE_READWRITE, &dwOldProtect);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
lpfnHook函数就是我的新的执行函数,只要执行格式化就会跳转到这里,我在SHFormatDrive函数的开头用新的命令覆盖,这个命令是跳转到我的lpfnHook函数,在lpfnHook中显示一个对话框,告诉不能格式化,我在下面有将SHFormatDrive的开头改回去,也可以就此退出,但注意要继续执行SHFormatDrive操作,必须将SHFormatDrive函数改回去,不然有会跳到lpfnHook中死循环.
在目标进程中若执行格式化函数SHFormatDrive,就会在跳转到我的函数lpfnHook中执行,这里要跟lpfnHook函数的声明要跟SHFormatDrive函数一模一样,就是调用格式也要一样,当初这里费了好大的劲才调试出调用格式不对,引起堆栈不平衡,好在我还学过汇编,不然,估计这篇文章就要夭折了.这里我也没有将lpfnHook函数从DLL中导出,所以检查导入表也看不到有什么新的函数导入.
当然,目标进程还是要导入这个DLL的.我怀疑就是没有将lpfnHook函数导出到目标进程中,所以才会被数据执行保护给闭掉.只是调试动态导入DLL的程序还是不太好调试,反正在VS2003中没有断到lpfnHook函数的入口.不清楚是不是因为不能执行lpfnHook的原因.
关了数据执行保护就可以向explorer.exe中注入代码来屏蔽掉格式化操作对没有被保护的进程可以直接使用.