首页
社区
课程
招聘
[原创]一个用CRC程序保护程序的具体例子
发表于: 2007-3-12 20:25 9679

[原创]一个用CRC程序保护程序的具体例子

2007-3-12 20:25
9679

这是一个用CRC程序保护的具体例子 前几天在网上找具体的例子 想直接放在自己的程序里 竟然没有找到完整的实例 只有算法和原理 我整理了一下找到的内容 在控制台下写了个完整的程序

只要大家用改动程序的一个字节 程序也能检测出来 比如把int3 nop掉也能检测出来

程序链接成可执行文件后要用16进制工具把原来程序的CRC值写在PE Optional_Section的Win32Version处

下面是源代码 附件是CRC值已经写入的可执行文件 大家可试验一下

#include "stdio.h"
#include "windows.h"

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);
}
bool isModified = false;

void main()
{
/*        DWORD res = CRC32((BYTE*)p, 6);
        printf("%x    ", res);*/
        DWORD dwNumberOfBytesReadWritten;
        HMODULE hmod;
        HGLOBAL hMemory;
        LPVOID pMemory;
        DWORD dwFileSize;
        CHAR szFileName[20];
        hmod = ::GetModuleHandle(0);
       
        ::GetModuleFileName(hmod, szFileName, MAX_PATH);

        HANDLE hFile = ::CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, 0);
        if(hFile != INVALID_HANDLE_VALUE)
                dwFileSize = ::GetFileSize(hFile, NULL);

        hMemory = ::GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,  dwFileSize);
       
        pMemory = ::GlobalLock(hMemory);

        ReadFile(hFile, pMemory, dwFileSize, &dwNumberOfBytesReadWritten, NULL);

        ::CloseHandle(hFile);

        DWORD dwPEHead, dwWin32Version;
        LPVOID pWin32Version;
        LPVOID pMemoryPEHead = pMemory;
       
        BYTE* pp;
        pp = static_cast<BYTE*>(pMemory) + 0x3c;
        pMemoryPEHead = (LPVOID)pp;
//        static_cast<BYTE*>(pMemory)++
//        static_cast(BYTE*)pMemory2 = static_cast(BYTE*)pMemory+ 0x3c;
        //static_cast<BYTE*>(pMemory2) = static_cast<BYTE*>(pMemory2) + 0x3c;
        dwPEHead = *((DWORD*)pMemoryPEHead);
       
        pWin32Version = pMemory;
        dwWin32Version = dwPEHead + 0x4c;

        BYTE* Version;
        Version = static_cast<BYTE*>(pWin32Version) + dwWin32Version;
        pWin32Version = (BYTE*)Version;
       
        DWORD OriginalCRC32 = *((DWORD*)pWin32Version);
        *((DWORD*)pWin32Version) = 0;

        DWORD NowCRC32 = CRC32((BYTE*)pMemory, dwFileSize);

        if(OriginalCRC32 != NowCRC32)
                ::MessageBox(0, "error", "e", MB_OK);
        else
                ::MessageBox(0, "chenggong", "c", MB_OK);

        getchar();
       

}


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 437
活跃值: (273)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
2
这是附件 ..
上传的附件:
2007-3-12 20:43
0
雪    币: 437
活跃值: (273)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
3
怎么有人点 没有人回啊
2007-3-13 10:54
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不错,顶一下。
2007-3-13 11:08
0
雪    币: 463
活跃值: (116)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
我修改后,再用工具计算修改文件的CRC值,再用工具写入正确的CRC值,嘿嘿。
2007-3-13 12:25
0
雪    币: 437
活跃值: (273)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
6
可以把CRC值放在别的地方
可以对程序的某一部分加密 让破解者不好计算修改后的CRC值
可以在程序中多制造几个CRC码表
可以在程序中对CRC码表进行多次无效处理 让破解的人不好下断点
办法多呢
2007-3-13 16:24
0
雪    币: 319
活跃值: (2459)
能力值: ( LV12,RANK:980 )
在线值:
发帖
回帖
粉丝
7
最初由 bzhkl 发布
可以把CRC值放在别的地方
可以对程序的某一部分加密 让破解者不好计算修改后的CRC值
可以在程序中多制造几个CRC码表
可以在程序中对CRC码表进行多次无效处理 让破解的人不好下断点
办法多呢


那就弄几个来玩玩
2007-3-13 16:41
0
雪    币: 437
活跃值: (273)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
8
这对大牛当然构不成多大困难 但能增加一般解密水平的人调试时间
把关键判断函数加上VM, 或者加上 userploybuffer这样就更好了
上面的实现都是很简单的
2007-3-20 13:14
0
雪    币: 219
活跃值: (58)
能力值: ( 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.
2007-3-20 13:27
0
雪    币: 817
活跃值: (1927)
能力值: ( LV12,RANK:2670 )
在线值:
发帖
回帖
粉丝
10
最初由 风铃夜思雨 发布
我这有一段为程序加CRC校验的,代码是DELPHI的
unit AsmPatch;
interface
........


这个就是网上的那个CRC校验添加工具吗?
2007-3-20 14:05
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
学习了,好样的,谢谢
2007-3-20 14:12
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
这样的强贴对编程者来说绝对是福气,不久将来演化,我们可惨了
2007-3-20 20:10
0
雪    币: 437
活跃值: (273)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
13
引来了牛贴
这个强
学习
2007-3-21 11:11
0
游客
登录 | 注册 方可回帖
返回
//