可以生成加载器补丁exe和字节补丁exe,用附加可执行代码等方法可用于一些程序的破解
#ifndef APIMACRO_H
#define APIMACRO_H
////////////////通用控件头文件和链接库////////////
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
//////////////////////////////////////////////////
///////////Sets the dialog box icons//////////////
inline void chSETDLGICONS(HWND hWnd, int idi) {
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)
LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
MAKEINTRESOURCE(idi)));
SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)
LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
MAKEINTRESOURCE(idi)));
}
inline void chMB(PCSTR szMsg) {
char szTitle[MAX_PATH];
GetModuleFileNameA(NULL, szTitle, _countof(szTitle));
MessageBoxA(GetActiveWindow(), szMsg, szTitle, MB_OK);
}
#define chBEGINTHREADEX(psa, cbStackSize, pfnStartAddr, \
pvParam, dwCreateFlags, pdwThreadId) \
((HANDLE)_beginthreadex( \
(void *) (psa), \
(unsigned) (cbStackSize), \
(PTHREAD_START) (pfnStartAddr), \
(void *) (pvParam), \
(unsigned) (dwCreateFlags), \
(unsigned *) (pdwThreadId)))
//通用控件使用前务必InitCommonControls初始化
//List_View 控件宏 行数列数索引均从0开始
static LV_ITEM _stLVI;
static LV_COLUMN _stLVC;
//////////////////////////////////在ListView中新增一行///////////////////////////////////
inline int ListView_AddLine(HWND hwndCtl)
{
RtlZeroMemory (&_stLVI,sizeof(LV_ITEM) );
_stLVI.mask = LVIF_TEXT;
_stLVI.pszText = TEXT("无数据可显示");
_stLVI.iSubItem = 0;
return ListView_InsertItem(hwndCtl, &_stLVI);
}
////////////////////////////////在ListView中增加一个标题列///////////////////////////////////
inline void ListView_InsertCaption(HWND hwndCtl, int iColumn, int iWidth, LPTSTR lpszCaption)
{
RtlZeroMemory (&_stLVC,sizeof(LV_COLUMN) );
_stLVC.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
_stLVC.fmt = LVCFMT_LEFT;
_stLVC.pszText = lpszCaption;
_stLVC.cx = iWidth;
_stLVC.iSubItem = iColumn;
ListView_InsertColumn(hwndCtl, iColumn, &_stLVC);
}
////////////////////////////////在ListView中更改一个标题列///////////////////////////////////
inline void ListView_SetCaption(HWND hwndCtl, int iColumn, LPTSTR lpszCaption)
{
RtlZeroMemory (&_stLVC,sizeof(LV_COLUMN) );
_stLVC.mask = LVCF_TEXT | LVCF_FMT;
_stLVC.fmt = LVCFMT_LEFT;
_stLVC.pszText = lpszCaption;
_stLVC.iSubItem = iColumn;
ListView_SetColumn(hwndCtl, iColumn, &_stLVC);
}
#endif
#ifndef RVATOOFFSET_H
#define RVATOOFFSET_H
#include <windows.h>
//////////////////////////////////////////各种PE中偏移的转换实现//////////////////////////////////////////////
char szNotFound[] = "无法查找";
///////////////////////////////////////将RVA偏移转换成文件偏移,失败返回-1////////////////////////////////////////////////
DWORD RvaToOffset (IMAGE_DOS_HEADER *lpFileHead, DWORD dwRva)
{
::IMAGE_NT_HEADERS *lpPEHead;
::IMAGE_SECTION_HEADER *lpSectionHead;
DWORD i;
lpPEHead = (IMAGE_NT_HEADERS*)( (BYTE*)lpFileHead + lpFileHead->e_lfanew);
i = lpPEHead->FileHeader.NumberOfSections;
lpSectionHead = (IMAGE_SECTION_HEADER*)(++lpPEHead);
for ( ; i > 0 ; i--, lpSectionHead++)
{
if ( (dwRva >= lpSectionHead->VirtualAddress) && (dwRva < (lpSectionHead->VirtualAddress + lpSectionHead->SizeOfRawData) ) )
{
dwRva = dwRva - lpSectionHead->VirtualAddress + lpSectionHead->PointerToRawData;
return dwRva;
}
}
return -1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////将RVA偏移转成文件指针偏移,失败返回-1////////////////////////////////////////////////
DWORD RvaToPointer(IMAGE_DOS_HEADER *lpFileHead,DWORD dwRva)
{
DWORD Offset = RvaToOffset(lpFileHead, dwRva);
if(Offset == -1)
return -1;
return (DWORD)(lpFileHead) + Offset;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////将虚拟地址转成文件指针偏移,失败返回-1////////////////////////////////////////////////
DWORD VirtualAddressToPointer(IMAGE_DOS_HEADER *lpFileHead,DWORD dwVirtualAddress)
{
::IMAGE_NT_HEADERS *lpPEHead;
lpPEHead = (IMAGE_NT_HEADERS*)( (BYTE*)lpFileHead + lpFileHead->e_lfanew);
return RvaToPointer(lpFileHead, dwVirtualAddress - lpPEHead->OptionalHeader.ImageBase);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////获得RVA偏移处的节区名称////////////////////////////////////////////////
PBYTE GetRvaSection (IMAGE_DOS_HEADER *lpFileHead, DWORD dwRva)
{
IMAGE_NT_HEADERS *lpPEHead;
IMAGE_SECTION_HEADER *lpSectionHead;
DWORD i;
lpPEHead = (IMAGE_NT_HEADERS*)( (BYTE*)lpFileHead + lpFileHead->e_lfanew);
i = lpPEHead->FileHeader.NumberOfSections;
lpSectionHead = (IMAGE_SECTION_HEADER*)(++lpPEHead);
for ( ; i > 0 ; i--, lpSectionHead++)
{
if ( (dwRva >= lpSectionHead->VirtualAddress) && (dwRva < (lpSectionHead->VirtualAddress + lpSectionHead->SizeOfRawData) ) )
{
return (PBYTE)lpSectionHead;
}
}
return (PBYTE)szNotFound;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////获得指定RVA所处节区的节表头,失败返回NULL/////////////////////////////////////////
PIMAGE_SECTION_HEADER GetSectionOfRva (IMAGE_DOS_HEADER *lpFileHead, char* secName)
{
::PIMAGE_NT_HEADERS lpNtHead = (PIMAGE_NT_HEADERS)( (BYTE*)lpFileHead + lpFileHead->e_lfanew);
DWORD dwSec = lpNtHead->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER* lpSection = (PIMAGE_SECTION_HEADER) (lpNtHead + 1);
for (DWORD i=0; i < dwSec; i++)
{
if(!strncmp((char*)lpSection->Name, secName, IMAGE_SIZEOF_SHORT_NAME) )
return lpSection;
lpSection++;
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////文件偏移转换成RVA///////////////////////////////////////////////////////////
DWORD OffsetToRva(IMAGE_DOS_HEADER *lpFileHead, DWORD dwOffset)
{
::IMAGE_NT_HEADERS *lpPEHead;
::IMAGE_SECTION_HEADER *lpSectionHead;
DWORD i;
lpPEHead = (IMAGE_NT_HEADERS*)( (BYTE*)lpFileHead + lpFileHead->e_lfanew);
i = lpPEHead->FileHeader.NumberOfSections;
lpSectionHead = (IMAGE_SECTION_HEADER*)(++lpPEHead);
for ( ; i > 0; i--, lpSectionHead++)
{
if ( (dwOffset >= lpSectionHead->PointerToRawData) && (dwOffset < (lpSectionHead->PointerToRawData + lpSectionHead->SizeOfRawData) ) )
{
dwOffset = dwOffset - lpSectionHead->PointerToRawData + lpSectionHead->VirtualAddress;
return dwOffset;
}
}
return -1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////文件偏移转换成内存指针///////////////////////////////////////////////////////////
DWORD OffsetToPointer(IMAGE_DOS_HEADER *lpFileHead, DWORD dwOffset)
{
DWORD RVA = OffsetToRva(lpFileHead, dwOffset);
if( RVA == -1)
return -1;
return (DWORD)(lpFileHead) + RVA;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////按指定大小对齐//////////////////////////////////////////////////////////
DWORD Align(DWORD dwSize, DWORD dwAlignment)
{
return (dwSize + dwAlignment - 1) /dwAlignment * dwAlignment;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////获得区块有效数据部分大小/////////////////////////////////////////////////
DWORD GetValidSize(PBYTE lpMemory, PIMAGE_SECTION_HEADER lpSection)
{
PBYTE lpData;
DWORD dwSize=0;
lpData = (PBYTE)( lpMemory + lpSection->PointerToRawData + lpSection->SizeOfRawData - 1);
while (*lpData == 0)
{
lpData--;
dwSize++;
}
dwSize -= 8; //减去8个字节防止是字符串或某结构的结尾
if (dwSize > 0)
return lpSection->SizeOfRawData - dwSize;
else
return lpSection->SizeOfRawData;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif
#ifndef KERNEL_H
#define KERNEL_H
#include "RvaToOffset.h"
#define ITEM_NUM 16
//静态补丁类型
#define ADD_LAST_SECTION 1 //添加代码到最后一个区段
#define ADD_NEW_SECTION 2 //添加代码到一个新建的区段
#define ADD_TO_HEADER 3 //添加代码到PE头部
#define BYTE_PATCH 4 //这里再加一种字节补丁,针对一些简单的程序
//动态补丁类型
#define SLEEP_PATCH 1
#define DEBUG_PATCH 2
extern HINSTANCE hInst; //此变量在主文件中定义
//主要功能函数实现
BOOL IsPeFile(TCHAR szFileName[])
{
HANDLE hFile;
WORD wMagic;
DWORD dwRead,dw;
if (INVALID_HANDLE_VALUE != ( hFile = CreateFile (szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, \
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
{
ReadFile(hFile , &wMagic, 2, &dwRead, NULL);
if ( wMagic == 0x5A4D)
{
SetFilePointer(hFile, 0x3C, 0, FILE_BEGIN);
ReadFile(hFile , &dw, 4, &dwRead, NULL);
SetFilePointer(hFile, dw, 0, FILE_BEGIN);
ReadFile(hFile , &wMagic, 2, &dwRead, NULL);
if (wMagic == 0x4550)
return TRUE;
}
}
return FALSE;
}
////////////////////////////////////////////////////////////////
// 计算字符串的CRC32值
// 参数:欲计算CRC32值字符串的首地址和大小
// 返回值: 返回CRC32值
DWORD CalCRC32(BYTE* ptr,DWORD Size)
{
DWORD crcTable[256],crcTmp1;
//动态生成CRC-32表
for (int i=0; i<256; i++)
{
crcTmp1 = i;
for (int j=8; j>0; j--)
{
if (crcTmp1&1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L;
else crcTmp1 >>= 1;
}
crcTable[i] = crcTmp1;
}
//计算CRC32值
DWORD crcTmp2= 0xFFFFFFFF;
while(Size--)
{
crcTmp2 = ((crcTmp2>>8) & 0x00FFFFFF) ^ crcTable[ (crcTmp2^(*ptr)) & 0xFF ];
ptr++;
}
return (crcTmp2^0xFFFFFFFF);
}
DWORD GetCRC32(TCHAR szFileName[])
{
PIMAGE_DOS_HEADER pDosHeader=NULL;
PIMAGE_NT_HEADERS pNtHeader=NULL;
PIMAGE_SECTION_HEADER pSecHeader=NULL;
DWORD fileSize, CRC32, NumberOfBytesRW;
PBYTE pBuffer ;
//打开文件
HANDLE hFile = CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if ( hFile == INVALID_HANDLE_VALUE )
return FALSE;
//获得文件长度 :
fileSize = GetFileSize(hFile,NULL);
if (fileSize == 0xFFFFFFFF)
return FALSE;
pBuffer = new BYTE[fileSize]; // 申请内存
ReadFile(hFile,pBuffer, fileSize, &NumberOfBytesRW, NULL);//读取文件内容
CloseHandle(hFile); //关闭文件
pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
fileSize = fileSize - pDosHeader->e_lfanew;
CRC32 = CalCRC32(pBuffer + pDosHeader->e_lfanew, fileSize);
delete pBuffer;
return CRC32;
}
/*需要工具修正的节为.sdata节
#pragma data_seg(".sdata")
DWORD dwTypeOfPatch = 0; /指示补丁类型
DWORD dwPatchNum = 2; //补丁数量
//偏移8
TCHAR szFileName[MAX_PATH] = { 0 };
//偏移528
DWORD dwPatchAddress[16] = { 0} //////////////////////利用调试寄存器打丁///////////////////////////////////////////////////////
/////////////打此类补丁应在补丁地址第一个地址填上希望中断的地址以确保所有地址数据已解码,以保证补丁正确性///////////
//偏移592
BYTE byOldData[16] = { 0}; //补丁处旧数据和新数据
//偏移608
BYTE byNewData[16] = { 0};
#pragma data_seg()
根据需要加入了CRC32验证,需要补丁工具在PE头前4个字节写上目标文件的CRC32*/
//创建补丁文件,补丁模版以资源的形式存储在程序中
//参数:szPatchName:创建的补丁文件名 szFileName:目标文件名 lpPatchAddress:补丁地址数组
// lpNewByte:补丁原始数据数组 lpNewByte:补丁新数据数组 dwTypeOfPatch:补丁类型
// dwPatchNum:补丁数量 ID:补丁模版的资源ID bCRC32:是否加入CRC32文件验证
BOOL CreatePatch(TCHAR szPatchName[], TCHAR szFileName[], DWORD lpPatchAddress[],BYTE lpOldByte[],BYTE lpNewByte[],\
DWORD dwTypeOfPatch, DWORD dwPatchNum, DWORD ID, BOOL bCRC32 )
{
static char secName[8] = ".sdata";
DWORD CRC32;
if (bCRC32)
{
CRC32 = GetCRC32(szFileName );
if (!CRC32)
{
MessageBox(NULL, TEXT("CRC32提取出错"), NULL, 0);
return FALSE;
}
}
DWORD dwResSize;
PBYTE lpResData;
HGLOBAL hGlobal;
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(ID), L"PETYPE" );
if (hRes)
{
dwResSize = SizeofResource(hInst, hRes);
hGlobal = LoadResource(hInst, hRes);
if (hGlobal )
{
lpResData = (PBYTE)LockResource(hGlobal);
if (lpResData )
{
///////////////////////////////////开始写入文件并修正补丁中的参数//////////////////////////////////////////
HANDLE hFile, hMap;
PBYTE lpMemory;
PIMAGE_NT_HEADERS lpNtHeaders;
PIMAGE_SECTION_HEADER lpSectionHeader;
PBYTE lpSectionData;
DWORD* lpCRC32;
DWORD dwFileSize, dwRead, dwSectionNum;
if (INVALID_HANDLE_VALUE != ( hFile = CreateFile (szPatchName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
{
WriteFile(hFile, lpResData, dwResSize, &dwRead, NULL); //写入文件
dwFileSize = GetFileSize (hFile, NULL);
//修正数据
if (dwFileSize)
{
hMap = CreateFileMapping (hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hMap)
{
lpMemory = (BYTE *)MapViewOfFile (hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpMemory)
{
lpNtHeaders = (PIMAGE_NT_HEADERS)(lpMemory + ((PIMAGE_DOS_HEADER)lpMemory)->e_lfanew);
if (bCRC32) //写CRC32值
{
lpCRC32 = (DWORD*)((PBYTE)(lpNtHeaders)-4);
*lpCRC32 = CRC32;
}
dwSectionNum = lpNtHeaders->FileHeader.NumberOfSections;
lpSectionHeader = (PIMAGE_SECTION_HEADER)(lpNtHeaders + 1);
//查找需修正变量所在区段
for (DWORD i=0; i < dwSectionNum; i++, lpSectionHeader++)
{
if ( !lstrcmpiA( (LPCSTR)lpSectionHeader->Name, secName) )
break;
}
lpSectionData = lpMemory + RvaToOffset( (PIMAGE_DOS_HEADER)lpMemory, lpSectionHeader->VirtualAddress);
////////////////////////////////////////////////////////////修正变量///////////////////////////////////////////////////////////////////////////
int x;
*(DWORD*)lpSectionData = dwTypeOfPatch;
*(DWORD*)(lpSectionData+4) = dwPatchNum;
for(x=lstrlen(szFileName); x > 0; x--)
if(szFileName[x] == TEXT('\\') )
break;
lstrcpy( (LPWSTR)(lpSectionData+8), &(szFileName[x]) );
memcpy(lpSectionData+528, lpPatchAddress, ITEM_NUM*sizeof(DWORD));
memcpy(lpSectionData+592, lpOldByte, ITEM_NUM*sizeof(BYTE));
memcpy(lpSectionData+608, lpNewByte, ITEM_NUM*sizeof(BYTE));
////////////////////////////////////////////////////////////修正完毕////////////////////////////////////////////////////////////////////////////
UnmapViewOfFile (lpMemory);
CloseHandle (hMap);
CloseHandle (hFile);
return TRUE;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
return FALSE;
}
}
}
return FALSE;
}
#endif
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
#include "resource.h"
#include "ApiMacro.h"
#include "kernel.h"
//搞掉些烦人的警告
#pragma warning(disable:4244)
#pragma warning(disable:4996)
#define ITEM_NUM 16 //ListView最大项目数
#define CODE_SIZE 1024*32 //自定义补丁代码的最大长度
static char g_szBuffer[CODE_SIZE] = { 0 }; //32KB缓存
static char g_szUserCode[CODE_SIZE] = { 0 };//32KB用户代码缓存
BOOL DIY_OK = FALSE;
//添加WIN7风格界面
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0'\
processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
////////////////////////////////////////界面辅助函数//////////////////////////////////////////////////////
void SuperClass(); //编辑控件超类化,生成16进制编辑控件
LONG WINAPI ProcEdit(HWND, UINT, WPARAM, LPARAM); //新编辑控件窗口过程
void PopFileInitialize (HWND hwnd); //文件对话框初始化
BOOL PopFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName); //打开对话框
BOOL PopFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName); //保存对话框
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//主对话框窗口过程
BOOL CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
//主对话框消息处理函数
BOOL Main_OnNotify (HWND hwnd, int wParam, LPNMHDR pnm);
BOOL Main_OnCommand (HWND hDlg, int id,HWND hCtrl, UINT codeNotify);
BOOL Main_OnInitDialog (HWND hWnd, HWND hWndFocus, LPARAM lParam) ;
//高级设置对话框
BOOL CALLBACK SetDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
//帮助对话框
BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) ;
//地址输入对话框
BOOL CALLBACK AddressDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
//定制补丁对话框
BOOL CALLBACK DiyDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
void GetListData( ); //提取ListView的数据存到全局变量中
void GetPeHeader(TCHAR szFileName[]); //获取整个PE头部数据
BOOL CreateDiyPatch(); //定制补丁生成函数
HINSTANCE hInst;
HWND g_hWnd; //主对话框窗口句柄
HWND g_hListView; //表格视图句柄
BOOL g_bOffset = FALSE; //记录补丁地址是否是用文件偏移,如果是则转换成虚拟地址
DWORD g_dwLineOfNum = 0; //记录ListView数据行数
DWORD g_dwTypeOfPatch = 1;//记录补丁类型,并赋值默认方法
DWORD g_dwTypeOfLoader= 1;//记录Loader类型,并赋值默认方法
BOOL g_bIsPeFile = FALSE;//指示目标文件是否是PE文件
PBYTE g_lpPeHeader= NULL; //指向整个PE头部,用于RVA与offset之间的转换
DWORD g_dwAddress = 0; //地址对话框获得的地址
TCHAR g_szFileName[MAX_PATH] = { 0 }; //目标文件名
TCHAR g_szPatchName[MAX_PATH]= { 0 }; //补丁文件名
DWORD g_pPatchAddress[ITEM_NUM] = { 0 }; //补丁地址
BYTE g_pOldByte[ITEM_NUM] = { 0 }; //老数据
BYTE g_pNewByte[ITEM_NUM] = { 0 }; //新数据
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
hInst = hInstance;
InitCommonControls();
SuperClass();//编辑控件超类化
DialogBoxParam (hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DialogProc, 0);
return 0;
}
BOOL CALLBACK DialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
HANDLE_MSG(hDlg, WM_INITDIALOG, Main_OnInitDialog);
HANDLE_MSG(hDlg, WM_COMMAND , Main_OnCommand );
case WM_CLOSE:
EndDialog (hDlg, 0);
return true;
}
return FALSE;
}
//对话框初始化
BOOL Main_OnInitDialog (HWND hDlg, HWND hWndFocus, LPARAM lParam)
{
chSETDLGICONS(hDlg, IDI_ICON1);
HWND hEdit1,hEdit2,hEdit3;
hEdit1 = GetDlgItem(hDlg, IDC_OFFSET);
hEdit2 = GetDlgItem(hDlg, IDC_OLDBYTE);
hEdit3 = GetDlgItem(hDlg, IDC_NEWBYTE);
Edit_LimitText(hEdit1, 8);
Edit_LimitText(hEdit2, 2);
Edit_LimitText(hEdit3, 2);
Edit_LimitText(GetDlgItem(hDlg, IDC_PATH), MAX_PATH);
g_hWnd = hDlg;
PopFileInitialize (hDlg);
CheckDlgButton(hDlg, IDC_VIRTUALADDRESS, BST_CHECKED);
//定义表格外观
g_hListView = GetDlgItem(hDlg, IDC_LISTVIEW);
ListView_SetExtendedListViewStyle(g_hListView, LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT );
//ListView_SetBkColor(g_hListView, 0xa0a0ff);背景色
ShowWindow (g_hListView, SW_SHOW);
ListView_InsertCaption(g_hListView, 0, 200, TEXT("虚拟地址") );
ListView_InsertCaption(g_hListView, 1, 178, TEXT("原始字节") );
ListView_InsertCaption(g_hListView, 2, 178, TEXT("新的字节") );
//ListView_AddLine(g_hListView);
return TRUE;
}
BOOL Main_OnCommand (HWND hDlg, int id,HWND hCtrl, UINT codeNotify)
{
static TCHAR szStr[] = TEXT("选择目标PE文件");
static TCHAR szOffset[10];
static TCHAR szOldByte[3], szNewByte[3];
static TCHAR szStr2[]= TEXT("创建补丁文件");
TCHAR szFormat[12] = TEXT("0x00000000");
int i;
DWORD a;
switch(id)
{
//case IDC_LISTVIEW: //列表
// return TRUE;
//case IDC_PATH: //目标文件路径
// return TRUE;
case IDC_OPEN: //浏览,打开文件
if (PopFileOpenDlg(hDlg, g_szFileName, szStr ) )
if ( IsPeFile(g_szFileName) )
{
g_bIsPeFile = TRUE;
SetDlgItemText(hDlg, IDC_PATH, g_szFileName);
GetPeHeader(g_szFileName); //读取PE头以备偏移转换用
}
else
{
g_bIsPeFile = FALSE;
MessageBox(hDlg, TEXT("文件格式错误"), TEXT("提示"), 0);
}
return TRUE;
case IDC_FILE_OFFSET: //文件偏移
g_bOffset = TRUE;
ListView_SetCaption(g_hListView, 0, TEXT("文件偏移") );
ListView_DeleteAllItems(g_hListView);
g_dwLineOfNum = 0;
return TRUE;
case IDC_VIRTUALADDRESS: //虚拟地址
g_bOffset = FALSE;
ListView_SetCaption(g_hListView, 0, TEXT("虚拟地址") );
ListView_DeleteAllItems(g_hListView);
g_dwLineOfNum = 0;
return TRUE;
/* case IDC_OFFSET: //偏移
return TRUE;
case IDC_OLDBYTE: //老字节
return TRUE;
case IDC_NEWBYTE: //新字节
return TRUE;
*/
case IDC_ADD: //添加
if (GetDlgItemText(hDlg, IDC_OFFSET, szOffset, sizeof(szOffset)) && GetDlgItemText(hDlg, IDC_OLDBYTE, szOldByte,\
sizeof(szOldByte)) && GetDlgItemText(hDlg, IDC_NEWBYTE, szNewByte, sizeof(szNewByte)) )
{
if ( g_dwLineOfNum < ITEM_NUM)
{
szFormat[10-lstrlen(szOffset)] = TEXT('\0');
lstrcat(szFormat, szOffset);
i = ListView_AddLine(g_hListView);//添加一行
ListView_SetItemText(g_hListView, i, 0, szFormat);
ListView_SetItemText(g_hListView, i, 1, szOldByte);
ListView_SetItemText(g_hListView, i, 2, szNewByte);
SetDlgItemText(hDlg, IDC_OFFSET, NULL);
SetDlgItemText(hDlg, IDC_OLDBYTE, NULL);
SetDlgItemText(hDlg, IDC_NEWBYTE, NULL);
g_dwLineOfNum++;
}
}
return TRUE;
case IDC_DELETE: //删除选中行
i = ListView_GetSelectionMark(g_hListView); //获得选中行索引
ListView_DeleteItem(g_hListView, i);
g_dwLineOfNum--;
return TRUE;
case IDC_CLEAR: //清空所有行
ListView_DeleteAllItems(g_hListView);
g_dwLineOfNum = 0;
return TRUE;
case IDC_SET: //高级设置
DialogBox (hInst, MAKEINTRESOURCE (IDD_SET), hDlg, SetDlgProc) ;
return TRUE;
case IDC_LOADER: //创建Loader
if (g_bIsPeFile )
{
lstrcpy(g_szPatchName, TEXT("Loader.exe") );
if ( PopFileSaveDlg (hDlg, g_szPatchName, szStr2))
{
GetListData( );
if (g_dwTypeOfLoader == DEBUG_PATCH) //用调试寄存器补丁需要特别处理
{
DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_ADDRESS), NULL, AddressDlgProc, 0);
if (g_dwAddress == 0) //如果没有指定进行补丁的地址
break;
else
{
for (int i=g_dwLineOfNum; i > 0; i--)
{
g_pPatchAddress[i] = g_pPatchAddress[i-1];
}
g_pPatchAddress[0] = g_dwAddress; //存储指定地址,由补丁数据的存储方式决定
}
}
if (CreatePatch(g_szPatchName, g_szFileName, g_pPatchAddress, g_pOldByte, g_pNewByte, g_dwTypeOfLoader,\
g_dwLineOfNum, IDR_LOADER, FALSE) )//ID为资源ID号
MessageBox( hDlg, TEXT("创建补丁成功"), TEXT("恭喜"), 0);
else
MessageBox(hDlg, TEXT("失败,未知错误"), TEXT("悲剧"), 0);
}
}
else
MessageBox(hDlg, TEXT("请选择目标文件"), TEXT("创建补丁失败"), 0);
return TRUE;
case IDC_PATCH: //创建补丁
if (g_bIsPeFile )
{
lstrcpy(g_szPatchName, TEXT("Patch.exe") );
if ( PopFileSaveDlg (hDlg, g_szPatchName, szStr2))
{
GetListData( );
if (CreatePatch(g_szPatchName, g_szFileName, g_pPatchAddress, g_pOldByte, g_pNewByte, g_dwTypeOfPatch,\
g_dwLineOfNum, IDR_PATCH, TRUE) )//ID为资源ID号
MessageBox( hDlg, TEXT("创建补丁成功"), TEXT("恭喜"), 0);
else
MessageBox(hDlg, TEXT("失败,未知错误"), TEXT("悲剧"), 0);
}
}
else
MessageBox(hDlg, TEXT("请选择目标文件"), TEXT("创建补丁失败"), 0);
return TRUE;
case IDC_DIY: //定制补丁
DialogBox (hInst, MAKEINTRESOURCE (IDD_DIY), hDlg, DiyDlgProc) ;
return TRUE;
case IDC_CREATE: //生成定制补丁
if (!CreateDiyPatch() )
MessageBox(hDlg, TEXT("创建补丁失败"), TEXT("oh yea"), 0);
return TRUE;
case IDM_HELP_ABOUT :
DialogBox (hInst, MAKEINTRESOURCE (IDD_ABOUT), hDlg, AboutDlgProc) ;
return TRUE;
case IDCANCEL:
EndDialog (hDlg, 0) ;
return TRUE;
}
return FALSE;
}
//高级设置对话框窗口过程
BOOL CALLBACK SetDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static DWORD dwTmpPatch = 1;
static DWORD dwTmpLoader= 1;
switch(message)
{
case WM_INITDIALOG:
switch(g_dwTypeOfPatch)
{
case ADD_LAST_SECTION:
CheckDlgButton(hDlg, IDC_ADDLAST, BST_CHECKED);
break;
case ADD_NEW_SECTION:
CheckDlgButton(hDlg, IDC_ADDNEW, BST_CHECKED);
break;
case ADD_TO_HEADER:
CheckDlgButton(hDlg, IDC_ADDHEADER, BST_CHECKED);
break;
case BYTE_PATCH:
CheckDlgButton(hDlg, IDC_ADDFILE, BST_CHECKED);
break;
}
switch(g_dwTypeOfLoader)
{
case SLEEP_PATCH:
CheckDlgButton(hDlg, IDC_THREAD, BST_CHECKED);
break;
case DEBUG_PATCH:
CheckDlgButton(hDlg, IDC_DEBUG, BST_CHECKED);
break;
}
return TRUE;
case WM_COMMAND :
switch (LOWORD (wParam))
{
case IDC_ADDLAST:
dwTmpPatch = ADD_LAST_SECTION;
return TRUE;
case IDC_ADDHEADER:
dwTmpPatch = ADD_TO_HEADER;
return TRUE;
case IDC_ADDNEW:
dwTmpPatch = ADD_NEW_SECTION;
return TRUE;
case IDC_ADDFILE:
dwTmpPatch = BYTE_PATCH;
return TRUE;
case IDC_THREAD:
dwTmpLoader = SLEEP_PATCH;
return TRUE;
case IDC_DEBUG:
dwTmpLoader = DEBUG_PATCH;
return TRUE;
case IDCANCEL:
EndDialog(hDlg, 0);
return TRUE;
case IDOK : //保存设置
g_dwTypeOfPatch = dwTmpPatch;
g_dwTypeOfLoader= dwTmpLoader;
EndDialog (hDlg, 0) ;
return TRUE ;
}
return TRUE ;
case WM_CLOSE:
EndDialog (hDlg, 0) ;
return TRUE;
}
return FALSE;
}
BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_LBUTTONDOWN:
PostMessage(hDlg, WM_NCLBUTTONDOWN, HTCAPTION, 0);//实现拖拽效果
return TRUE ;
case WM_COMMAND :
switch (LOWORD (wParam))
{
case IDOK :
EndDialog (hDlg, 0) ;
return TRUE ;
}
return TRUE ;
case WM_CLOSE:
EndDialog (hDlg, 0) ;
return TRUE;
}
return FALSE;
}
BOOL CALLBACK AddressDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static TCHAR szBuffer[12];
static HWND hEdit;
switch(message)
{
case WM_INITDIALOG:
hEdit = GetDlgItem(hDlg, ID_ADDRESS);
Edit_LimitText(hEdit, 8);
return TRUE;
case WM_COMMAND :
switch (LOWORD (wParam))
{
case IDOK :
GetDlgItemText(hDlg, ID_ADDRESS, szBuffer, sizeof(szBuffer) );
swscanf(szBuffer, L"%x", &g_dwAddress);
EndDialog (hDlg, 0) ;
return TRUE ;
}
return TRUE ;
case WM_CLOSE:
g_dwAddress = 0;
EndDialog (hDlg, 0) ;
return TRUE;
}
return FALSE;
}
BOOL CALLBACK DiyDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hEdit;
static FILE *pFile;
static long fileSize;
static BOOL bFirst = TRUE; //第一次进入?
char ch;
int i;
switch(message)
{
case WM_INITDIALOG:
hEdit = GetDlgItem(hDlg, IDC_CODE);
if (bFirst)
{
bFirst = FALSE;
pFile = fopen(".\\template\\patch", "r");
if (pFile != NULL)
{
i=0;
while((ch = fgetc(pFile) )!= EOF)
{
if (ch == '\n')
g_szBuffer[i++]='\r';
g_szBuffer[i++]=ch;
}
SetWindowTextA(hEdit, g_szBuffer);
DIY_OK = TRUE;
fclose(pFile);
}
ShowWindow(g_hWnd, SW_HIDE);
return TRUE;
}
if (DIY_OK)
{
ShowWindow(g_hWnd, SW_HIDE);
SetWindowTextA(hEdit, g_szBuffer);
}
else
{
MessageBox(g_hWnd,L"读取失败",L"未知错误", NULL);
EndDialog (hDlg, 0) ;
}
return TRUE;
case WM_COMMAND :
switch (LOWORD (wParam))
{
case IDOK :
GetDlgItemTextA(hDlg, IDC_CODE, g_szUserCode, CODE_SIZE );
EnableWindow(GetDlgItem(g_hWnd, IDC_CREATE), TRUE);
ShowWindow(g_hWnd, SW_SHOW);
EndDialog (hDlg, 0) ;
return TRUE ;
case IDCANCEL:
EnableWindow(GetDlgItem(g_hWnd, IDC_CREATE), FALSE);
ShowWindow(g_hWnd, SW_SHOW);
EndDialog (hDlg, 0) ;
return TRUE;
}
return TRUE ;
case WM_CLOSE:
ShowWindow(g_hWnd, SW_SHOW);
EndDialog (hDlg, 0) ;
return TRUE;
}
return FALSE;
}
BOOL CreateDiyPatch()
{
static TCHAR szStr[]= TEXT("创建自定义补丁");
static char szBuffer[1024];
static TCHAR szPatch[MAX_PATH];
static TCHAR szCurrentDirectory[MAX_PATH];
static TCHAR szOriDirectory[MAX_PATH];
HANDLE hAsmFile, hAsmMap;
PBYTE lpMemory;
DWORD dwFileSize;
int x;
if (DIY_OK == FALSE)
return FALSE;
if ( PopFileSaveDlg (g_hWnd, g_szPatchName, szStr) )
{
GetCurrentDirectory(sizeof(szOriDirectory), szOriDirectory);
GetModuleFileName(hInst, szPatch, sizeof(szPatch) );
for(x=lstrlen(szPatch); x > 0; x--)
if(szPatch[x] == TEXT('\\') )
break;
lstrcpy(szCurrentDirectory, szPatch);
lstrcpy(&(szCurrentDirectory[x]), L"\\template\\"); //获得当前目录
lstrcpy( &(szPatch[x]), TEXT("\\template\\patch"));
if (INVALID_HANDLE_VALUE != ( hAsmFile = CreateFile ( szPatch, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
{
dwFileSize = GetFileSize (hAsmFile, NULL);
if (dwFileSize)
{
hAsmMap = CreateFileMapping (hAsmFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hAsmMap)
{
lpMemory = (BYTE *)MapViewOfFile (hAsmMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpMemory)
{
memcpy(lpMemory, g_szUserCode, strlen( (char*)g_szUserCode) ); //复制自定义代码
//下面代码用来隐藏控制台,要不一闪一闪比较难看
TCHAR szConsoleTitle[100];//控制台标题
HWND hCon;
AllocConsole();
GetConsoleTitle(szConsoleTitle, sizeof(szConsoleTitle));
hCon=FindWindow(NULL, szConsoleTitle);
ShowWindow(hCon, SW_HIDE);
//设置工作目录并编译连接
SetCurrentDirectory(szCurrentDirectory);
system("ml /c /coff DiyPatch >> _1.txt");
system("link /subsystem:windows DiyPatch.obj DiyPatch.res >> _1.txt");
system("del DiyPatch.obj");
MoveFile(L"DiyPatch.exe", g_szPatchName);
memcpy(lpMemory, g_szBuffer, dwFileSize );//还原模版代码
UnmapViewOfFile(lpMemory);
CloseHandle(hAsmMap);
CloseHandle(hAsmFile);
FILE *pFile = fopen("_1.txt", "r+");
int ch,i=0;
if (pFile != NULL)
{
while((ch = fgetc(pFile) )!= EOF)
{
if (ch == '\n')
szBuffer[i++]='\r';
szBuffer[i++]=ch;
}
MessageBoxA(g_hWnd, szBuffer, "生成结果", 0);
fclose(pFile);
}
system("del _1.txt");
SetCurrentDirectory(szOriDirectory); //还原工作目录
return TRUE;
}
else UnmapViewOfFile(lpMemory);
}
else CloseHandle(hAsmMap);
}
else CloseHandle(hAsmFile);
}
}
return FALSE;
}
//提取数据
void GetListData( )
{
TCHAR szBuffer[12] = { 0 };
DWORD dwAddress;
DWORD dwOldData;
DWORD dwNewData;
for ( DWORD i=0; i < g_dwLineOfNum; i++)
{
ListView_GetItemText(g_hListView, i, 0, szBuffer, sizeof(szBuffer) );
swscanf(szBuffer, L"%x", &dwAddress);
ListView_GetItemText(g_hListView, i, 1, szBuffer, sizeof(szBuffer) );
swscanf(szBuffer, L"%x", &dwOldData);
ListView_GetItemText(g_hListView, i, 2, szBuffer, sizeof(szBuffer) );
swscanf(szBuffer, L"%x", &dwNewData);
if (g_bOffset) //统一转换成虚拟地址
dwAddress = OffsetToRva( (PIMAGE_DOS_HEADER)g_lpPeHeader, dwAddress);
g_pPatchAddress[i] = dwAddress;
g_pOldByte[i] = (BYTE)dwOldData;
g_pNewByte[i] = (BYTE)dwNewData;
}
}
//读取目标文件PE头
void GetPeHeader(TCHAR szFileName[])
{
DWORD dwRead, dwHeaderSize;
HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if ( hFile == INVALID_HANDLE_VALUE )
return ;
if (g_lpPeHeader)
delete g_lpPeHeader;
/////////////////////////////////读取整个PE头/////////////////////////////////////////////
IMAGE_NT_HEADERS stNtHeaders;
SetFilePointer(hFile, 0x3c, 0, FILE_BEGIN);
ReadFile(hFile, &dwHeaderSize, 4, &dwRead, NULL);
SetFilePointer(hFile, dwHeaderSize, 0, FILE_BEGIN);
ReadFile(hFile, &stNtHeaders, sizeof(IMAGE_NT_HEADERS), &dwRead, NULL);
dwHeaderSize = stNtHeaders.OptionalHeader.SizeOfHeaders;
g_lpPeHeader = new BYTE[dwHeaderSize];
SetFilePointer(hFile, 0, 0, FILE_BEGIN);
ReadFile(hFile, g_lpPeHeader, dwHeaderSize, &dwRead, NULL);
CloseHandle(hFile);
//////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////16进制编辑控件实现/////////////////////////////////////////
WNDPROC g_lpOldProc; //edit控件的老窗口过程地址
void SuperClass()
{
WNDCLASSEX stWC;
stWC.cbSize = sizeof(WNDCLASSEX);
GetClassInfoEx(NULL, TEXT("Edit"), &stWC);
g_lpOldProc = stWC.lpfnWndProc;
stWC.lpfnWndProc = ProcEdit;
stWC.hInstance = hInst;
stWC.lpszClassName = TEXT("HexEdit"); //新类名
RegisterClassEx(&stWC);
}
TCHAR szHexChar[] = TEXT("0123456789abcdefABCDEF\b"); //编辑控件允许显示的字符,包括退格键
LONG WINAPI ProcEdit(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) //新编辑控件窗口过程
{
int len=lstrlen(szHexChar);
if (message == WM_CHAR)
{
for (int i=0; i < len; i++)
{
if (szHexChar[i] == (TCHAR)wParam)
{
if (wParam > TEXT('9') )
wParam &= ~0x20;
return CallWindowProc(g_lpOldProc, hwnd, message, wParam, lParam);
}
}
return TRUE;
}
return CallWindowProc(g_lpOldProc, hwnd, message, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////文件对话框函数/////////////////////////////////////
static OPENFILENAME ofn ;
void PopFileInitialize (HWND hwnd)
{
static TCHAR szFilter[] = TEXT ("PE Files (*.exe;*.dll)\0*.exe;*.dll;*.scr;*.fon;*.drv\0") \
TEXT ("All Files (*.*)\0*.*\0\0") ;
ofn.lStructSize = sizeof (OPENFILENAME) ;
ofn.hwndOwner = hwnd ;
ofn.hInstance = NULL ;
ofn.lpstrFilter = szFilter ;
ofn.lpstrCustomFilter = NULL ;
ofn.nMaxCustFilter = 0 ;
ofn.nFilterIndex = 0 ;
ofn.lpstrFile = NULL ; // Set in Open and Close functions
ofn.nMaxFile = MAX_PATH ;
ofn.lpstrFileTitle = NULL ; // Set in Open and Close functions
ofn.nMaxFileTitle = MAX_PATH ;
ofn.lpstrInitialDir = NULL ;
ofn.lpstrTitle = NULL ;
ofn.Flags = 0 ; // Set in Open and Close functions
ofn.nFileOffset = 0 ;
ofn.nFileExtension = 0 ;
ofn.lpstrDefExt = NULL; //TEXT ("exe") ;
ofn.lCustData = 0L ;
ofn.lpfnHook = NULL ;
ofn.lpTemplateName = NULL ;
}
BOOL PopFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
{
ofn.hwndOwner = hwnd ;
ofn.lpstrFile = pstrFileName ;
ofn.lpstrFileTitle = pstrTitleName ;
ofn.Flags = OFN_HIDEREADONLY | OFN_CREATEPROMPT ;
return GetOpenFileName (&ofn) ;
}
BOOL PopFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
{
ofn.hwndOwner = hwnd ;
ofn.lpstrFile = pstrFileName ;
ofn.lpstrFileTitle = pstrTitleName ;
ofn.Flags = OFN_OVERWRITEPROMPT ;
return GetSaveFileName (&ofn) ;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
patc.exe
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include c:\masm32\include\windows.inc
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 导出变量供补丁工具使用
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
PUBLIC Appendcode_Start ;附加代码起始处
PUBLIC Appendcode_End ;附加代码结束处
PUBLIC Patch_Data ;补丁数据处
.code
Appendcode_Start LABEL DWORD
jmp _NewEntry
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;重要的函数名,为兼容WIN7 kernelbase.dll,使用LoadLibraryExA函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
szLoadLibraryExA db 'LoadLibraryExA',0
szGetProcAddress db 'GetProcAddress',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;补丁功能代码需要的DLL,函数名,字符串等全局变量定义,以下为测试用
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;szUser32 db 'user32',0
;szMessageBoxA db 'MessageBoxA',0
;szCaption db '恭喜',0
;szText db '代码插入成功!',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;SEH错误Handler
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_SEHHandler proc _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatchertext
pushad
mov esi,_lpExceptionRecord
assume esi:ptr EXCEPTIONRECORD
mov edi,_lpContext
assume edi:ptr CONTEXT
mov eax,_lpSEH
push [eax+0ch]
pop [edi].regEbp
push [eax+08]
pop [edi].regEip
push eax
pop [edi].regEsp
assume edi:nothing,esi:nothing
popad
mov eax,ExceptionContinueExecution
ret
_SEHHandler endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;获取kernel32.dll基地址,2种获取方法自行选择
;PS:用PEB获取最好使用LoadLibraryExA函数以兼容WIN7
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;_GetKernel32Base proc uses edi esi ebx _dwEsp
; call @F
; @@:
; pop ebx
; sub ebx,offset @B
;
; ;安装SEH
; assume fs:nothing
; push ebp
; lea eax, [ebx+offset _safeplace]
; push eax
; lea eax,[ebx + offset _SEHHandler]
; push eax
; push fs:[0]
; mov fs:[0],esp
;
; mov eax,_dwEsp
; and eax,0ffff0000h
;
; .while eax>=70000000h
; .if word ptr [eax] == IMAGE_DOS_SIGNATURE
; mov edi,eax
; add edi,[eax+03ch]
; .if word ptr [edi] == IMAGE_NT_SIGNATURE
; jmp find
; .endif
; .endif
; _safeplace:
; sub eax,10000h
; .endw
; mov eax,0
; find:
; pop fs:[0]
; add esp,0ch
; ret
;_GetKernel32Base endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;用PEB获取基址的方法,WIN7中获得的实际是kernelbase.dll的基地址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_GetKernel32Base proc
local @dwRet
pushad
assume fs:nothing
mov eax,fs:[30h] ;获取PEB所在地址
mov eax,[eax+0ch] ;获取PEB_LDR_DATA 结构指针
mov esi,[eax+1ch] ;获取InInitializationOrderModuleList 链表头
;第一个LDR_MODULE节点InInitializationOrderModuleList成员的指针
lodsd ;获取双向链表当前节点后继的指针
mov eax,[eax+8] ;获取kernel32.dll的基地址
mov @dwRet,eax
popad
mov eax,@dwRet
ret
_GetKernel32Base endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;查找导出表获取制定API地址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_GetApi proc _hModule,_lpszApi
local @dwReturn,@dwSize
pushad
call @F
@@:
pop ebx
sub ebx,@B
assume fs:nothing
push ebp
push [ebx+offset error]
push [ebx+offset _SEHHandler]
push fs:[0]
mov fs:[0],esp
mov edi,_lpszApi
mov ecx,-1
xor eax,eax
cld
repnz scasb
sub edi,_lpszApi
mov @dwSize,edi
mov esi,_hModule
add esi,[esi+3ch]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,_hModule
assume esi:ptr IMAGE_EXPORT_DIRECTORY
mov ebx,[esi].AddressOfNames
add ebx,_hModule
xor edx,edx
.while edx < [esi].NumberOfNames
push esi
mov edi,[ebx]
add edi,_hModule
mov esi,_lpszApi
mov ecx,@dwSize
cld
repz cmpsb
.if !ecx
pop esi
jmp @F
.endif
next:
pop esi
inc edx
add ebx,4
.endw
jmp error
@@:
sub ebx,[esi].AddressOfNames
sub ebx,_hModule
shr ebx,1
add ebx,[esi].AddressOfNameOrdinals
add ebx,_hModule
movzx eax,word ptr [ebx]
shl eax,2
add eax,[esi].AddressOfFunctions
add eax,_hModule
mov eax,[eax]
add eax,_hModule
mov @dwReturn,eax
error:
pop fs:[0]
add esp,0ch
assume esi:nothing
popad
mov eax,@dwReturn
ret
_GetApi endp
;补丁所需要的函数和全局变量
szCreateThread db 'CreateThread',0
szGetTickCount db 'GetTickCount',0
szVirtualProtect db 'VirtualProtect',0
lpGetTickCount dd 0
StartCount dd 0
;以下变量需要补丁程序修正
Patch_Data LABEL DWORD
;dwTypeOfPatch dd 0 ;指示补丁类型
dwPatchNum dd 0 ;补丁数量
dwPatchAddress dd 16 dup(0) ;补丁地址
byOldData db 16 dup(0) ;补丁处旧数据和新数据
byNewData db 16 dup(0)
_Thread proc _lpVirtualProtect
local @lpGetTickCount,@temp,@StartCount,@num
pushad
call @F
@@:
pop ebx
sub ebx,@B
mov edx,dword ptr [ebx+offset lpGetTickCount]
mov @lpGetTickCount,edx
mov edx,dword ptr [ebx+offset StartCount]
mov @StartCount,edx
mov ecx,dword ptr [ebx+offset dwPatchNum]
mov @num,ecx
.while TRUE
call @lpGetTickCount
sub eax,@StartCount
cmp eax,493e0h ;大于五分钟则超时退出线程
jg _exit
;开始检测补丁地址
lea esi,dword ptr [ebx+offset dwPatchAddress] ;指向补丁地址
lea edi,dword ptr [ebx+offset byOldData] ;补丁处旧数据
lea edx,dword ptr [ebx+offset byNewData] ;补丁处新数据
;检测所有补丁处字节
mov ecx,dword ptr [ebx+offset dwPatchNum]
_peek:
push ecx
mov ecx,dword ptr [esi]
xor eax,eax
mov al,byte ptr [ecx] ;取补丁处数据
cmp al,byte ptr [edi] ;补丁处是否解码
jne _mismatch
;更改页面为读写执行,以确保补丁地址处拥有读写执行权限
pushad
lea eax,@temp
push eax
push 40h
push 100h
push ecx
call _lpVirtualProtect
popad
mov al,byte ptr [edx] ;进行补丁
mov byte ptr [ecx],al
dec @num
_mismatch:
inc edi
inc edx
add esi,4
pop ecx
cmp @num,0
je _exit
loop _peek
.endw
_exit:
popad
ret
_Thread endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;补丁功能部分
;_dwKernelBase: kernel32.dll基址
;_lpGetProcAddress: GetProcAddress地址
;_lpLoadLibraryA LoadLibraryA或LoadLibraryExA地址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Patch proc _dwKernelBase,_lpGetProcAddress,_lpLoadLib
local @lpVirtualProtect ;local @hUser32,@lpMessageBoxA
local @temp
pushad
;以下注释掉的为测试代码
;lea edx,dword ptr [ebx+offset szUser32]
;push 0
;push 0
;push edx
;call _lpLoadLib
;.if eax
; mov @hUser32,eax
; lea edx,dword ptr [ebx+offset szMessageBoxA]
; push edx
; push eax
; call _lpGetProcAddress
; .if eax
; mov @lpMessageBoxA,eax
; .endif
;.endif
;.if @lpMessageBoxA
;push MB_YESNO
;lea edx,dword ptr [ebx+offset szCaption]
;push edx
;lea edx,dword ptr [ebx+offset szText]
;push edx
;push NULL
;call @lpMessageBoxA
;.endif
lea edx,dword ptr [ebx+offset szVirtualProtect]
push edx
push _dwKernelBase
call _lpGetProcAddress
cmp eax,0
je _exit
mov @lpVirtualProtect,eax
lea edx,@temp
push edx
push 40h
push 1000h
lea edx,dword ptr [ebx+offset lpGetTickCount]
push edx
call @lpVirtualProtect ;确保全局变量位置可写
lea edx,dword ptr [ebx+offset szGetTickCount]
push edx
push _dwKernelBase
call _lpGetProcAddress
.if eax
mov dword ptr [ebx+offset lpGetTickCount],eax
call eax
mov dword ptr [ebx+offset StartCount],eax
lea edx,dword ptr [ebx+offset szCreateThread]
push edx
push _dwKernelBase
call _lpGetProcAddress
.if eax
lea edx,@temp
push edx
push 0
push @lpVirtualProtect ;线程参数为VirtualProtect函数的地址
lea edx,dword ptr [ebx+offset _Thread]
push edx
push 0
push 0
call eax ;创建监测线程进行补丁
.endif
.endif
_exit:
popad
ret
_Patch endp
_start proc
local @dwKernel32Base
local @lpGetProcAddress,@lpLoadLibraryExA
pushad
call _GetKernel32Base
.if eax
mov @dwKernel32Base,eax
lea edx,dword ptr [ebx+offset szGetProcAddress]
push edx
push eax
call _GetApi
mov @lpGetProcAddress,eax
.endif
.if @lpGetProcAddress
lea edx,dword ptr [ebx+offset szLoadLibraryExA]
push edx
push @dwKernel32Base
call @lpGetProcAddress
.if eax
mov @lpLoadLibraryExA,eax
push eax
push @lpGetProcAddress
push @dwKernel32Base
call _Patch
.endif
.endif
popad
xor eax,eax
ret
_start endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;PE文件新入口
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_NewEntry:
call @F
@@:
pop ebx
sub ebx,@B
call _start
;ret
jmpToStart db 0E9h,0F0h,0FFh,0ffh,0ffh ;需要补丁程序修正
ret
Appendcode_End LABEL DWORD
end
#ifndef ADDCODE_H
#define ADDCODE_H
#include <windows.h>
#include "RvaToOffset.h"
/////////////////////////下面几种附加代码的补丁应该是能很好的互相兼容(表示我测试过给一文件加了20多个依然正常#_#)///////////////////////////////////
//静态补丁类型
#define ADD_LAST_SECTION 1 //添加代码到最后一个区段
#define ADD_NEW_SECTION 2 //添加代码到一个新建的区段
#define ADD_TO_HEADER 3 //添加代码到PE头部
//除了以上3种外还有一种是寻找已存在区段空闲处并插入代码,这种插入PE头的修改更简单,只是比较容易失败,这里就不实现了
//这里再加一种字节补丁,针对一些简单的程序
#define BYTE_PATCH 4
///////////////////此文件补丁最多支持16个补丁地址,特别创建一个段用于补丁工具生成补丁时修正变量//////////////////////
#pragma data_seg(".sdata")
DWORD dwTypeOfPatch = 0 ; //指示补丁类型
DWORD dwPatchNum = 0; //补丁数量
TCHAR szFileName[MAX_PATH] = { L"load" };
DWORD dwPatchAddress[16] = { 0 }; //补丁地址
BYTE byOldData[16] = { 0 }; //补丁处旧数据和新数据
BYTE byNewData[16] = { 0 };
#pragma data_seg()
#pragma comment(linker, "/SECTION:.sdata,ERW")
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////从附加代码中引入的变量,需要补丁程序使用和修正//////////////////////
extern "C" DWORD Appendcode_Start; //附加代码段起始
extern "C" DWORD Appendcode_End; //附加代码段结束
extern "C" DWORD Patch_Data; //需要将补丁数据转存到附加代码中
/////////////////////////////////////////////////////////////////////////////////////////
HANDLE hFile ;//文件句柄
HANDLE hMap; //映射文件句柄
//////////////////////////////添加代码到最后一个区块/////////////////////////////////////
BOOL AddToLastSection(PBYTE lpMemory, DWORD dwFileSize)
{
PIMAGE_NT_HEADERS lpNtHeaders;
PIMAGE_SECTION_HEADER lpSectionHeader;
PIMAGE_SECTION_HEADER lpLastSectionHeader;
DWORD dwNewFileSize; //最终文件大小
DWORD dwFileAlignSize; //原文件对齐后大小
DWORD dwLastSectionAlignSize; //最后区段内存对齐后大小
DWORD dwPatchSize; //补丁大小
DWORD dwFileAlign; //文件对齐粒度
DWORD dwSectionAlign; //内存对齐粒度
//DWORD dwLastSectionSize;
//DWORD dwPatchStart; //指定补丁要复制到的文件偏移起始
PBYTE lpNewFile; //最终文件缓存
DWORD dwSectionNum;
lpNtHeaders = (PIMAGE_NT_HEADERS)( lpMemory + ((PIMAGE_DOS_HEADER)lpMemory)->e_lfanew );
lpSectionHeader = (PIMAGE_SECTION_HEADER)(lpNtHeaders + 1);
dwSectionNum = lpNtHeaders->FileHeader.NumberOfSections ;
lpLastSectionHeader = lpSectionHeader + dwSectionNum - 1;
dwFileAlign = lpNtHeaders->OptionalHeader.FileAlignment;
dwSectionAlign = lpNtHeaders->OptionalHeader.SectionAlignment;
dwFileAlignSize = Align(dwFileSize, dwFileAlign); //求原文件对齐大小
dwPatchSize = ((DWORD)&Appendcode_End ) - ( (DWORD)&Appendcode_Start ); //获得补丁代码大小
dwNewFileSize = Align(dwFileAlignSize + dwPatchSize, dwFileAlign); //获得最终文件对齐后大小
dwLastSectionAlignSize = Align(lpLastSectionHeader->Misc.VirtualSize + dwPatchSize, dwSectionAlign); //获得内存中最后区段大小
lpNewFile = (PBYTE)VirtualAlloc (NULL, dwNewFileSize, MEM_COMMIT, PAGE_READWRITE);
if ( !lpNewFile ) //分配内存失败
return FALSE;
//复制原文件数据
memset(lpNewFile, 0, dwNewFileSize);
memcpy(lpNewFile, lpMemory, dwFileSize);
//复制完毕,关闭映射文件和句柄 (不关闭后面就无法创建新文件,本来想在AddCode关闭,结果试了抛异常什么的还是没用,只能hMap设置成全局变量然后在这关了,实在不雅观啊‘_’)
UnmapViewOfFile(lpMemory);
CloseHandle(hMap);
CloseHandle(hFile);
//复制补丁代码前先转储补丁数据
PBYTE pBuffer = (PBYTE)(&Patch_Data); //指向附加代码补丁数据处
//(*(DWORD*)pBuffer) = dwPatchNum; 原本是这句,但是被优化掉后就变成了mov xxx,0 所以对于变量的读写需要特别注意,一不小心就优化掉了,也不想牺牲效率,这里就换成汇编吧虽然不太好看
_asm
{
pushad
mov eax,dwPatchNum
mov ebx,pBuffer
mov dword ptr [ebx], eax
popad
}
memcpy(pBuffer + 4, dwPatchAddress, 16*sizeof(DWORD) );
pBuffer += 4 + 16*sizeof(DWORD);
memcpy(pBuffer, byOldData, 16);
memcpy(pBuffer+16, byNewData, 16);
//复制补丁代码
memcpy(lpNewFile + dwFileAlignSize, &Appendcode_Start, dwPatchSize);
//修正PE头数据
PIMAGE_NT_HEADERS lpNewNtHeaders;
PIMAGE_SECTION_HEADER lpNewSectionHeader;
PIMAGE_SECTION_HEADER lpNewLastSection;
DWORD* lpNewEntry; //指向新入口处
DWORD OldEntry;
lpNewNtHeaders = (PIMAGE_NT_HEADERS)( lpNewFile + ((PIMAGE_DOS_HEADER)lpNewFile)->e_lfanew );
lpNewSectionHeader = (PIMAGE_SECTION_HEADER)(lpNewNtHeaders + 1);
lpNewLastSection = lpNewSectionHeader + dwSectionNum - 1;
//给最后区段添加读写执行属性
lpNewLastSection->Characteristics |= 0xC0000020;
//修正最后一个区段的偏移量
lpNewLastSection->SizeOfRawData = dwNewFileSize - lpNewLastSection->PointerToRawData;
lpNewLastSection->Misc.VirtualSize = Align( GetValidSize(lpNewFile, lpNewLastSection), dwSectionAlign);//Align(lpNewLastSection->Misc.VirtualSize + dwPatchSize, dwSectionAlign) ;
//修正镜像大小
lpNewNtHeaders->OptionalHeader.SizeOfImage = Align(lpNewLastSection->VirtualAddress + lpNewLastSection->Misc.VirtualSize, dwSectionAlign);
//修正入口地址
OldEntry = lpNewNtHeaders->OptionalHeader.AddressOfEntryPoint;
lpNewNtHeaders->OptionalHeader.AddressOfEntryPoint = OffsetToRVA( (IMAGE_DOS_HEADER *)lpNewFile, dwFileAlignSize) ;
//修正补丁代码跳回OEP的参数
lpNewEntry = (DWORD*)(lpNewFile + dwFileAlignSize + dwPatchSize - 5);
*lpNewEntry = OldEntry - (lpNewNtHeaders->OptionalHeader.AddressOfEntryPoint + dwPatchSize - 1);
//补丁完毕,写回文件
HANDLE hNewFile;
DWORD dwRead;
if (INVALID_HANDLE_VALUE == ( hNewFile = CreateFile (szFileName, GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ , NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
{
VirtualFree(lpNewFile, dwNewFileSize, MEM_RELEASE);
return FALSE;
}
WriteFile(hNewFile, lpNewFile, dwNewFileSize, &dwRead, NULL);
CloseHandle(hNewFile);
//释放内存
VirtualFree(lpNewFile, dwNewFileSize, MEM_RELEASE);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////新建一个区段并插入代码///////////////////////////////////
//如果节表没有多余的空间
BOOL AddToNewSection(PBYTE lpMemory, DWORD dwFileSize)
{
PIMAGE_NT_HEADERS lpNtHeaders;
PIMAGE_SECTION_HEADER lpSectionHeader;
PIMAGE_SECTION_HEADER lpLastSectionHeader;
DWORD dwNewFileSize; //最终文件大小
DWORD dwPatchSize; //补丁大小
DWORD dwPatchSectionSize; //内存中补丁区块的大小
DWORD dwPatchFileSize; //补丁区段文件中大小
DWORD dwFileAlign; //文件对齐粒度
DWORD dwSectionAlign; //内存对齐粒度
PBYTE lpNewFile; //最终文件缓存
DWORD dwSectionNum;
DWORD dwNewHeaderSize; //新头部大小
DWORD dwOldHeaderSize; //老头部大小
DWORD dwSectionSize; //内存中所有区块总大小
BOOL bChange = FALSE; //指示新节表的加入是否影响到文件头大小,如有影响,则需修正各区段偏移
lpNtHeaders = (PIMAGE_NT_HEADERS)(lpMemory + ((PIMAGE_DOS_HEADER)lpMemory)->e_lfanew);
lpSectionHeader = (PIMAGE_SECTION_HEADER)(lpNtHeaders + 1);
dwSectionNum = lpNtHeaders->FileHeader.NumberOfSections;
lpLastSectionHeader = lpSectionHeader + dwSectionNum - 1;
dwFileAlign = lpNtHeaders->OptionalHeader.FileAlignment;
dwSectionAlign = lpNtHeaders->OptionalHeader.SectionAlignment;
dwOldHeaderSize = lpSectionHeader->PointerToRawData;
dwSectionSize = Align(lpLastSectionHeader->VirtualAddress + lpLastSectionHeader->Misc.VirtualSize - Align(dwOldHeaderSize, dwSectionAlign), dwSectionAlign); //内存中区段总大小
//获得补丁相关数据
dwPatchSize = ((DWORD)&Appendcode_End ) - ( (DWORD)&Appendcode_Start ); //获得补丁代码大小
dwPatchSectionSize = Align(dwPatchSize, dwSectionAlign); //内存中新区段对齐大小
dwPatchFileSize = Align(dwPatchSize, dwFileAlign); //文件中新区段对齐大小
//头部是否能增加一个节表
DWORD dwValidSize; //头部当前有效大小
dwValidSize = sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER)*(dwSectionNum + 1) + ((PIMAGE_DOS_HEADER)lpMemory)->e_lfanew ;
if ( Align(dwValidSize + sizeof(IMAGE_SECTION_HEADER), dwFileAlign) > 0x1000 )
return FALSE;
//是否要增加头部大小
dwNewHeaderSize = Align(dwValidSize + sizeof(IMAGE_SECTION_HEADER), dwFileAlign); //新头部大小
if (dwNewHeaderSize > Align(dwValidSize, dwFileAlign) )
bChange = TRUE; //记录头部增加,后面需要修改所有节表偏移
dwNewFileSize = Align (Align(dwFileSize, dwFileAlign) + dwPatchFileSize, dwFileAlign);
lpNewFile = (PBYTE)VirtualAlloc (NULL, dwNewFileSize, MEM_COMMIT, PAGE_READWRITE);
if ( !lpNewFile ) //分配内存失败
return FALSE;
//复制原文件数据
memset(lpNewFile, 0, dwNewFileSize);
memcpy(lpNewFile, lpMemory, dwValidSize); //头部数据复制
//区段数据复制
DWORD dwSize = lpLastSectionHeader->PointerToRawData + lpLastSectionHeader->SizeOfRawData - dwOldHeaderSize; //文件中所有区段总大小
memcpy(lpNewFile + dwNewHeaderSize, lpMemory + lpSectionHeader->PointerToRawData, dwSize);
//复制补丁代码前先转储补丁数据
PBYTE pBuffer = (PBYTE)(&Patch_Data); //指向附加代码补丁数据处
_asm
{
pushad
mov eax,dwPatchNum
mov ebx,pBuffer
mov dword ptr [ebx], eax
popad
}
memcpy(pBuffer + 4, dwPatchAddress, 16*sizeof(DWORD) );
pBuffer += 4 + 16*sizeof(DWORD);
memcpy(pBuffer, byOldData, 16);
memcpy(pBuffer+16, byNewData, 16);
//补丁数据复制
memcpy(lpNewFile + dwNewHeaderSize + dwSize, &Appendcode_Start, dwPatchSize);
//复制完毕,关闭映射文件和句柄
UnmapViewOfFile(lpMemory);
CloseHandle(hMap);
CloseHandle(hFile);
//开始修正PE头
PIMAGE_NT_HEADERS lpNewNtHeaders;
PIMAGE_SECTION_HEADER lpNewSectionHeader;
PIMAGE_SECTION_HEADER lpNewLastSection;
DWORD* lpNewEntry; //指向新入口处
DWORD OldEntry;
lpNewNtHeaders = (PIMAGE_NT_HEADERS)( lpNewFile + ((PIMAGE_DOS_HEADER)lpNewFile)->e_lfanew);
lpNewSectionHeader = (PIMAGE_SECTION_HEADER) (lpNewNtHeaders + 1);
lpNewLastSection = lpNewSectionHeader + dwSectionNum; //此处即指向要创建的新区段
lpNewNtHeaders->FileHeader.NumberOfSections += 1; //添加一个区段
lpNewNtHeaders->OptionalHeader.SizeOfHeaders = dwNewHeaderSize;
lpNewNtHeaders->OptionalHeader.SizeOfImage = dwNewHeaderSize + dwSectionSize + dwPatchSectionSize; //镜像总大小
//根据需要修正节表偏移
if (bChange)
{
PIMAGE_SECTION_HEADER lpTempSection = lpNewSectionHeader;
DWORD dwOffset = dwNewHeaderSize - dwOldHeaderSize;
for (DWORD i=0; i < dwSectionNum; i++, lpTempSection++ )
{
lpTempSection->PointerToRawData += dwOffset;
}
}
//建立一个新节表
lpNewLastSection->Characteristics = 0xC0000020; //读写执行属性添加
lpNewLastSection->VirtualAddress = Align(dwNewHeaderSize, dwSectionAlign) + dwSectionSize;
lpNewLastSection->Misc.VirtualSize = dwPatchSectionSize;
lpNewLastSection->PointerToRawData = dwNewHeaderSize + dwSize;
lpNewLastSection->SizeOfRawData = dwPatchFileSize;
lstrcpyA( (LPSTR)(lpNewLastSection->Name), ".crk");
//修正入口地址
OldEntry = lpNewNtHeaders->OptionalHeader.AddressOfEntryPoint;
lpNewNtHeaders->OptionalHeader.AddressOfEntryPoint = Align(dwNewHeaderSize, dwSectionAlign) + dwSectionSize ;
//修正补丁代码跳回OEP的参数
lpNewEntry = (DWORD*)(lpNewFile + dwNewHeaderSize + dwSize + dwPatchSize - 5);
*lpNewEntry = OldEntry - (lpNewNtHeaders->OptionalHeader.AddressOfEntryPoint + dwPatchSize - 1);
//补丁完毕,写回文件
HANDLE hNewFile;
DWORD dwRead;
if (INVALID_HANDLE_VALUE == ( hNewFile = CreateFile (szFileName, GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ , NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
{
VirtualFree(lpNewFile, dwNewFileSize, MEM_RELEASE);
return FALSE;
}
WriteFile(hNewFile, lpNewFile, dwNewFileSize, &dwRead, NULL);
CloseHandle(hNewFile);
//释放内存
VirtualFree(lpNewFile, dwNewFileSize, MEM_RELEASE);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////添加代码到PE头部///////////////////////////////////////////////
//由于PE头部内存中最大为0x1000字节,所以此方法可能会添加失败
BOOL AddToHeaderSection(PBYTE lpMemory, DWORD dwFileSize)
{
PIMAGE_NT_HEADERS lpNtHeaders;
PIMAGE_SECTION_HEADER lpSectionHeader;
PIMAGE_SECTION_HEADER lpLastSectionHeader;
DWORD dwNewFileSize; //最终文件大小
DWORD dwPatchSize; //补丁大小
DWORD dwFileAlign; //文件对齐粒度
DWORD dwSectionAlign; //内存对齐粒度
PBYTE lpNewFile; //最终文件缓存
DWORD dwSectionNum;
DWORD dwPatchOffset; //补丁代码复制到文件的偏移,也即老头部有效数据的大小
DWORD dwNewHeaderSize; //新头部大小
DWORD dwOldHeaderSize; //老头部大小
DWORD dwSectionSize; //所有区块总大小
lpNtHeaders = (PIMAGE_NT_HEADERS)( lpMemory + ((PIMAGE_DOS_HEADER)lpMemory)->e_lfanew );
lpSectionHeader = (PIMAGE_SECTION_HEADER)(lpNtHeaders + 1);
dwSectionNum = lpNtHeaders->FileHeader.NumberOfSections;
lpLastSectionHeader = lpSectionHeader + dwSectionNum - 1; //获得最后一个区块的节表
dwFileAlign = lpNtHeaders->OptionalHeader.FileAlignment;
dwSectionAlign = lpNtHeaders->OptionalHeader.SectionAlignment;
dwPatchSize = ((DWORD)&Appendcode_End ) - ( (DWORD)&Appendcode_Start ); //获得补丁代码大小
dwOldHeaderSize = lpSectionHeader->PointerToRawData;
//dwPatchOffset = sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER)*(dwSectionNum + 1) + ((PIMAGE_DOS_HEADER)lpMemory)->e_lfanew; //老PE头有效数据大小,附加代码从此放置
//原本是使用上面这种方式求有效大小,但考虑到如果PE已有补丁情况下的兼容,所有直接从头最后面往前搜索以取得大小
PBYTE lpTemp = lpMemory + lpSectionHeader->PointerToRawData - 1;
DWORD dwSize = 0;
while(*lpTemp == 0) { lpTemp--; dwSize++; } //获得可填充数据的大小
dwSize -= sizeof(IMAGE_SECTION_HEADER); //因为可能有个全零的节表,所以减去
dwPatchOffset = lpSectionHeader->PointerToRawData - dwSize ; //老PE头有效数据大小,附加代码从此放置
dwNewHeaderSize = Align(dwPatchOffset + dwPatchSize, dwFileAlign); //获得新头部对齐后大小
if (dwNewHeaderSize > 0x1000)
{
MessageBox (GetActiveWindow() , TEXT("PE头大小不够,请选择其他补丁方式"), NULL, MB_OK);
return FALSE;
}
//最后区段偏移加上大小再减去老PE头大小就等于原文件所有区段的文件大小,再加上新头部大小并对齐就是我们需要的新文件大小
dwSectionSize = Align(lpLastSectionHeader->PointerToRawData + lpLastSectionHeader->SizeOfRawData - dwOldHeaderSize, dwFileAlign);
dwNewFileSize = Align(dwNewHeaderSize + dwSectionSize, dwFileAlign);
lpNewFile = (PBYTE)VirtualAlloc(NULL, dwNewFileSize, MEM_COMMIT, PAGE_READWRITE);
if (!lpNewFile) //分配内存失败
return FALSE;
//复制原文件数据
memset(lpNewFile, 0, dwNewFileSize);
memcpy(lpNewFile, lpMemory, dwPatchOffset); //复制原始PE头
memcpy(lpNewFile + dwNewHeaderSize, lpMemory + dwOldHeaderSize, dwSectionSize); //复制区块数据
//复制完毕,关闭映射文件和句柄 (不关闭后面就无法创建新文件,本来想在AddCode关闭,结果试了抛异常什么的还是没用,只能hMap设置成全局变量然后在这关了,实在不雅观啊‘_’)
UnmapViewOfFile(lpMemory);
CloseHandle(hMap);
CloseHandle(hFile);
//复制补丁代码前先转储补丁数据
PBYTE pBuffer = (PBYTE)(&Patch_Data); //指向附加代码补丁数据处
_asm
{
pushad
mov eax,dwPatchNum
mov ebx,pBuffer
mov dword ptr [ebx], eax
popad
}
memcpy(pBuffer + 4, dwPatchAddress, 16*sizeof(DWORD) );
pBuffer += 4 + 16*sizeof(DWORD);
memcpy(pBuffer, byOldData, 16);
memcpy(pBuffer+16, byNewData, 16);
//复制补丁代码
memcpy(lpNewFile + dwPatchOffset, &Appendcode_Start, dwPatchSize);
//开始对头部数据进行修复
PIMAGE_NT_HEADERS lpNewNtHeaders;
PIMAGE_SECTION_HEADER lpNewSectionHeader;
lpNewNtHeaders = (PIMAGE_NT_HEADERS)(lpNewFile + ((PIMAGE_DOS_HEADER)lpNewFile)->e_lfanew);
lpNewSectionHeader = (PIMAGE_SECTION_HEADER)(lpNewNtHeaders + 1);
//由于文件头部大小增加,节表所有的文件偏移都需要修复,RVA则不变
DWORD dwOffset;
PIMAGE_SECTION_HEADER lpTempSectionHeader = lpNewSectionHeader;
dwOffset = dwNewHeaderSize - dwOldHeaderSize; //计算出需要加上的文件偏移
for (DWORD i=0; i < dwSectionNum; i++, lpTempSectionHeader++)
{
lpTempSectionHeader->PointerToRawData += dwOffset;
}
//修正头部大小
lpNewNtHeaders->OptionalHeader.SizeOfHeaders = dwNewHeaderSize;
//修正入口
DWORD dwOldEntry;
dwOldEntry = lpNewNtHeaders->OptionalHeader.AddressOfEntryPoint;
lpNewNtHeaders->OptionalHeader.AddressOfEntryPoint = dwPatchOffset;
//修正补丁代码的最后一个跳转参数
DWORD *lpNewEntry;
lpNewEntry = (DWORD*)(lpNewFile + dwPatchOffset + dwPatchSize - 5); //指向要修正的参数
*lpNewEntry = dwOldEntry - (dwPatchOffset + dwPatchSize - 1);
//补丁完毕,写回文件
HANDLE hNewFile;
DWORD dwRead;
if (INVALID_HANDLE_VALUE == ( hNewFile = CreateFile (szFileName, GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ , NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
{
VirtualFree(lpNewFile, dwNewFileSize, MEM_RELEASE);
return FALSE;
}
WriteFile(hNewFile, lpNewFile, dwNewFileSize, &dwRead, NULL);
CloseHandle(hNewFile);
//释放内存
VirtualFree(lpNewFile, dwNewFileSize, MEM_RELEASE);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
BOOL BytePatch(PBYTE lpMemory,DWORD dwFileSize)
{
//这里就不需要原来的句柄了,都关掉(其实是因为设置了只读属性,但又不好 加写属性,只好这样,实在不雅观啊啊啊+..+)
UnmapViewOfFile(lpMemory);
CloseHandle(hMap);
CloseHandle(hFile);
HANDLE hNewFile, hNewMap;
PBYTE lpNewMemory;
DWORD num=0; //记录成功补丁的次数
DWORD dwNum;
if (INVALID_HANDLE_VALUE == ( hNewFile = CreateFile (szFileName, GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
return FALSE;
//开始补丁
hNewMap = CreateFileMapping (hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hMap)
{
lpNewMemory = (BYTE *)MapViewOfFile (hNewMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpNewMemory)
{
PBYTE pData=0;
_asm //也没想到什么好办法,只有在用到dwPatchNum的地方都用内联汇编实现了
{
pushad
mov eax,dwPatchNum
mov dwNum, eax
popad
}
for (DWORD i = 0; i < dwNum; i++)
{
pData = (PBYTE)VirtualAddressToPointer( (PIMAGE_DOS_HEADER)lpNewMemory, dwPatchAddress[i]); //将虚拟地址转换成相对的文件指针
if ( *pData == byOldData[i])
{
*pData = byNewData[i];
num++;
}
}
}
}
UnmapViewOfFile(lpNewMemory);
CloseHandle(hNewMap);
CloseHandle(hNewFile);
if (num != dwNum) //与需要补丁的数量比较
{
MessageBox (GetActiveWindow() , TEXT("补丁数不一致,请检查补丁地址"), NULL, MB_OK);
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//由于下面那个switch跳转会因为变量为常量而被优化掉,所以这里使用#pragma指示来取消优化
#pragma optimize("",off)
BOOL AddCode( )
{
DWORD dwFileSize; //文件大小
PBYTE lpMemory; //内存映射指针
if (INVALID_HANDLE_VALUE != ( hFile = CreateFile (szFileName, GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
{
dwFileSize = GetFileSize (hFile, NULL);
if (dwFileSize)
{
hMap = CreateFileMapping (hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMap)
{
lpMemory = (BYTE *)MapViewOfFile (hMap, FILE_MAP_READ, 0, 0, 0);
if (lpMemory)
{
//使用指定方法打补丁
switch(dwTypeOfPatch)
{
case ADD_LAST_SECTION:
if (!AddToLastSection(lpMemory, dwFileSize) )
return FALSE;
break;
case ADD_NEW_SECTION:
if (!AddToNewSection(lpMemory, dwFileSize) )
return FALSE;
break;
case ADD_TO_HEADER:
if (!AddToHeaderSection(lpMemory, dwFileSize) )
return FALSE;
break;
case BYTE_PATCH:
if (!BytePatch(lpMemory, dwFileSize))
return FALSE;
break;
}
return TRUE;
}
else
MessageBox (GetActiveWindow() , TEXT("目标文件打开失败"), NULL, MB_OK);
}
else
MessageBox ( GetActiveWindow() , TEXT("目标文件打开失败"), NULL, MB_OK);
}
}
else
MessageBox (GetActiveWindow() , TEXT("目标文件打开失败"), NULL, MB_OK);
return FALSE;
}
//函数结束,恢复优化
#pragma optimize("",on)
#endif
#include <windows.h>
#include "resource.h"
#include "AddCode.h"
#pragma comment(linker, "/SECTION:.text,ERW") //添加写属性,后面要修正参数
///////////////////////////设置对图标////////////////////////////////
inline void chSETDLGICONS(HWND hWnd, int idi) {
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)
LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
MAKEINTRESOURCE(idi)));
SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)
LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
MAKEINTRESOURCE(idi)));
}
BOOL CALLBACK DialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); //主窗口过程
BOOL IsFileModified( ); //检测文件是否已补丁或损坏
DWORD CRC32(BYTE* ptr,DWORD Size); //获取目标文件CRC32校验值,和本补丁程序存储的校验值进行对比(校验值为PE头前4个字节)
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
{
DialogBoxParam (hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DialogProc, 0);
return 0 ;
}
BOOL CALLBACK DialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bBackup = TRUE;
static TCHAR szBakFileName[MAX_PATH] ;
switch (message)
{
case WM_INITDIALOG:
chSETDLGICONS(hDlg, IDI_ICON1);
CheckDlgButton(hDlg, IDC_BACKUP, BST_CHECKED);
return TRUE;
case WM_PAINT:
return FALSE;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDC_BACKUP: //备份选项
if(SendDlgItemMessage(hDlg, IDC_BACKUP, BM_GETCHECK, 0, 0) == BST_CHECKED)
bBackup = TRUE;
else
bBackup = FALSE;
break;
case IDOK:
if ( !IsFileModified() )
{
MessageBox(hDlg, TEXT("已补丁或文件损坏,放弃"), TEXT("提示"), 0);
break;
}
if (bBackup ) //进行文件备份
{
lstrcpy(szBakFileName,szFileName);
lstrcat(szBakFileName,TEXT(".bak") );
CopyFile(szFileName,szBakFileName,TRUE);
}
if (AddCode( ) ) //为目标PE打补丁(给PE添加代码)
MessageBox(hDlg, TEXT("补丁成功"), TEXT("提示"), 0);
else
MessageBox(hDlg, TEXT("补丁失败"), TEXT("提示"), 0);
break;
case IDCANCEL:
EndDialog(hDlg, 0);
break;
}
return TRUE;
}
return FALSE;
}
////////////////////////////////////////////////////////////////
// 打开文件判断CRC32值是否正确
//
BOOL IsFileModified()
{
PIMAGE_DOS_HEADER pDosHeader=NULL;
PIMAGE_NT_HEADERS pNtHeader=NULL;
PIMAGE_SECTION_HEADER pSecHeader=NULL;
DWORD fileSize,OriginalCRC32,NumberOfBytesRW;
PBYTE pBuffer ;
//打开文件
HANDLE hFile = CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if ( hFile == INVALID_HANDLE_VALUE )
return FALSE;
//获得文件长度 :
fileSize = GetFileSize(hFile,NULL);
if (fileSize == 0xFFFFFFFF)
return FALSE;
pBuffer = new BYTE[fileSize]; // 申请内存,也可用VirtualAlloc等函数申请内存
ReadFile(hFile,pBuffer, fileSize, &NumberOfBytesRW, NULL);//读取文件内容
CloseHandle(hFile); //关闭文件
pDosHeader=(PIMAGE_DOS_HEADER)pBuffer;
///////////////定位到本文件PE头前4个字节读取目标CRC32的值/////////////////////////////
TCHAR szMyName[MAX_PATH];
DWORD dwRead;
GetModuleFileName(NULL, szMyName,MAX_PATH);
HANDLE hMyFile = CreateFile(szMyName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if ( hMyFile == INVALID_HANDLE_VALUE )
{
delete pBuffer;
return FALSE;
}
//定位到PE头前4个字节处并读取
SetFilePointer(hMyFile, 0x3c, 0, FILE_BEGIN);
ReadFile(hMyFile, &OriginalCRC32, 4, &dwRead, NULL);
SetFilePointer(hMyFile, OriginalCRC32-4, 0, FILE_BEGIN);
ReadFile(hMyFile, &OriginalCRC32, 4, &dwRead, NULL);
CloseHandle(hMyFile);
//////////////////////////////////////////////////////////////////////////////////////////
fileSize=fileSize-DWORD(pDosHeader->e_lfanew);//将PE文件头前那部分数据去除
if (CRC32((BYTE*)(pBuffer+pDosHeader->e_lfanew),fileSize) == OriginalCRC32 )
{
delete pBuffer;
return TRUE;
}
else
{
delete pBuffer;
return FALSE;
}
}
////////////////////////////////////////////////////////////////
// 计算字符串的CRC32值
// 参数:欲计算CRC32值字符串的首地址和大小
// 返回值: 返回CRC32值
DWORD CRC32(BYTE* ptr,DWORD Size)
{
DWORD crcTable[256],crcTmp1;
//动态生成CRC-32表
for (int i=0; i<256; i++)
{
crcTmp1 = i;
for (int j=8; j>0; j--)
{
if (crcTmp1&1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L;
else crcTmp1 >>= 1;
}
crcTable[i] = crcTmp1;
}
//计算CRC32值
DWORD crcTmp2= 0xFFFFFFFF;
while(Size--)
{
crcTmp2 = ((crcTmp2>>8) & 0x00FFFFFF) ^ crcTable[ (crcTmp2^(*ptr)) & 0xFF ];
ptr++;
}
return (crcTmp2^0xFFFFFFFF);
}
loader.exe
#include <windows.h>
#include "resource.h"
//动态补丁类型
#define SLEEP_PATCH 1
#define DEBUG_PATCH 2
//动态补丁,最多支持16个补丁地址,特别创建一个段用于补丁工具生成补丁时修正变量
#pragma data_seg(".sdata")
DWORD dwTypeOfPatch = 0; //指示补丁类型
DWORD dwPatchNum = 0 ; //补丁数量
TCHAR szFileName[MAX_PATH] = { 0 };
DWORD dwPatchAddress[16] = { 0 }; //补丁地址
BYTE byOldData[16] = { 0 }; //补丁处旧数据和新数据
BYTE byNewData[16] = { 0 };
#pragma data_seg()
#pragma comment(linker, "/SECTION:.sdata,ERW")
//时间记录
DWORD dwTickCount;
///////////////////////////类型1,利用进程读写机制不断测试补丁位置///////////////////////////
////////////////好处是能无视一些壳,弊端是仅仅是停一段时间检测,可能失败,不稳定//////////////
void Patch1()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
BYTE ReadBuffer = 0;
BOOL bContinueRun=TRUE;
ZeroMemory(&si, sizeof(STARTUPINFO)) ;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)) ;
if( !CreateProcess(szFileName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi) )
{
MessageBox(NULL, TEXT("请确定补丁是否在目标文件目录下."), TEXT("提示"), MB_OK);
return ;
}
DWORD i, dwCount=0;
DWORD dwCurrentTick, OldPro;
while (bContinueRun) {
ResumeThread(pi.hThread);
Sleep(10);
SuspendThread(pi.hThread);
for (i=0; dwPatchAddress[i] ; i++)
{
ReadProcessMemory(pi.hProcess, (LPVOID)dwPatchAddress[i], &ReadBuffer, 1, NULL);
if( byOldData[i] == ReadBuffer ) //判断地址数据是否正确
{
VirtualProtectEx(pi.hProcess, (LPVOID)dwPatchAddress[i], 1, PAGE_EXECUTE_READWRITE, &OldPro);
WriteProcessMemory(pi.hProcess, (LPVOID)dwPatchAddress[i],&byNewData[i], 1,NULL);
dwCount++;
ResumeThread(pi.hThread);
}
}
_asm
{
mov ebx,dwPatchNum
cmp dwCount,ebx
jne _exit
mov bContinueRun,0
_exit:
}
//if (dwCount == dwPatchNum) //所有补丁完毕,退出循环
// bContinueRun = FALSE;
dwCurrentTick = GetTickCount();
if ( (dwCurrentTick - dwTickCount) > 6*1000) //如果10秒还没退出,超时
{
MessageBox( NULL, TEXT("超时,补丁失败,指示的补丁数据可能有错误"), 0, 0);
TerminateProcess(pi.hProcess, 0);
bContinueRun = FALSE; ;
}
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
/////////////////////////////////////////利用调试寄存器打补丁///////////////////////////////////////////////////////
/////////////打此类补丁应在补丁地址第一个地址填上希望中断的地址以确保所有地址数据已解码,以保证补丁正确性///////////
void Patch2()
{
STARTUPINFO si ;
PROCESS_INFORMATION pi ;
ZeroMemory(&si, sizeof(STARTUPINFO)) ;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)) ;
si.cb = sizeof(STARTUPINFO) ;
BOOL WhileDoFlag=TRUE;
BYTE ReadBuffer=0;
if( !CreateProcess(szFileName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi) )
{
MessageBox(NULL, TEXT("请确定补丁是否在目标文件目录下."), TEXT("提示"), MB_OK);
return ;
}
DEBUG_EVENT DBEvent ;
CONTEXT Regs ;
DWORD dwSSCnt , dwNum;
dwSSCnt = 0 ;
Regs.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS ;
//使进程在Single Step模式下运行,每执行一条指令就会给调试进程发送EXCEPTION_SINGLE_STEP
//需要注意的是,收到这个消息后,如果还想继续让程序Single Step下去,是需要重新设置一次SF位的
GetThreadContext(pi.hThread,&Regs);
Regs.EFlags|=0x100;
SetThreadContext(pi.hThread,&Regs);
ResumeThread(pi.hThread);
DWORD i,OldPro,dwCount=0;
while (WhileDoFlag) {
WaitForDebugEvent (&DBEvent, INFINITE);
switch (DBEvent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
switch (DBEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_SINGLE_STEP :
{
++dwSSCnt ;
if (dwSSCnt == 1)
{
//当收到第一个EXCEPTION_SINGLE_STEP异常信号,表示中断在程序的第一条指令,即入口点
//把Dr0设置成程序的入口地址
GetThreadContext(pi.hThread,&Regs);
Regs.Dr0=Regs.Eax;
Regs.Dr7=0x101;
SetThreadContext(pi.hThread,&Regs);
}
else if (dwSSCnt == 2)
{
//第二次中断在起先设置的补丁点,设置硬件断点,后面所有的地址均在运行到此处时补丁
GetThreadContext(pi.hThread, &Regs) ;
Regs.Dr0 = dwPatchAddress[0];
Regs.Dr7 = 0x101 ;
SetThreadContext(pi.hThread, &Regs) ;
}
else if (dwSSCnt == 3)
{
//第三次中断,己到补丁指示的地址
GetThreadContext(pi.hThread, &Regs) ;
Regs.Dr0 = Regs.Dr7 = 0 ;
//从下标1开始才是需要打补丁的地址
for (i=1; dwPatchAddress[i] ; i++)
{
ReadProcessMemory(pi.hProcess, (LPVOID)dwPatchAddress[i], &ReadBuffer, 1, NULL);
if( byOldData[i-1] == ReadBuffer ) //判断地址数据是否正确
{
VirtualProtectEx(pi.hProcess, (LPVOID)dwPatchAddress[i], 1, PAGE_EXECUTE_READWRITE, &OldPro);
WriteProcessMemory(pi.hProcess, (LPVOID)dwPatchAddress[i],&byNewData[i-1], 1,NULL);
dwCount++;
}
}
_asm
{
push eax
mov eax,dwPatchNum
mov dwNum,eax
pop eax
}
if (dwPatchNum != dwNum) //补丁成功数与需要补丁数不同
MessageBox(NULL, TEXT("补丁字节数不一致,补丁可能失败"), TEXT("提示"), 0);
SetThreadContext(pi.hThread, &Regs) ;
}
break ;
}
}
break ;
case EXIT_PROCESS_DEBUG_EVENT :
WhileDoFlag=FALSE;
break ;
}
ContinueDebugEvent(DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE) ;
}
CloseHandle(pi.hProcess) ;
CloseHandle(pi.hThread) ;
}
//////////////////////////////提升当前进程权限(调试权限)///////////////////////////////////
BOOL EnablePrivilege(PCTSTR szPrivilege, BOOL fEnable) {
BOOL fOk = FALSE;
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES,
&hToken)) {
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
LookupPrivilegeValue(NULL, szPrivilege, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
fOk = (GetLastError() == ERROR_SUCCESS);
CloseHandle(hToken);
}
return(fOk);
}
//取消优化以免跳转无效
#pragma optimize("",off)
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
{
dwTickCount = GetTickCount();
EnablePrivilege(SE_DEBUG_NAME, TRUE);
switch(dwTypeOfPatch)
{
case SLEEP_PATCH:
Patch1();
break;
case DEBUG_PATCH:
Patch2();
break;
}
EnablePrivilege(SE_DEBUG_NAME, FALSE);
return 0 ;
}
#pragma optimize("",on)
/*
void Patch2()
{
STARTUPINFO si ;
PROCESS_INFORMATION pi ;
ZeroMemory(&si, sizeof(STARTUPINFO)) ;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)) ;
si.cb = sizeof(STARTUPINFO) ;
BOOL WhileDoFlag=TRUE;
BYTE ReadBuffer={0};
BYTE dwINT3code[1]={0xCC};
BYTE dwOldbyte[1]={0};
HANDLE hFile;
DWORD dwEntry, dwRead;
IMAGE_NT_HEADERS stNtHeaders;
if (INVALID_HANDLE_VALUE != ( hFile = CreateFile (szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL) ) )
{
dwFileSize = GetFileSize (hFile, NULL);
if (dwFileSize)
{
SetFilePointer(hFile, 0x3c, 0, FILE_BEGIN);
ReadFile(hFile, &dwEntry, 4, &dwRead, NULL);
SetFilePointer(hFile, dwEntry, 0, FILE_BEGIN);
ReadFile(hFile, &stNtHeaders, sizeof(IMAGE_NT_HEADERS), &dwRead, NULL);
dwEntry = stNtHeaders.OptionalHeader.AddressOfEntryPoint;
dwEntry+= stNtHeaders.OptionalHeader.ImageBase;
CloseHandle(hFile);
}
}
else
{
MessageBox(NULL, TEXT("请确定补丁是否在目标文件目录下."), NULL, MB_OK);
return ;
}
if( !CreateProcess(SZFILENAME, NULL, NULL, NULL, FALSE, DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi) )
{
MessageBox(NULL, TEXT("请确定补丁是否在目标文件目录下."), NULL, MB_OK);
return ;
}
DEBUG_EVENT DBEvent ;
CONTEXT Regs ;
DWORD dwState,Oldpp;
Regs.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS ;
DWORD i, dwCount=0;
DWORD dwCurrentTick, OldPro;
while (WhileDoFlag) {
WaitForDebugEvent (&DBEvent, INFINITE);
dwState = DBG_EXCEPTION_NOT_HANDLED ;
switch (DBEvent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
//如果进程开始,则将断点地址的代码改为INT3中断,同时备份原机器码
ReadProcessMemory(pi.hProcess, (LPCVOID)(dwEntry), &dwOldbyte, sizeof(dwOldbyte), NULL) ;
VirtualProtectEx(pi.hProcess, (LPVOID)dwEntry, 1, PAGE_EXECUTE_READWRITE, &Oldpp);
WriteProcessMemory(pi.hProcess, (LPVOID)dwEntry,&dwINT3code, 1,NULL); //打补丁
dwState = DBG_CONTINUE ;
break;
case EXIT_PROCESS_DEBUG_EVENT :
WhileDoFlag=FALSE;
break ;
case EXCEPTION_DEBUG_EVENT:
switch (DBEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT:
{
GetThreadContext(pi.hThread, &Regs) ;
if(Regs.Eip==dwEntry+1){
//中断触发异常事件,恢复原机器码,并读出数据
Regs.Eip--;
WriteProcessMemory(pi.hProcess, (LPVOID)dwEntry,&dwOldbyte, 1,NULL);
for (i=0; dwPatchAddress[i] ; i++)
{
ReadProcessMemory(pi.hProcess, (LPVOID)dwPatchAddress[i], &ReadBuffer, 1, NULL);
if( byOldData[i] == ReadBuffer ) //判断地址数据是否正确
{
VirtualProtectEx(pi.hProcess, (LPVOID)dwPatchAddress[i], 1, PAGE_EXECUTE_READWRITE, &OldPro);
WriteProcessMemory(pi.hProcess, (LPVOID)dwPatchAddress[i],&byNewData[i], 1,NULL);
dwCount++;
ResumeThread(pi.hThread);
}
}
SetThreadContext(pi.hThread, &Regs) ;
}
dwState = DBG_CONTINUE ;
break;
}
}
break;
}
ContinueDebugEvent(DBEvent.dwProcessId, DBEvent.dwThreadId, dwState) ;
} //.end while
CloseHandle(pi.hProcess) ;
CloseHandle(pi.hThread) ;
}*/