可以生成加载器补丁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