能力值:
( LV3,RANK:20 )
9 楼
我这有一段为程序加CRC校验的,代码是DELPHI的
unit AsmPatch;
interface
uses
Windows, SysUtils, Classes, PEStruct;
type
{ 文件处理参数 }
TBakPath = (bpWindowsDir, bpSystemDir, bpWorkDir, bpTempDir);
TDlgIcon = (diNone, diStop, diInformationx, diWarning);
TCanRepairAct = (crAutoRepair, crInfoOk, crQuestionYesNo
, crQuestionYesNoCancel);
TCannotRepairAct = (cnQuit, cnInfoOkContinue, cnInfoOkQuit, cnQuestionYesNo);
TCrcErrorAct = (ceQuit, ceInfoOkContinue, ceInfoOkQuit, ceQuestionYesNo);
TRepairSuccAct = (rsQuit, rsExcute, rsInfoOkExcute, rsInfoOkQuit);
TRepairFailAct = (rfQuit, rfInfoOkQuit);
TDlgParam = record
Text: string;
Caption: string;
Icon: TDlgIcon;
end;
PPatchParam = ^TPatchParam;
TPatchParam = record
FileName: WideString;
BackupOrgFile: Boolean;
AllowRegQuery: Boolean;
RegKey: HKEY;
RegSubKey: string;
RegValue: string;
AllowRepair: Boolean;
BakPath: TBakPath;
BakSubDir: string;
BakName: string;
CanRepair: TCanRepairAct;
CanRepairDlg: TDlgParam;
RepairSucc: TRepairSuccAct;
RepairSuccDlg: TDlgParam;
RepairFail: TRepairFailAct;
RepairFailDlg: TDlgParam;
CannotRepair: TCannotRepairAct;
CannotRepairDlg: TDlgParam;
CrcError: TCrcErrorAct;
CrcErrorDlg: TDlgParam;
end;
{ 文件处理结果 }
TPatchResult = (prSuccess, prAlreadyPatched, prOpenError, prWriteError
, prFileFormatError, prOtherError);
PPatchInfo = ^TPatchInfo;
TPatchInfo = record
FileName: string;
BakFileName: string;
OrgSize: Cardinal;
NewSize: Cardinal;
AddSize: Cardinal;
Result: TPatchResult;
end;
const
MB_NONE = 0;
ctDlgIcon: array[TDlgIcon] of DWORD =
(MB_NONE, MB_ICONSTOP, MB_ICONINFORMATION, MB_ICONWARNING);
ctCanRepair: array[TCanRepairAct] of DWORD =
(MB_NONE, MB_OK, MB_YESNO, MB_YESNOCANCEL);
ctCannotRepair: array[TCannotRepairAct] of DWORD =
(MB_NONE, MB_OK, MB_OK, MB_YESNO);
ctCrcError: array[TCrcErrorAct] of DWORD =
(MB_NONE, MB_OK, MB_OK, MB_YESNO);
ctRepairSucc: array[TRepairSuccAct] of DWORD =
(MB_NONE, MB_NONE, MB_OK, MB_OK);
ctRepairFail: array[TRepairFailAct] of DWORD =
(MB_NONE, MB_OK);
function FilePatch(Param: TPatchParam): TPatchInfo;
implementation
//..uses
// PEStruct;
//{$R ResTool.RES}
const
MAX_PATH = $400;
csSectionChar = $0E0000020; //节属性代码(可执行、可读、可写)
csSectionName = 'CODE';
csFileFlag = 'CRC64';
csBakExt = '.bak';
csSizeOfExeExt = 4; //EXE文件扩展名长度
csFileFlagLen = 16;
csToolDataOffset = $A00; //修复工具中数据块位置
{ 附加到原PE文件尾的数据结构 }
type
TDataOffset = type DWORD; //内部数据偏移
TDlgData = packed record
Text: TDataOffset;
Caption: TDataOffset;
uType: DWORD;
end;
PAddData = ^TAddData;
TAddData = packed record
Flag: array[0..csFileFlagLen - 1] of Char; //文件标志
Xor1: DWORD; //数据加密
Pos1: TDataOffset;
Len1: DWORD;
Xor2: DWORD;
Pos2: TDataOffset;
Len2: DWORD;
OEP: DWORD; //原代码入口
CRCAddr: DWORD; //CRC存放地址
CRC: DWORD; //原始CRC
FileSize: DWORD; //原文件长度
iAddress: DWORD; //原Import表
AllowRegQuery: Boolean; //允许查询注册表
RegKey: HKEY; //主键
RegSubKey: TDataOffset; //子键
RegValue: TDataOffset; //值(DWORD)非0不进行校验
AllowRepair: Boolean; //允许修复
BakPath: TBakPath; //备份文件主路径
BakSubDir: TDataOffset; //备份文件子路径
BakName: TDataOffset; //备份文件名
RepairCode: TDataOffset; //用于修复的代码
RepairCodeSize: DWORD; //代码长度
CanRepair: TCanRepairAct; //可以修复
CanRepairDlg: TDlgData;
CannotRepair: TCannotRepairAct; //不能修复
CannotRepairDlg: TDlgData;
CrcError: TCrcErrorAct; //Crc32校验错(不允许修复)
CrcErrorDlg: TDlgData;
end;
{ 修复工具内部数据结构 }
const
csMaxDlgCaptionLen = 31;
csMaxDlgTextLen = 127;
type
PToolDlgData = ^TToolDlgData;
TToolDlgData = packed record
Text: array[0..csMaxDlgTextLen] of Char;
Caption: array[0..csMaxDlgCaptionLen] of Char;
uType: DWORD;
end;
PToolData = ^TToolData;
TToolData = packed record
RepairSucc: TRepairSuccAct; //修复成功
RepairSuccDlg: TToolDlgData;
RepairFail: TRepairFailAct; //修复失败
RepairFailDlg: TToolDlgData;
end;
const
SizeOfTAddData = SizeOf(TAddData); //附加数据长度
var
ResStream: TResourceStream; //文件修复工具(资源中)
AsmAdd_Addr: DWORD;
Fake_tbl_Addr: DWORD;
Fake_tbl_End: DWORD;
Repair_Addr: DWORD;
Repair_End: DWORD;
type
TCRC32Table = array[0..255] of DWORD;
var
CRC32Table: TCRC32Table;
procedure Make_CRC32Table;
asm
PUSH EBX
MOV EDX, OFFSET CRC32Table
XOR EBX, EBX
@MakeCRC32Loop:
CMP EBX, $100
JE @MakeCRC32_Succ
MOV EAX, EBX
MOV ECX, 8
@MakeLoop:
TEST EAX, 1
JZ @MakeIsZero
SHR EAX, 1
XOR EAX, $EDB88320
JMP @MakeNext
@MakeIsZero:
SHR EAX, 1
@MakeNext:
LOOP @MakeLoop
MOV DWORD PTR [EDX], EAX
ADD EDX, 4
INC EBX
JMP @MakeCRC32Loop
@MakeCRC32_Succ:
POP EBX
RET
end;
function CRC32Calc(CRC: DWORD; Data: Pointer; DataLen: DWORD): DWORD;
asm
OR EDX, EDX //Data = nil?
JE @Exit
JECXZ @Exit //DataLen = 0?
PUSH ESI
PUSH EBX
MOV ESI, OFFSET CRC32Table
@Upd:
MOVZX EBX, AL //CRC32
XOR BL, [EDX]
SHR EAX, 8
AND EAX, $00FFFFFF
XOR EAX, [EBX + ESI]
INC EDX
LOOP @Upd
POP EBX
POP ESI
@Exit:
RET
end;
//-----------------------------------------------//
//附加到PE文件尾的代码(起始) //
//-----------------------------------------------//
//主代码
procedure AsmAdd;
asm
MOV EAX, OFFSET @Start
MOV AsmAdd_Addr, EAX
MOV EAX, OFFSET @Fake_tbl
MOV Fake_tbl_Addr, EAX
MOV EAX, OFFSET @Fake_tbl_End
MOV Fake_tbl_End, EAX
MOV EAX, OFFSET @Repair_Code_Start
MOV Repair_Addr, EAX
MOV EAX, OFFSET @Repair_Code_End
MOV Repair_End, EAX
RET
@Start: { 代码入口 }
PUSHAD
CALL @Delta
@Delta:
POP EBP //得到实际EIP
SUB EBP, OFFSET @Delta //计算地址偏移修正
LEA EDI, [EBP + @Start]
SUB EDI, SizeOfTAddData //附加数据地址
MOV DWORD PTR [EBP + @AddData], EDI
MOV ECX, [EDI].TAddData.Len1
MOV ESI, EDI
ADD ESI, [EDI].TAddData.Pos1
MOV EAX, [EDI].TAddData.Xor1
CALL @DataDecode
MOV ECX, [EDI].TAddData.Len2
MOV ESI, EDI
ADD ESI, [EDI].TAddData.Pos2
MOV EAX, [EDI].TAddData.Xor2
CALL @DataDecode
PUSH 0
CALL DWORD PTR [EBP + @_GetModuleHandle] //获得应用程序模块句柄
MOV DWORD PTR [EBP + @hInstance], EAX
CALL @QueryReg //查询注册表
JC @JmpToOrgCode
//-----------------------------------------------//
//CRC32校验(准备工作) //
//-----------------------------------------------//
@DoCRC32Calc:
CALL @MakeCRC32Table //初始化CRC32校验表
JC @Quit
MOV EDI, DWORD PTR [EBP + @AddData] //处理参数
@GetFileName: { 应用程序名 }
PUSH MAX_PATH
PUSH LMEM_FIXED
CALL DWORD PTR [EBP + @_LocalAlloc] //分配临时内存保存文件名
OR EAX, EAX
JZ @Quit
MOV DWORD PTR [EBP + @lpFileName], EAX
PUSH MAX_PATH
MOV EBX, DWORD PTR [EBP + @lpFileName]
PUSH EBX
MOV EBX, DWORD PTR [EBP + @hInstance]
PUSH EBX
CALL DWORD PTR [EBP + @_GetModuleFileName] //获得应用程序名
OR EAX, EAX
JZ @QUIT
MOV AL, [EDI].TAddData.AllowRepair //允许修复?
OR AL, AL
JZ @OpenFile
Call @PrepairBackup //准备备份文件名等
JC @Quit
//-----------------------------------------------//
//CRC32校验 //
//-----------------------------------------------//
@OpenFile: { 打开并映射应用程序文件 }
PUSH 0
PUSH FILE_ATTRIBUTE_NORMAL
PUSH OPEN_EXISTING
PUSH 0
PUSH FILE_SHARE_READ
PUSH GENERIC_READ
MOV EAX, DWORD PTR [EBP + @lpFileName]
PUSH EAX
CALL DWORD PTR [EBP + @_CreateFile] //打开文件
CMP EAX, INVALID_HANDLE_VALUE
JZ @Quit
MOV DWORD PTR [EBP + @hFile], EAX //文件句柄
PUSH 0
PUSH 0
PUSH 0
PUSH PAGE_READONLY
PUSH 0
PUSH EAX
CALL DWORD PTR [EBP + @_CreateFileMapping] //创建映射文件
OR EAX, EAX
JZ @Quit
MOV DWORD PTR [EBP + @hFileMap], EAX //映射文件句柄
PUSH 0
PUSH 0
PUSH 0
PUSH FILE_MAP_READ
PUSH EAX
CALL DWORD PTR [EBP + @_MapViewOfFile] //映射文件到内存
OR EAX, EAX
JZ @Quit
MOV DWORD PTR [EBP + @lpFileMapping], EAX //内存指针
PUSH FILE_END
PUSH 0
PUSH 0
MOV EAX, DWORD PTR [EBP + @hFile]
PUSH EAX
CALL DWORD PTR [EBP + @_SetFilePointer] //设置文件指针
CMP EAX, -1
JZ @Quit
MOV DWORD PTR [EBP + @dwFileSize], EAX //文件长度
PUSH FILE_BEGIN
PUSH 0
PUSH 0
MOV EAX, DWORD PTR [EBP + @hFile]
PUSH EAX
CALL DWORD PTR [EBP + @_SetFilePointer] //设置文件指针
MOV EAX, DWORD PTR [EBP + @dwFileSize]
CMP EAX, [EDI].TAddData.FileSize //文件长度比较
JNZ @CRCError
XOR EAX, EAX //CRC
MOV EDX, DWORD PTR [EBP + @lpFileMapping] //内存指针
MOV ECX, [EDI].TAddData.CRCAddr //数据长度
CALL @CRC32Calc
MOV EDX, DWORD PTR [EBP + @lpFileMapping]
ADD EDX, [EDI].TAddData.CRCAddr
ADD EDX, 4 //SizeOf DWORD
MOV ECX, DWORD PTR [EBP + @dwFileSize] //文件长度
SUB ECX, [EDI].TAddData.CRCAddr
SUB ECX, 4 //SizeOf DWORD
CALL @CRC32Calc
CMP EAX, [EDI].TAddData.CRC
JNZ @CRCError //不相等
@CRCPassed: { CRC32校验通过 }
MOV AL, [EDI].TAddData.AllowRepair //允许修复?
OR AL, AL
JZ @Quit
CALL @CreateBackup //创建备份文件
JMP @Quit
//-----------------------------------------------//
//CRC32错误处理 //
//-----------------------------------------------//
@CRCError:
MOV AL, [EDI].TAddData.AllowRepair //允许修复
OR AL, AL
JZ @ErrorHint
CALL @CheckBackup
JNC @CannotRepair
@CanRepair: { 可以自动修复 }
MOV AL, BYTE PTR [EDI].TAddData.CanRepair
CMP AL, crAutoRepair //自动修复
JZ @BeginRepair
MOV EAX, [EDI].TAddData.CanRepairDlg.uType
PUSH EAX
MOV EAX, EDI
ADD EAX, [EDI].TAddData.CanRepairDlg.Caption
PUSH EAX
MOV EAX, EDI
ADD EAX, [EDI].TAddData.CanRepairDlg.Text
PUSH EAX
PUSH 0
CALL DWORD PTR [EBP + @_MessageBox] //弹出提示窗口
CMP EAX, IDCANCEL //Cancel
JZ @DoQuit
CMP EAX, IDNO //No
JZ @DoReturn
@BeginRepair: { 开始修复 }
CALL @Repair
JC @Quit
JMP @DoQuit
@CannotRepair: { 无法自动修复 }
MOV AL, BYTE PTR [EDI].TAddData.CannotRepair
CMP AL, cnQuit //直接退出
JZ @DoQuit
MOV EAX, [EDI].TAddData.CannotRepairDlg.uType
PUSH EAX
MOV EAX, EDI
ADD EAX, [EDI].TAddData.CannotRepairDlg.Caption
PUSH EAX
MOV EAX, EDI
ADD EAX, [EDI].TAddData.CannotRepairDlg.Text
PUSH EAX
PUSH 0
CALL DWORD PTR [EBP + @_MessageBox] //弹出提示窗口
CMP EAX, IDNO //No 中断运行
JZ @DoQuit
MOV EAX, DWORD PTR [EDI].TAddData.CannotRepair
CMP EAX, cnInfoOkQuit //直接退出
JZ @DoQuit
JMP @DoReturn //Yes 或 cnInfoOkContinue 回到原代码入口
@ErrorHint: { 不支持修复功能 }
MOV AL, BYTE PTR [EDI].TAddData.CrcError
CMP AL, cnQuit //直接退出
JZ @DoQuit
MOV EAX, [EDI].TAddData.CrcErrorDlg.uType
PUSH EAX
MOV EAX, EDI
ADD EAX, [EDI].TAddData.CrcErrorDlg.Caption
PUSH EAX
MOV EAX, EDI
ADD EAX, [EDI].TAddData.CrcErrorDlg.Text
PUSH EAX
PUSH 0
CALL DWORD PTR [EBP + @_MessageBox] //弹出提示窗口
// CMP EAX, IDNO //No 中断运行
JZ @DoQuit
MOV EAX, DWORD PTR [EDI].TAddData.CrcError
CMP EAX, ceInfoOkQuit //直接退出
JZ @DoQuit
// JMP @DoReturn //Yes 或 cnInfoOkContinue 回到原代码入口
@DoQuit: //直接退出
MOV EAX, 1
MOV DWORD PTR [EBP + @bIsExit], EAX
JMP @Quit
@DoReturn: //转到原程序入口
XOR EAX, EAX
MOV DWORD PTR [EBP + @bIsExit], EAX
JMP @Quit
//-----------------------------------------------//
//主代码执行结束 //
//-----------------------------------------------//
@Quit:
@FreeMem: { 释放内存 }
LEA ESI, [EBP + @lpMemTableStart] //指针表起始
LEA EDI, [EBP + @lpMemTableEnd] //指针表结束
@FreeMemLoop:
CMP ESI, EDI //已结束?
JGE @UnmapView
MOV EAX, [ESI]
ADD ESI, 4 //下一个
OR EAX, EAX
JZ @FreeMemLoop
PUSH EAX
CALL DWORD PTR [EBP + @_LocalFree]
JMP @FreeMemLoop
@UnmapView: { 关闭映射 }
LEA ESI, [EBP + @MappingTableStart] //指针表起始
LEA EDI, [EBP + @MappingTableEnd] //指针表结束
@UnmapViewLoop:
CMP ESI, EDI //已结束?
JGE @CloseAllHandle
MOV EAX, [ESI]
ADD ESI, 4 //下一个
OR EAX, EAX
JZ @UnmapViewLoop
PUSH EAX
CALL DWORD PTR [EBP + @_UnmapViewOfFile]
JMP @UnmapViewLoop
@CloseAllHandle:{ 关闭全部句柄 }
LEA ESI, [EBP + @HandleTableStart] //句柄表起始
LEA EDI, [EBP + @HandleTableEnd] //句柄表结束
@CloseAllHandleLoop:
CMP ESI, EDI //已结束?
JGE @ExitAddCode
MOV EAX, [ESI]
ADD ESI, 4 //下一个
OR EAX, EAX
JZ @CloseAllHandleLoop
PUSH EAX
CALL DWORD PTR [EBP + @_CloseHandle]
JMP @CloseAllHandleLoop
@ExitAddCode: //退出附加代码
MOV EAX, DWORD PTR [EBP + @bIsExit]
OR EAX, EAX //退出进程?
JZ @JmpToOrgCode
@ExitProcess: //结束程序
MOV [ESP + $1C], EBP //保存地址修正到堆栈中的EAX部分
POPAD
PUSH 0
CALL DWORD PTR [EAX + @_ExitProcess]
@JmpToOrgCode: //转到原代码入口执行
MOV EDI, DWORD PTR [EBP + @AddData]
CALL @ProcessImports //处理原Import表
JC @ExitProcess
MOV EAX, DWORD PTR [EBP + @HInstance] //模块基址
ADD EAX, [EDI].TAddData.OEP //原代码入口
MOV [ESP + $1C], EAX //保存入口到堆栈中的EAX部分
POPAD //恢复现场
JMP EAX //转到原代码入口
//-----------------------------------------------//
//常量定义 //
//-----------------------------------------------//
@szBakExt: DB 'BK.DAT', 0
@szToolName: DB 'RestTool.EXE', 0
//-----------------------------------------------//
//变量定义 //
//-----------------------------------------------//
//内部变量
@Hinstance: DD 0
@DllHandle: DD 0
//字符串指针
@lpMemTableStart:
@lpFileName: DD 0
@lpBakName: DD 0
@lpBakExeName: DD 0
@lpToolName: DD 0
@lpParam: DD 0
@lpCRC32_Table: DD 0
@lpMemTableEnd:
//文件句柄
@HandleTableStart:
@hFileMap: DD 0
@hFile: DD 0
@hBakFileMap: DD 0
@hBakFile: DD 0
@hToolFile: DD 0
@HandleTableEnd:
//映象视图
@MappingTableStart:
@lpFileMapping: DD 0
@lpBakFileMapping: DD 0
@MappingTableEnd:
//其它变量
@dwFileSize: DD 0
@dwBakFileSize: DD 0
@dwOrgFileCRC: DD 0
@dwBytesWritten: DD 0
@HKEY: DD 0
@dwType: DD 0
@cbData: DD 4 //注册表键值缓冲区为4字节
@dwRegValue: DD 0
@bIsExit: DD 0
@AddData: DD 0
//-----------------------------------------------//
//自定义的Import表 //
//-----------------------------------------------//
@Fake_tbl:
@Kernel32Api_tbl: DD OFFSET @Kernel32Api
DD 0, 0
@Kernel32Dll: DD OFFSET @szKernel32
@Kernel32Api_tbl1: DD OFFSET @Kernel32Api
@User32Api_tbl: DD OFFSET @User32Api
DD 0, 0
@User32Dll: DD OFFSET @szUser32
@User32Api_tbl1: DD OFFSET @User32Api
@Shell32Api_tbl: DD OFFSET @Shell32Api
DD 0, 0
@Shell32Dll: DD OFFSET @szShell32
@Shell32Api_tbl1: DD OFFSET @Shell32Api
@AdvApi32Api_tbl: DD OFFSET @AdvApi32Api
DD 0, 0
@AdvApi32Dll: DD OFFSET @szAdvApi32
@AdvApi32Api_tbl1: DD OFFSET @AdvApi32Api
DD 0, 0, 0, 0, 0 //结束
@Lookup_tbl: //地址表
@Kernel32Api:
@_GetProcAddress: DD OFFSET @szGetProcAddress
@_LoadLibrary: DD OFFSET @szLoadLibrary
@_GetModuleHandle: DD OFFSET @szGetModuleHandle
@_GetModuleFileName: DD OFFSET @szGetModuleFileName
@_FreeLibrary: DD OFFSET @szFreeLibrary
@_ExitProcess: DD OFFSET @szExitProcess
@_LocalAlloc: DD OFFSET @szLocalAlloc
@_LocalFree: DD OFFSET @szLocalFree
@_CreateFile: DD OFFSET @szCreateFile
@_SetFilePointer: DD OFFSET @szSetFilePointer
@_CloseHandle: DD OFFSET @szCloseHandle
@_CreateFileMapping: DD OFFSET @szCreateFileMapping
@_MapViewOfFile: DD OFFSET @szMapViewOfFile
@_UnmapViewOfFile: DD OFFSET @szUnmapViewOfFile
@_WriteFile: DD OFFSET @szWriteFile
@_DeleteFile: DD OFFSET @szDeleteFile
@_CreateDirectory: DD OFFSET @szCreateDirectory
@_GetTempPath: DD OFFSET @szGetTempPath
@_GetSystemDirectory: DD OFFSET @szGetSystemDirectory
@_GetWindowsDirectory: DD OFFSET @szGetWindowsDirectory
@_WinExec: DD OFFSET @szWinExec
@_lstrcpy: DD OFFSET @szlstrcpy
@_lstrcpyn: DD OFFSET @szlstrcpyn
@_lstrcat: DD OFFSET @szlstrcat
@_lstrlen: DD OFFSET @szlstrlen
DD 0
@User32Api:
@_MessageBox: DD OFFSET @szMessageBox
DD 0
@Shell32Api:
@_ShellExecute: DD OFFSET @szShellExecute
DD 0
@Advapi32Api:
@_RegOpenKeyEx: DD OFFSET @szRegOpenKeyEx
@_RegQueryValueEx: DD OFFSET @szRegQueryValueEx
@_RegCloseKey: DD OFFSET @szRegCloseKey
DD 0
@Name_tbl: //名字表
@szKernel32: DB 'kernel32.dll', 0
@szGetProcAddress: DW 0
DB 'GetProcAddress', 0
@szLoadLibrary: DW 0
DB 'LoadLibraryA', 0
@szGetModuleHandle: DW 0
DB 'GetModuleHandleA', 0
@szGetModuleFileName: DW 0
DB 'GetModuleFileNameA', 0
@szFreeLibrary: DW 0
DB 'FreeLibrary', 0
@szExitProcess: DW 0
DB 'ExitProcess', 0
@szLocalAlloc: DW 0
DB 'LocalAlloc', 0
@szLocalFree: DW 0
DB 'LocalFree', 0
@szCreateFile: DW 0
DB 'CreateFileA', 0
@szSetFilePointer: DW 0
DB 'SetFilePointer', 0
@szCloseHandle: DW 0
DB 'CloseHandle', 0
@szCreateFileMapping: DW 0
DB 'CreateFileMappingA', 0
@szMapViewOfFile: DW 0
DB 'MapViewOfFile', 0
@szUnmapViewOfFile: DW 0
DB 'UnmapViewOfFile', 0
@szWriteFile: DW 0
DB 'WriteFile', 0
@szDeleteFile: DW 0
DB 'DeleteFileA', 0
@szCreateDirectory: DW 0
DB 'CreateDirectoryA', 0
@szGetTempPath: DW 0
DB 'GetTempPathA', 0
@szGetSystemDirectory: DW 0
DB 'GetSystemDirectoryA', 0
@szGetWindowsDirectory: DW 0
DB 'GetWindowsDirectoryA', 0
@szWinExec: DW 0
DB 'WinExec', 0
@szlstrcpy: DW 0
DB 'lstrcpyA', 0
@szlstrcpyn: DW 0
DB 'lstrcpynA', 0
@szlstrcat: DW 0
DB 'lstrcatA', 0
@szlstrlen: DW 0
DB 'lstrlenA', 0
@szUser32: DB 'user32.dll', 0
@szMessageBox: DW 0
DB 'MessageBoxA', 0
@szShell32: DB 'shell32.dll', 0
@szShellExecute: DW 0
DB 'ShellExecuteA', 0
@szAdvapi32: DB 'advapi32.dll', 0
@szRegOpenKeyEx: DW 0
DB 'RegOpenKeyExA', 0
@szRegQueryValueEx: DW 0
DB 'RegQueryValueExA', 0
@szRegCloseKey: DW 0
DB 'RegCloseKey', 0
@Fake_tbl_End:
//-----------------------------------------------//
//内部子过程 //
//-----------------------------------------------//
{ 数据解密子过程 }
//ESI -> 数据块地址
//EAX -> XOR 值
//ECX -> 长度
@DataDecode:
@DataXor:
MOV EBX, [ESI]
OR EBX, EBX
JZ @XorZero
XOR [ESI], EAX
@XorZero:
ADD ESI, 4
LOOP @DataXor
RET
{ 查询注册表键值确定是否允许CRC32校验 }
@QueryReg: { 查询注册表 }
@RegOpen:
MOV EDI, DWORD PTR [EBP + @AddData]
MOV AL, BYTE PTR [EDI].TAddData.AllowRegQuery
OR AL, AL
JZ @Reg_Succ
LEA EAX, [EBP + @hKey]
PUSH EAX
PUSH KEY_READ
PUSH 0
MOV EAX, EDI
ADD EAX, [EDI].TAddData.RegSubKey
PUSH EAX
MOV EAX, [EDI].TAddData.RegKey
PUSH EAX
CALL DWORD PTR [EBP + @_RegOpenKeyEx] //打开注册表子键
CMP EAX, ERROR_SUCCESS
JNZ @Reg_Succ
@QueryValue:
LEA EAX, [EBP + @cbData]
PUSH EAX
LEA EAX, [EBP + @dwRegValue]
PUSH EAX
LEA EAX, [EBP + @dwType]
PUSH EAX
PUSH 0
MOV EAX, EDI
ADD EAX, [EDI].TAddData.RegValue
PUSH EAX
MOV EAX, DWORD PTR [EBP + @hKey]
PUSH EAX
CALL DWORD PTR [EBP + @_RegQueryValueEx] //查询键值
CMP EAX, ERROR_SUCCESS
JZ @RegClose
XOR EAX, EAX
MOV DWORD PTR [EBP + @dwRegValue], EAX
@RegClose:
MOV EAX, DWORD PTR [EBP + @hKey]
PUSH EAX
CALL DWORD PTR [EBP + @_RegCloseKey] //关闭注册表
MOV EAX, DWORD PTR [EBP + @dwRegValue]
OR EAX, EAX
JNZ @Reg_Fail
@Reg_Succ:
CLC
RET
@Reg_Fail:
STC
RET
{ 处理原Import表 }
@ProcessImports:
PUSH EDI
MOV ESI, [EDI].TAddData.iAddress
OR ESI, ESI
JZ @Import_Succ
MOV EDX, DWORD PTR [EBP + @HInstance]
ADD ESI, EDX
@Dir_loop:
CALL @ProcessImportDir
JC @Import_Fail
ADD ESI, SizeOfImportDir
CMP DWORD PTR [ESI].TImageImportDirectory.Name, 0
JNZ @Dir_loop
@Import_Succ:
CLC
POP EDI
RET
@Import_Fail:
STC
POP EDI
RET
{ 处理Import表目录 }
//ESI -> IMPORT_DIRECTORY_VA
//EDX -> IMAGEBASE
@ProcessImportDir:
MOV ECX, [ESI].TImageImportDirectory.Misc.OriginalFirstThunk //ECX->原地址表
MOV EDI, [ESI].TImageImportDirectory.FirstThunk //EDI->结果地址表
OR ECX, ECX
JNZ @lr_ok
MOV ECX, EDI
@lr_ok:
ADD ECX, EDX
ADD EDI, EDX
MOV EAX, [ESI].TImageImportDirectory.Name //EAX->Dll Name
ADD EAX, EDX
PUSH ECX
PUSH EDX
PUSH EAX
CALL DWORD PTR [EBP + @_LoadLibrary]
POP EDX
POP ECX
OR EAX, EAX
JZ @iret_error
MOV DWORD PTR [EBP + @DllHandle], EAX
@lookup_loop:
MOV EBX, [ECX]
OR EBX, EBX
JZ @iret_success
TEST EBX, $80000000 //按序号输入
JNZ @import_by_ordinal
ADD EBX, EDX
INC EBX
INC EBX
@import_by_ordinal:
AND EBX, $7FFFFFFF
PUSH ECX
PUSH EDX
PUSH EBX
MOV EAX, DWORD PTR [EBP + @DllHandle]
PUSH EAX
CALL DWORD PTR [EBP + @_GetProcAddress]
POP EDX
POP ECX
OR EAX,EAX
JZ @iret_error
STOSD
ADD ECX, 4 //下一个入口
JMP @lookup_loop
@iret_success:
CLC
RET
@iret_error:
STC
RET
{ 初始化CRC32表 }
@MakeCRC32Table:
PUSH 1024
PUSH LMEM_FIXED
CALL DWORD PTR [EBP + @_LocalAlloc]
OR EAX, EAX
JZ @MakeCRC32_Error
MOV DWORD PTR [EBP + @lpCRC32_Table], EAX
MOV EDX, EAX
XOR EBX, EBX
@MakeCRC32Loop:
CMP EBX, $100
JE @MakeCRC32_Succ
MOV EAX, EBX
MOV ECX, 8
@MakeLoop:
TEST EAX, 1
JZ @MakeIsZero
SHR EAX, 1
XOR EAX, $EDB88320
JMP @MakeNext
@MakeIsZero:
SHR EAX, 1
@MakeNext:
LOOP @MakeLoop
MOV DWORD PTR [EDX], EAX
ADD EDX, 4
INC EBX
JMP @MakeCRC32Loop
@MakeCRC32_Succ:
CLC
RET
@MakeCRC32_Error:
STC
RET
{ 计算CRC32值 }
//CRC --> EAX
//Data --> EDX
//DataLen --> ECX
//Result <-- EAX
//function CRC32Calc(CRC: Longint; Data: Pointer; DataLen: Longint): Longint;
@CRC32Calc:
OR EDX, EDX //Data = nil?
JE @Exit
JECXZ @Exit //DataLen = 0?
PUSH ESI
PUSH EBX
MOV ESI, DWORD PTR [EBP + @lpCRC32_Table]
@Upd:
MOVZX EBX, AL //CRC32
XOR BL, [EDX]
SHR EAX, 8
AND EAX, $00FFFFFF
XOR EAX, [EBX + ESI]
INC EDX
LOOP @Upd
POP EBX
POP ESI
@Exit:
RET
@Repair_Code_Start:
{ 取备份文件名 }
@PrepairBackup: { 备份文件名 }
PUSH MAX_PATH
PUSH LMEM_FIXED
CALL DWORD PTR [EBP + @_LocalAlloc] //分配临时内存保存备份文件名
OR EAX, EAX
JZ @PreBak_Error
MOV DWORD PTR [EBP + @lpBakName], EAX
MOV CL, [EDI].TAddData.BakPath
CMP CL, bpWindowsDir
JZ @BakWindowsDir
CMP CL, bpSystemDir
JZ @BakSystemDir
CMP CL, bpTempDir
JZ @BakTempDir
@BakWorkDir: //备份文件位于应用程序目录
MOV EAX, DWORD PTR [EBP + @lpFileName]
PUSH EAX
CALL DWORD PTR [EBP + @_lstrlen]
MOV ECX, EAX
ADD EAX, DWORD PTR [EBP + @lpFileName]
@BakWorkDirLoop: //分离文件路径
DEC EAX
MOV BL, [EAX]
CMP BL, '\'
JZ @BakWorkDirCopy
CMP BL, ':'
JZ @BakWorkDirCopy
LOOP @BakWorkDirLoop
@BakWorkDirCopy: //复制应用程序路径到备份文件路径
INC ECX
PUSH ECX
MOV EAX, DWORD PTR [EBP + @lpFileName]
PUSH EAX
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_lstrcpyn]
JMP @CreateBakPath
@BakWindowsDir: //备份文件位于Windows目录
PUSH MAX_PATH
PUSH EAX
CALL DWORD PTR [EBP + @_GetWindowsDirectory]
OR EAX, EAX
JZ @PreBak_Error
JMP @CreateBakPath
@BakSystemDir: //备份文件位于System目录
PUSH MAX_PATH
PUSH EAX
CALL DWORD PTR [EBP + @_GetSystemDirectory]
OR EAX, EAX
JZ @PreBak_Error
JMP @CreateBakPath
@BakTempDir: //备份文件位于Temp目录
PUSH EAX
PUSH MAX_PATH
CALL DWORD PTR [EBP + @_GetTempPath]
OR EAX, EAX
JZ @PreBak_Error
JMP @CreateBakPath
@CreateBakPath: //备份文件存放路径
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_lstrlen]
ADD EAX, DWORD PTR [EBP + @lpBakName]
CMP BYTE PTR [EAX - 1], '\'
JZ @BakAddSubDir
MOV BYTE PTR [EAX], '\'
INC EAX
@BakAddSubDir:
MOV EBX, EDI
ADD EBX, [EDI].TAddData.BakSubDir
PUSH EBX
PUSH EAX
CALL DWORD PTR [EBP + @_lstrcpy] //复制子路径
PUSH 0
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_CreateDirectory] //创建子文件夹
MOV EAX, EDI
ADD EAX, [EDI].TAddData.BakName
CMP BYTE PTR [EAX], 0
JZ @GetDefBakName
@GetUserBakName:
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_lstrlen]
ADD EAX, DWORD PTR [EBP + @lpBakName]
MOV EBX, EDI
ADD EBX, [EDI].TAddData.BakName
PUSH EBX
PUSH EAX
CALL DWORD PTR [EBP + @_lstrcpy] //复制备份文件名
JMP @GetTempName
@GetDefBakName: //创建默认备份文件名
MOV EAX, DWORD PTR [EBP + @lpFileName]
PUSH EAX
CALL DWORD PTR [EBP + @_lstrlen]
MOV ECX, EAX
MOV EDX, EAX
ADD EAX, DWORD PTR [EBP + @lpFileName]
@GetDefBakNameLoop: //分离文件路径
DEC EAX
MOV BL, [EAX]
CMP BL, '\'
JZ @GetDefBakNameCopy
CMP BL, ':'
JZ @GetDefBakNameCopy
LOOP @GetDefBakNameLoop
@GetDefBakNameCopy:
SUB EDX, ECX //文件名长度(查找循环次数)
SUB EDX, csSizeOfExeExt //去掉扩展名
INC EDX
INC EAX
PUSH EDX
PUSH EAX
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_lstrlen]
MOV ECX, EAX
ADD EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_lstrcpyn] //复制原文件名
LEA EAX, [EBP + @szBakExt]
PUSH EAX
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_lstrcat] //复制备份(附加)文件名
@GetTempName: { 创建修复工具文件名 }
PUSH MAX_PATH
PUSH LMEM_FIXED
CALL DWORD PTR [EBP + @_LocalAlloc] //分配临时内存保存修复工具文件名
OR EAX, EAX
JZ @PreBak_Error
MOV DWORD PTR [EBP + @lpToolName], EAX
PUSH EAX
PUSH MAX_PATH
CALL DWORD PTR [EBP + @_GetTempPath]
OR EAX, EAX
JZ @PreBak_Error
ADD EAX, DWORD PTR [EBP + @lpToolName]
LEA EBX, [EBP + @szToolName]
PUSH EBX
PUSH EAX
CALL DWORD PTR [EBP + @_lstrcpy] //修复工具文件名
@DeleteTool: //删除临时修复工具
MOV EAX, DWORD PTR [EBP + @lpToolName]
PUSH EAX
CALL DWORD PTR [EBP + @_DeleteFile]
@PreBak_Succ:
CLC
RET
@PreBak_Error:
STC
RET { 创建备份文件 }
@CreateBackup:
PUSH 0
PUSH FILE_ATTRIBUTE_NORMAL
PUSH OPEN_EXISTING
PUSH 0
PUSH FILE_SHARE_READ
PUSH GENERIC_READ
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_CreateFile] //打开文件
CMP EAX, INVALID_HANDLE_VALUE
JZ @CreateNewBackup
MOV DWORD PTR [EBP + @hBakFile], EAX //文件句柄
PUSH FILE_END
PUSH 0
PUSH 0
MOV EAX, DWORD PTR [EBP + @hBakFile]
PUSH EAX
CALL DWORD PTR [EBP + @_SetFilePointer] //设置文件指针
CMP EAX, -1
JZ @CreateBak_Error
MOV DWORD PTR [EBP + @dwBakFileSize], EAX //文件长度
MOV EDX, [EDI].TAddData.FileSize
ADD EDX, 4
CMP EAX, EDX //比较文件长度
JZ @CreateBak_Succ
MOV EAX, DWORD PTR [EBP + @hBakFile] //备份文件长度不对
PUSH EAX
CALL DWORD PTR [EBP + @_CloseHandle]
XOR EAX, EAX
MOV EAX, DWORD PTR [EBP + @hBakFile]
@DeleteBackup:
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_DeleteFile] //删除备份文件
@CreateNewBackup:
PUSH 0
PUSH FILE_ATTRIBUTE_HIDDEN
PUSH CREATE_NEW
PUSH 0
PUSH FILE_SHARE_READ
PUSH GENERIC_WRITE
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_CreateFile] //创建新文件
CMP EAX, INVALID_HANDLE_VALUE
JZ @CreateBak_Succ //文件已存在
MOV DWORD PTR [EBP + @hBakFile], EAX //文件句柄
XOR EAX, EAX //文件CRC
MOV EDX, DWORD PTR [EBP + @lpFileMapping] //原文件指针
MOV ECX, DWORD PTR [EBP + @dwFileSize] //文件长度
CALL @CRC32Calc
MOV DWORD PTR [EBP + @dwOrgFileCRC], EAX
PUSH 0
LEA EAX, [EBP + @dwBytesWritten]
PUSH EAX
PUSH 4 //SizeOf DWORD
LEA EAX, [EBP + @dwOrgFileCRC]
PUSH EAX
MOV EAX, DWORD PTR [EBP + @hBakFile] //文件句柄
PUSH EAX
CALL DWORD PTR [EBP + @_WriteFile] //写入CRC32值
PUSH 0
LEA EAX, [EBP + @dwBytesWritten]
PUSH EAX
MOV EAX, DWORD PTR [EBP + @dwFileSize]
PUSH EAX //文件长度
MOV EAX, DWORD PTR [EBP + @lpFileMapping]
PUSH EAX
MOV EAX, DWORD PTR [EBP + @hBakFile] //文件句柄
PUSH EAX
CALL DWORD PTR [EBP + @_WriteFile] //写入原文件内容
@CreateBak_Succ:
CLC
RET
@CreateBak_Error:
STC
RET
{ 检查备份文件 }
@CheckBackup:
PUSH 0
PUSH FILE_ATTRIBUTE_NORMAL
PUSH OPEN_EXISTING
PUSH 0
PUSH FILE_SHARE_READ
PUSH GENERIC_READ
MOV EAX, DWORD PTR [EBP + @lpBakName]
PUSH EAX
CALL DWORD PTR [EBP + @_CreateFile] //打开文件
CMP EAX, INVALID_HANDLE_VALUE
JZ @Check_Fail
MOV DWORD PTR [EBP + @hBakFile], EAX //文件句柄
PUSH 0
PUSH 0
PUSH 0
PUSH PAGE_READONLY
PUSH 0
PUSH EAX
CALL DWORD PTR [EBP + @_CreateFileMapping] //创建映射文件
OR EAX, EAX
JZ @Check_Fail
MOV DWORD PTR [EBP + @hBakFileMap], EAX //映射文件句柄
PUSH 0
PUSH 0
PUSH 0
PUSH FILE_MAP_READ
PUSH EAX
CALL DWORD PTR [EBP + @_MapViewOfFile] //映射文件到内存
OR EAX, EAX
JZ @Check_Fail
MOV DWORD PTR [EBP + @lpBakFileMapping], EAX //内存指针
PUSH FILE_END
PUSH 0
PUSH 0
MOV EAX, DWORD PTR [EBP + @hBakFile]
PUSH EAX
CALL DWORD PTR [EBP + @_SetFilePointer] //设置文件指针
CMP EAX, -1
JZ @Check_Fail
MOV DWORD PTR [EBP + @dwBakFileSize], EAX //文件长度
MOV EDX, [EDI].TAddData.FileSize
ADD EDX, 4
CMP EAX, EDX //比较文件长度
JNZ @Check_Fail
PUSH FILE_BEGIN
PUSH 0
PUSH 0
MOV EAX, DWORD PTR [EBP + @hBakFile]
PUSH EAX
CALL DWORD PTR [EBP + @_SetFilePointer] //设置文件指针
XOR EAX, EAX //备份文件CRC
MOV EDX, DWORD PTR [EBP + @lpBakFileMapping] //备份文件指针
ADD EDX, 4 //文件头CRC数据长度
MOV ECX, DWORD PTR [EBP + @dwBakFileSize] //备份文件长度
SUB ECX, 4 //文件头CRC数据长度
CALL @CRC32Calc
MOV EBX, DWORD PTR [EBP + @lpBakFileMapping]
CMP EAX, [EBX]
JNZ @Check_Fail
@Check_Succ:
STC
RET
@Check_Fail:
CLC
RET
{ 修复应用程序 }
@Repair:
@CreateTool: //创建自动修复工具文件
PUSH 0
PUSH FILE_ATTRIBUTE_HIDDEN
PUSH CREATE_NEW
PUSH 0
PUSH FILE_SHARE_READ
PUSH GENERIC_WRITE
MOV EAX, DWORD PTR [EBP + @lpToolName]
PUSH EAX
CALL DWORD PTR [EBP + @_CreateFile] //创建新文件
CMP EAX, INVALID_HANDLE_VALUE
JZ @DoRepair //文件已存在
MOV DWORD PTR [EBP + @hToolFile], EAX //文件句柄
PUSH 0
LEA EAX, [EBP + @dwBytesWritten]
PUSH EAX
MOV EAX, [EDI].TAddData.RepairCodeSize
PUSH EAX
MOV EAX, EDI
ADD EAX, [EDI].TAddData.RepairCode
PUSH EAX
MOV EAX, DWORD PTR [EBP + @hToolFile] //文件句柄
PUSH EAX
CALL DWORD PTR [EBP + @_WriteFile] //写入修复工具数据
MOV EAX, DWORD PTR [EBP + @hToolFile] //文件句柄
PUSH EAX
CALL DWORD PTR [EBP + @_CloseHandle] //关闭文件
@DoRepair: { 运行修复工具进行修复 }
PUSH MAX_PATH
PUSH LMEM_FIXED
CALL DWORD PTR [EBP + @_LocalAlloc] //分配临时内存保存文件名
OR EAX, EAX
JZ @Repair_Fail
MOV DWORD PTR [EBP + @lpParam], EAX
@ParamCopyFileName: //应用程序文件名为第一参数
MOV BYTE PTR [EAX], '?'
INC EAX
MOV EBX, DWORD PTR [EBP + @lpFileName]
PUSH EBX
PUSH EAX
CALL DWORD PTR [EBP + @_lstrcpy] //复制应用程序文件名
PUSH EDI
MOV EDI, DWORD PTR [EBP + @lpParam]
MOV ECX, MAX_PATH
XOR AL, AL
REPNZ SCASB
MOV EAX, EDI
POP EDI
@ParamCopyBakName: //备份文件名为第二参数
DEC EAX
MOV BYTE PTR [EAX], '?' //文件名中用'?'分隔
INC EAX
MOV EBX, DWORD PTR [EBP + @lpBakName]
PUSH EBX
PUSH EAX
CALL DWORD PTR [EBP + @_lstrcpy] //复制应用程序文件名
@RunRepairTool: //运行修复工具进行修复
PUSH SW_SHOWNORMAL
PUSH 0
MOV EAX, DWORD PTR [EBP + @lpParam]
PUSH EAX
MOV EAX, DWORD PTR [EBP + @lpToolName]
PUSH EAX
PUSH 0
MOV EAX, DWORD PTR [EBP + @hInstance]
PUSH EAX
CALL DWORD PTR [EBP + @_ShellExecute] //运行修复程序
@Repair_Succ:
CLC
RET
@Repair_Fail:
STC
RET
@Repair_Code_End:
end;
//-----------------------------------------------//
//附加到PE文件尾的代码(结束) //
//-----------------------------------------------//
//文件处理代码
function FilePatch(Param: TPatchParam): TPatchInfo;
var
Stream: TFileStream;
OEP: DWORD; //原代码入口
iAddr: DWORD; //原Import表地址
CRCAddr: DWORD; //CRC原始值地址
CRC: DWORD; //CRC值
PBuff: Pointer; //文件缓冲区
peHdr: Pointer; //PE文件头
pData: PAddData; //附加代码段中的数据指针
pTData: PToolData; //修复工具内部数据指针
pEndData: Pointer; //附加在文件末尾数据指针
pHeader: PImageNtHeaders; //NT头指针
pSection: PImageSectionHeader; //节结构
pNewSection: PImageSectionHeader; //新节
OrgSize: DWORD; //原文件长度
AddDataSize: DWORD; //附加在原文件后的数据长度
AddCodeSize: DWORD; //附加的代码长度
EndDataSize: DWORD; //附加在文件未尾的数据长度
AddSize: DWORD; //新增总长度
NewSection_VSZ: DWORD; //新节映象长度
NewFileSize: DWORD; //新文件长度
Sections: DWORD; //节数
Image_Sz: DWORD; //原映象长度
i: DWORD;
FakeRva: DWORD;
FakeAddr: Pointer;
PImportDir: PImageImportDirectory;
PApi: PDWORD;
CreationTime: TFileTime;
LastAccessTime: TFileTime;
LastWriteTime: TFileTime;
FileAttr: Integer;
procedure SaveFileInfo(Handle: THandle);
begin
GetFileTime(Handle, @CreationTime, @LastAccessTime, @LastWriteTime);
FileAttr := FileGetAttr(Param.FileName);
FileSetAttr(Param.FileName, faArchive);
end;
procedure RestoreFileInfo(Handle: THandle);
begin
SetFileTime(Handle, @CreationTime, @LastAccessTime, @LastWriteTime);
FileSetAttr(Param.FileName, FileAttr);
end;
//字符串存储长度
function SLen(const Str: string): DWORD;
begin
Result := Length(Str) + 1;
end;
function DlgSLen(Dlg: TDlgParam): DWORD;
begin
Result := SLen(Dlg.Text) + SLen(Dlg.Caption);
end;
//处理文件尾附加字符串数据
procedure AddStr(var AOff: TDataOffset; const Str: string);
begin
AOff := DWORD(pEndData) - DWORD(pData);
CopyMemory(pEndData, PChar(Str), Length(Str));
pEndData := Pointer(DWORD(pEndData) + DWORD(Length(Str)) + 1);
end;
procedure AddDlgStr(var DlgData: TDlgData; DlgParam: TDlgParam);
begin
AddStr(DlgData.Text, DlgParam.Text);
AddStr(DlgData.Caption, DlgParam.Caption);
end;
//数据加密
procedure XorData(XorValue: DWORD; Pos: DWORD; Len: DWORD);
var
p: PDWORD;
i: DWORD;
begin
p := PDWORD(DWORD(pData) + Pos);
for i := 0 to Len - 1 do
begin
if p^ <> 0 then
p^ := p^ xor XorValue;
Inc(p);
end;
end;
//设置Rav所在节的属性
procedure SetSectionFlag(pHdr: Pointer; SectionNum: Integer; Rva: DWORD; Flag: DWORD);
type
PSecs = ^TSecs;
TSecs = array[0..0] of TImageSectionHeader;
var
pSec: PSecs;
i: Integer;
begin
pSec := PSecs(DWORD(pHdr) + $F8);
for i := 0 to SectionNum - 1 do
begin
if (pSec[i].VirtualAddress <= Rva) and ((i = SectionNum - 1) or
(pSec[i + 1].VirtualAddress > Rva)) then
begin
pSec[i].Characteristics := Flag;
end;
end;
end;
begin
ZeroMemory(@Result, SizeOf(Result));
try
Stream := TFileStream.Create(Param.FileName, fmOpenRead);
try
SaveFileInfo(Stream.Handle);
//原文件长度
OrgSize := Stream.Size;
//附加在原文件后的数据长度
AddDataSize := SizeOfTAddData;
//附加代码实际长度
if Param.AllowRepair then
AddCodeSize := Repair_End - AsmAdd_Addr
else
AddCodeSize := Repair_Addr - AsmAdd_Addr;
//附加在文件尾可变长度数据实际长度
with Param do
EndDataSize := SLen(RegSubKey) + SLen(RegValue) + SLen(BakSubDir) +
SLen(BakName) + DlgSLen(CanRepairDlg) + DlgSLen(CannotRepairDlg) +
DlgSLen(CrcErrorDlg);
if Param.AllowRepair then //文件修复工具
Inc(EndDataSize, ResStream.Size);
//增加的总长度
AddSize := AddDataSize + AddCodeSize + EndDataSize;
//新节虚拟长度
NewSection_VSZ := (AddSize + $1000) and $FFFFF000;
//新文件长度
NewFileSize := OrgSize + AddSize;
GetMem(PBuff, NewFileSize); //分配缓冲区
ZeroMemory(PBuff, NewFileSize);
try
Stream.Position := 0;
Stream.read(PBuff^, OrgSize); //读文件到缓冲区
FreeAndNil(Stream);
if PWORD(PBuff)^ <> IMAGE_DOS_SIGNATURE then
begin //检查Dos头标志
Result.Result := prFileFormatError;
Exit;
end;
peHdr := Pointer(PDWORD(DWORD(PBuff) + $3C)^ + DWORD(PBuff));
if DWORD(peHdr^) <> IMAGE_NT_SIGNATURE then
begin //检查PE头标志
Result.Result := prFileFormatError;
Exit;
end;
pHeader := peHdr; //文件头
OEP := pHeader.OptionalHeader.AddressOfEntryPoint; //原代码入口
iAddr := pHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; //原Import表地址
Sections := pHeader.FileHeader.NumberOfSections; //总节数
for i := 0 to Sections - 1 do //检测是否已处理过
begin
pSection := Pointer(DWORD(peHdr) + $F8 + $28 * i);
if CompareMem(Pointer(@pSection.Name), PChar(csSectionName),
Length(csSectionName)) then
begin
Result.Result := prAlreadyPatched;
Exit;
end;
end;
Inc(pHeader.FileHeader.NumberOfSections); //总节数加一
Image_Sz := pHeader.OptionalHeader.SizeOfImage; //原映象大小
Inc(pHeader.OptionalHeader.SizeOfImage, NewSection_VSZ); //增加附加虚拟长度
pHeader.OptionalHeader.AddressOfEntryPoint := Image_Sz + AddDataSize; //修改代码入口
//增加新的节信息
pNewSection := Pointer(DWORD(peHdr) + $F8 + $28 * Sections);
ZeroMemory(pNewSection, SizeOf(TImageSectionHeader)); //填充节表
for i := 0 to Length(csSectionName) - 1 do
pNewSection.Name[i] := Byte(csSectionName[i + 1]); //节名
pNewSection.Misc.VirtualSize := NewSection_VSZ; //虚拟长度
pNewSection.VirtualAddress := Image_Sz; //虚拟偏移
pNewSection.SizeOfRawData := AddSize; //实际长度
pNewSection.PointerToRawData := OrgSize; //文件中的偏移量
pNewSection.Characteristics := csSectionChar; //新节为可执行、可读、可写
//复制附加代码
CopyMemory(Pointer(DWORD(PBuff) + OrgSize + AddDataSize),
Pointer(AsmAdd_Addr), AddCodeSize);
//处理新的Import表
FakeRva := Image_Sz + AddDataSize + Fake_tbl_Addr - AsmAdd_Addr;
FakeAddr := Pointer(DWORD(PBuff) + OrgSize + AddDataSize + Fake_tbl_Addr
- AsmAdd_Addr);
PImportDir := PImageImportDirectory(FakeAddr);
while PImportDir^.Name <> 0 do
begin
PApi := PDWORD(DWORD(FakeAddr) + PImportDir^.Misc.OriginalFirstThunk - Fake_tbl_Addr);
while PApi^ <> 0 do
begin
PApi^ := PApi^ - Fake_tbl_Addr + FakeRva;
Inc(PApi);
end;
PImportDir.Misc.OriginalFirstThunk := PImportDir.Misc.OriginalFirstThunk
- Fake_tbl_Addr + FakeRva;
PImportDir.Name := PImportDir.Name - Fake_tbl_Addr + FakeRva;
PImportDir.FirstThunk := PImportDir.FirstThunk - Fake_tbl_Addr + FakeRva;
Inc(PImportDir);
end;
pHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress := FakeRva;
pHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size := Fake_tbl_End - Fake_tbl_Addr;
SetSectionFlag(peHdr, Sections, iAddr, csSectionChar);
//附加代码中需要保存的数据
pData := PAddData(DWORD(PBuff) + OrgSize);
//文件尾动态长度数据
pEndData := Pointer(DWORD(pData) + AddDataSize + AddCodeSize);
//处理文件尾附加字符串数据
AddStr(pData^.RegSubKey, Param.RegSubKey);
AddStr(pData^.RegValue, Param.RegValue);
if (Param.BakSubDir <> '') and (Param.BakSubDir[1] = '\') then
Delete(Param.BakSubDir, 1, 1);
if (Param.BakSubDir <> '') and (Param.BakSubDir[Length(Param.BakSubDir)]
<> '\') then
Param.BakSubDir := Param.BakSubDir + '\';
AddStr(pData^.BakSubDir, Param.BakSubDir);
AddStr(pData^.BakName, Param.BakName);
AddDlgStr(pData^.CanRepairDlg, Param.CanRepairDlg);
AddDlgStr(pData^.CannotRepairDlg, Param.CannotRepairDlg);
AddDlgStr(pData^.CrcErrorDlg, Param.CrcErrorDlg);
//原始CRC在文件中存放的地址
CRCAddr := OrgSize + DWORD(@pData^.CRC) - DWORD(pData);
//填充附加数据块
pData^.Flag := csFileFlag; //处理标志
pData^.OEP := OEP; //原代码入口
pData^.iAddress := iAddr; //原Import表地址
pData^.CRCAddr := CRCAddr; //CRC存放地址
pData^.FileSize := NewFileSize; //文件长度
pData^.AllowRegQuery := Param.AllowRegQuery;
pData^.RegKey := Param.RegKey;
pData^.AllowRepair := Param.AllowRepair;
pData^.BakPath := Param.BakPath;
pData^.CanRepair := Param.CanRepair;
pData^.CannotRepair := Param.CannotRepair;
pData^.CrcError := Param.CrcError;
pData^.CanRepairDlg.uType := ctDlgIcon[Param.CanRepairDlg.Icon] +
ctCanRepair[Param.CanRepair];
pData^.CannotRepairDlg.uType := ctDlgIcon[Param.CannotRepairDlg.Icon] +
ctCannotRepair[Param.CannotRepair];
pData^.CrcErrorDlg.uType := ctDlgIcon[Param.CrcErrorDlg.Icon] +
ctCrcError[Param.CrcError];
//文件修复工具
if Param.AllowRepair then
begin
pData^.RepairCode := DWORD(pEndData) - DWORD(pData);
pData^.RepairCodeSize := ResStream.Size;
CopyMemory(pEndData, ResStream.memory, ResStream.Size);
//修复工具内部数据
pTData := PToolData(DWORD(pEndData) + csToolDataOffset);
pTData^.RepairSucc := Param.RepairSucc;
pTData^.RepairFail := Param.RepairFail;
pTData^.RepairSuccDlg.uType := ctDlgIcon[Param.RepairSuccDlg.Icon] +
ctRepairSucc[Param.RepairSucc];
pTData^.RepairFailDlg.uType := ctDlgIcon[Param.RepairFailDlg.Icon] +
ctRepairFail[Param.RepairFail];
lstrcpyn(pTData^.RepairSuccDlg.Text, PChar(Param.RepairSuccDlg.Text)
, csMaxDlgTextLen);
lstrcpyn(pTData^.RepairSuccDlg.Caption, PChar(Param.RepairSuccDlg.Caption)
, csMaxDlgCaptionLen);
lstrcpyn(pTData^.RepairFailDlg.Text, PChar(Param.RepairFailDlg.Text)
, csMaxDlgTextLen);
lstrcpyn(pTData^.RepairFailDlg.Caption, PChar(Param.RepairFailDlg.Caption)
, csMaxDlgCaptionLen);
end;
//数据加密
pData^.Xor1 := Random($FFFFFFFF);
pData^.Pos1 := DWORD(@pData^.FileSize) - DWORD(pData);
pData^.Len1 := (SizeOfTAddData - pData^.Pos1) div 4;
pData^.Xor2 := Random($FFFFFFFF);
pData^.Pos2 := AddDataSize + AddCodeSize;
pData^.Len2 := EndDataSize div 4;
XorData(pData^.Xor1, pData^.Pos1, pData^.Len1);
XorData(pData^.Xor2, pData^.Pos2, pData^.Len2);
//计算文件CRC32值
CRC := CRC32Calc(0, PBuff, CRCAddr);
CRC := CRC32Calc(CRC, Pointer(DWORD(PBuff) + CRCAddr + SizeOf(DWORD))
, NewFileSize - CRCAddr - SizeOf(DWORD));
pData^.CRC := CRC; //CRC计算跳过保存CRC原始值的4字节
//原文件备份
if Param.BackupOrgFile then
RenameFile(Param.FileName, Param.FileName + csBakExt)
else
DeleteFile(Param.FileName);
//保存
Stream := TFileStream.Create(Param.FileName, fmCreate);
Stream.Position := 0;
Stream.write(PBuff^, NewFileSize);
Result.Result := prSuccess;
Result.FileName := Param.FileName;
if Param.BackupOrgFile then
Result.BakFileName := Param.FileName + csBakExt;
Result.OrgSize := OrgSize;
Result.NewSize := NewFileSize;
Result.AddSize := AddSize;
finally
FreeMem(PBuff);
end;
RestoreFileInfo(Stream.Handle);
finally
Stream.Free;
end;
except
on EFCreateError do Result.Result := prWriteError;
on EFOpenError do Result.Result := prOpenError;
else
Result.Result := prOtherError;
end;
end;
initialization
// ResStream := TResourceStream.Create(GetModuleHandle(''), csRestoreToolRes, RT_RCDATA);
AsmAdd;
Make_CRC32Table;
//finalization
// ResStream.Free;
end.