用CRC保护程序(DELPHI)
2010年06月07日
为程序加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
2010年06月07日
为程序加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