学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

450

积分

0

好友

15

主题
发表于 2021-4-3 10:59:33 | 查看: 6774| 回复: 9
新建文件夹.rar (8.78 MB, 下载次数: 14)

前置知识:
PE头
导数表
导出表
重定位表
TLS

壳的基本原理
对目标程序添加一段壳代码,目标PE执行的时候,先执行壳代码,之后再回到原始OEP

难点
API调用问题
重定位问题
信息交互问题
调试(非常浪费时间)
被加壳程序的随机基址
被加壳程序的导入表
动态加密
TLS处理问题

实现思路
读取一个文件,并判断目标文件是否是 PE 文件

  1. 使用 CreateFIle 打开一个文件
  2. 使用函数 GetFileSize 获取文件的大小
  3. 使用前面获取到的大小申请一块堆空间
  4. 从文件中读取内容并保存到堆空间中
  5. 判断 Dos 头中和 Nt 头中的字段
  6. 如果不兼容 dll 加壳,还需要判断目标是否是 exe
BOOL Pack::LoadFile(LPCWSTR path)
{
        HANDLE file = CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
        if (file == INVALID_HANDLE_VALUE)
        {
                MessageBox(NULL, L"文件打开失败", L"错误", MB_OK | MB_ICONERROR);
                ExitProcess(-1);
        }

        size = GetFileSize(file, NULL);
        data = (ULONG)malloc(size);

        DWORD bytes = 0;
        if (!ReadFile(file, (LPVOID)data, size, &bytes, NULL))
        {
                MessageBox(NULL, L"文件读取失败", L"错误", MB_OK | MB_ICONERROR);
                ExitProcess(-1);
        }

        if (DosHeader(data)->e_magic != IMAGE_DOS_SIGNATURE ||
                NtHeader(data)->Signature != IMAGE_NT_SIGNATURE)
        {
                MessageBox(NULL, L"不是有效的PE文件", L"错误", MB_OK | MB_ICONERROR);
                ExitProcess(-1);
        }
        printf("文件加载完成\n\n");
        CloseHandle(file);
        return TRUE;
}

读取壳代码对应的 dll 文件,并保存相关信息

  1. 将模块展开到当前应用程序的虚拟空间中
  2. 获取到壳代码的入口函数,并计算其区段内偏移,后续用于求新偏移
    新oeprva = startva - dll基址 - 所在区段rva + 移动后的区段rva
  3. 将共享数据获取到,加壳器主要负责向内写入数据
VOID Pack::LoadStub(LPCWSTR path)
{
        stub = (ULONG)LoadLibraryExW(path,NULL,DONT_RESOLVE_DLL_REFERENCES);
        if (stub == NULL)
        {
                MessageBox(NULL, L"文件打开失败", L"错误", MB_OK | MB_ICONERROR);
                ExitProcess(-1);
        }
        ULONG va = (ULONG)GetProcAddress((HMODULE)stub, "start");
        offset = va - stub - GetSection(stub, ".text")->VirtualAddress;
        share = (PSHAREDATA)GetProcAddress((HMODULE)stub, "share");
        printf("Dll加载完成\n\n");
}
            将壳代码的区段[表]直接的复制到PE文件中
            1. 通过名称找到 src_name 对应于 dll 的区段表
            2. 找到 PE 文件内新区段的位置,并设置区段数量 +1
            3. 将目标区段的区段属性复制到当前的新区段表内
            4. 重新计算出新区段在 PE 文件中的起始 FOA\RVA
            5. 重新计算 PE 文件的大小以及 SizeOfImage 的值
            6. 扩充 PE 文件到指定的大小并结束当前函数
VOID Pack::CopySection(LPCSTR src_name,LPCSTR dest_name)
{

        auto src_section = GetSection(stub, ".text");
        auto last_section = &IMAGE_FIRST_SECTION(NtHeader(data))[FileHeader(data)->NumberOfSections - 1];

        auto new_section = last_section + 1;
        FileHeader(data)->NumberOfSections++;

        memset(new_section, 0, sizeof(IMAGE_SECTION_HEADER));
        memcpy(new_section, src_section, sizeof(IMAGE_SECTION_HEADER));

        memcpy(new_section->Name, dest_name, strlen(dest_name) + 1);
        //newRVA = oldRVA + 内存对齐
        new_section->VirtualAddress = last_section->VirtualAddress + Aligment(last_section->Misc.VirtualSize,OptionalHeader(data)->SectionAlignment);
        //文件偏移 = 旧文件偏移 + 内存对齐
        new_section->PointerToRawData = last_section->PointerToRawData + Aligment(last_section->SizeOfRawData,OptionalHeader(data)->FileAlignment);
        //文件大小 + 偏移
        this->size = new_section->SizeOfRawData + new_section->PointerToRawData;

        data = (ULONG)realloc((LPVOID)data, this->size);

        //映像总大小 = RVA + 对齐前的大小
        OptionalHeader(data)->SizeOfImage = new_section->VirtualAddress + new_section->Misc.VirtualSize;
        printf("区段表拷贝完成\n\n");
}
            备份,修复重定位表
            1.备份原程序的重定位表地址,将原程序的重定位写入到通讯结构体中,
            将dll的重定位表替换到原程序的重定位表
            2.在壳代码中,系统会帮我修复壳代码的重定位,待原程序解密之后,
            在壳代码中获取通讯结构体,获取原程序重定位表,修复原程序重定位
VOID Pack::BackupReloc()
{
        //保存数据
        //文件在内存中的地址
        DWORD DllImageBase = OptionalHeader(stub)->ImageBase;
        share->dwRelocRva = OptionalHeader(data)->DataDirectory[5].VirtualAddress;
        share->dwRelocSize = OptionalHeader(data)->DataDirectory[5].Size;
        share->OldImageBase = OptionalHeader(data)->ImageBase;

        auto DllBaseReloc = (PIMAGE_BASE_RELOCATION)
                (OptionalHeader(stub)->DataDirectory[5].VirtualAddress + DllImageBase);
        DWORD DllRelocSize = OptionalHeader(stub)->DataDirectory[5].Size;

        AddSection(".Sec", DllRelocSize + 8);
        auto NewSection = GetSection(data, ".Sec");
        auto OldSection = GetSection(stub, ".text");
        auto PackSection = GetSection(data, ".pack");
        //文件偏移 + 首地址
        auto NewSentionReloc = (PIMAGE_BASE_RELOCATION)(NewSection->PointerToRawData + data);
        //rva + 基址
        DWORD OldSectionAddr = (DWORD)(OldSection->VirtualAddress + stub);

        memcpy((DWORD*)NewSentionReloc, (DWORD*)(DllBaseReloc), DllRelocSize);
        while (NewSentionReloc->VirtualAddress)
        {
                //新的内存页起始RVA = 原RVA - 原段基址 +.pack段基址
                NewSentionReloc->VirtualAddress = NewSentionReloc->VirtualAddress - (OldSectionAddr - stub) + PackSection->VirtualAddress;
                NewSentionReloc = (PIMAGE_BASE_RELOCATION)(NewSentionReloc->SizeOfBlock + (DWORD)NewSentionReloc);
        }
        //替换原程序重定位表
        OptionalHeader(data)->DataDirectory[5].VirtualAddress = NewSection->VirtualAddress;
        OptionalHeader(data)->DataDirectory[5].Size = DllRelocSize;
}
            备份,修复重定位表
            1.备份原程序的重定位表地址,将原程序的重定位写入到通讯结构体中,
            将dll的重定位表替换到原程序的重定位表
            2.在壳代码中,系统会帮我修复壳代码的重定位,待原程序解密之后,
            在壳代码中获取通讯结构体,获取原程序重定位表,修复原程序重定位
VOID Pack::FixReloc()
{
        typedef struct _TYPEOFFSET
        {
                WORD offset : 12;
                WORD type : 4;
        } TYPEOFFSET, * PTYPEOFFSET;

        auto reloc = (PIMAGE_BASE_RELOCATION)(OptionalHeader(stub)->DataDirectory[5].VirtualAddress + stub);

        ULONG old_base = stub;
        ULONG new_base = OptionalHeader(data)->ImageBase;
        ULONG old_section_base = GetSection(stub, ".text")->VirtualAddress;
        ULONG new_section_base = GetSection(data, ".pack")->VirtualAddress;

        while (reloc->SizeOfBlock)
        {
                auto item = (PTYPEOFFSET)(reloc + 1);
                ULONG count = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;

                for (ULONG i = 0; i < count; ++i)
                {
                        if (item[i].type == 3)
                        {
                                DWORD old_protect = 0;
                                ULONG* address = (ULONG*)(item[i].offset + reloc->VirtualAddress + stub);
                                VirtualProtect(address, 4, PAGE_READWRITE, &old_protect);
                                *address = *address - old_base - old_section_base + new_base + new_section_base;
                                VirtualProtect(address, 4, old_protect, &old_protect);
                        }
                }
                reloc = (PIMAGE_BASE_RELOCATION)((ULONG)reloc + reloc->SizeOfBlock);
        }

        //auto a = OptionalHeader(data)->DllCharacteristics;
        //a &= ~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
        //OptionalHeader(data)->DllCharacteristics = a;
        printf("Dll重定位修复完成\n\n");
        return;
}
            将TLS信息保存到共享数据中
VOID Pack::SaveTLS()
{
        //备份
        share->TlsVirtualAddress = OptionalHeader(data)->DataDirectory[9].VirtualAddress;
        if (NULL != share->TlsVirtualAddress)
        {
                OptionalHeader(data)->DataDirectory[9].VirtualAddress = 0;
                ULONG Foa = RvaToOffset(data,share->TlsVirtualAddress);
                auto Tls = (PIMAGE_TLS_DIRECTORY)(Foa + data);
                share->TlsVa = Tls->AddressOfCallBacks;
                share->OldImageBase = OptionalHeader(data)->ImageBase;
        }
}
            设置 OEP 到新的位置
            1. 将旧的 oep 保存到共享数据中
            2. 将新的 oep 设置到扩展头中
            1. 分别找到两个区段在文件中(pe)和内存中(stub)的区段表
            2. 计算出两个区段在内存中的位置,分别使用 foa 和 rva
            3. 进行拷贝,拷贝的大小就是区段的大小(SizeOfRawData)
VOID Pack::SetNewOep()
{
        share->old_oep = OptionalHeader(data)->AddressOfEntryPoint;
        OptionalHeader(data)->AddressOfEntryPoint = offset + GetSection(data, ".pack")->VirtualAddress;
        printf("新OEP设置完成\n\n");
}
            加密指定的区段,使用异或方式
            1. 找到区段
            2. 计算大小和起始位置
            3. 生成 key 并将区段信息保存到共享数据
            4. 进行加密操作
VOID Pack::XorSection(LPCSTR name)
{
        auto section = GetSection(data, name);
        auto text = (BYTE*)(section->PointerToRawData + data);

        share->xorkey = rand() % 0x100;
        share->xorsection = section->VirtualAddress;
        share->xorsize = section->SizeOfRawData;

        for (UINT i = 0; i < share->xorsize; ++i)
        {
                text[i] ^= share->xorkey;
        }
}
            1. 首先将数据目录表中的导入表信息保存到共享数据
            2. 清除数据目录表中的导入表和 IAT 表
VOID Pack::HookIat()
{
        share->intrva = OptionalHeader(data)->DataDirectory[1].VirtualAddress;

        OptionalHeader(data)->DataDirectory[1].Size = OptionalHeader(data)->DataDirectory[1].VirtualAddress =
                OptionalHeader(data)->DataDirectory[12].Size =
                OptionalHeader(data)->DataDirectory[12].VirtualAddress = 0;
}

// 将壳代码的区段[内容]直接的复制到PE文件中

VOID Pack::CopySectionData(LPCSTR src_name,LPCSTR dest_name)
{

        auto src_section = GetSection(stub, src_name);
        auto dest_section = GetSection(data, dest_name);

        LPVOID src_data = (LPVOID)(src_section->VirtualAddress + stub);
        LPVOID dest_data = (LPVOID)(dest_section->PointerToRawData + data);

        memcpy(dest_data, src_data, src_section->SizeOfRawData);
}
        保存修改后的 PE 文件到新的位置
            1. 使用指定路径创建一个新的文件
            2. 按照事先约定好的大小写入内容
            3. 释放堆空间并且关闭句柄
VOID Pack::SaveFile(LPCWSTR path)
{

        HANDLE file = CreateFileW(path,GENERIC_ALL,NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
        if (file == INVALID_HANDLE_VALUE)
        {
                MessageBox(NULL, L"文件打开失败", L"错误", MB_OK | MB_ICONERROR);
                ExitProcess(-1);
        }

        DWORD bytes = 0;
        if (!WriteFile(file, (LPVOID)data, size, &bytes, NULL))
        {
                MessageBox(NULL, L"文件写入失败", L"错误", MB_OK | MB_ICONERROR);
                ExitProcess(-1);
        }

        free((LPVOID)data);
        CloseHandle(file);
}

壳代码实现

typedef struct _SHAREDATA
{
        unsigned int old_oep;
        unsigned char xorkey;
        unsigned long xorsection;
        unsigned int xorsize;
        int TlsVirtualAddress;
        int TlsVa;
        int dwRelocRva;
        int dwRelocSize;
        int OldImageBase;
        DWORD intrva;
} SHAREDATA, * PSHAREDATA;

using FuncVirtualProtect = BOOL(WINAPI*)(
        _In_  LPVOID lpAddress,
        _In_  SIZE_T dwSize,
        _In_  DWORD flNewProtect,
        _Out_ PDWORD lpflOldProtect);
FuncVirtualProtect pVirtualProtect;

using funcGetProcAddress = FARPROC(WINAPI*)(
        _In_ HMODULE hModule,
        _In_ LPCSTR lpProcName
        );
funcGetProcAddress pGetProcAddress;

using funcLoadLibraryA = HMODULE(WINAPI*)(
        _In_ LPCSTR lpLibFileName
        );
funcLoadLibraryA pLoadLibraryA;

using funcVirtualAlloc = LPVOID(WINAPI*)(
        _In_opt_ LPVOID lpAddress,
        _In_     SIZE_T dwSize,
        _In_     DWORD flAllocationType,
        _In_     DWORD flProtect);
funcVirtualAlloc pVirtualAlloc;

typedef ATOM(WINAPI* MYRegisterClassA)
(CONST WNDCLASSA* lpWndClass);
MYRegisterClassA MyRegisterClassA;

typedef HWND(WINAPI* MYCreateWindowExA)
(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
MYCreateWindowExA MyCreateWindowExA;

typedef HMODULE(WINAPI* MYGetModuleHandleA)
(LPCSTR lpModuleName);
MYGetModuleHandleA MyGetModuleHandleA;

typedef BOOL(WINAPI* MYShowWindow)
(HWND hWnd, int nCmdShow);
MYShowWindow MyShowWindow;

typedef BOOL(WINAPI* MYUpdateWindow)
(HWND hWnd);
MYUpdateWindow MyUpdateWindow;

typedef BOOL(WINAPI* MYGetMessageA)
(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
MYGetMessageA MyGetMessageA;

typedef BOOL(WINAPI* MYTranslateMessage)
(CONST MSG* lpMsg);
MYTranslateMessage MyTranslateMessage;

typedef LRESULT(WINAPI* MYDispatchMessageA)
(CONST MSG* lpMsg);
MYDispatchMessageA MyDispatchMessageA;

typedef LRESULT(WINAPI* MYDefWindowProcA)
(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
MYDefWindowProcA   MyDefWindowProcA;

typedef VOID(WINAPI* MYPostQuitMessage)
(int nExitCode);
MYPostQuitMessage MyPostQuitMessage;

typedef BOOL(WINAPI* MYGetClientRect)
(HWND hWnd, LPRECT lpRect);
MYGetClientRect MyGetClientRect;

typedef int (WINAPI* MYGetWindowTextA)
(HWND hWnd, _Out_writes_(nMaxCount) LPSTR lpString, int nMaxCount);
MYGetWindowTextA MyGetWindowTextA;

typedef HWND(WINAPI* MYGetDlgItem)
(HWND hDlg, int nIDDlgItem);
MYGetDlgItem MyGetDlgItem;

typedef int(__cdecl* MYmemcmp)
(_In_reads_bytes_(_Size) void const* _Buf1, _In_reads_bytes_(_Size) void const* _Buf2, size_t _Size);
MYmemcmp Mymemcmp;

typedef VOID(WINAPI* MYExitProcess)
(UINT uExitCode);
MYExitProcess MyExitProcess;

typedef LRESULT(WINAPI* MYSendMessageA)
(HWND hWnd, UINT Msg, _Pre_maybenull_ _Post_valid_ WPARAM wParam, _Pre_maybenull_ _Post_valid_ LPARAM lParam);
MYSendMessageA MySendMessageA;

typedef HMODULE(WINAPI* MYLoadLibraryExA)
(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
MYLoadLibraryExA MyLoadLibraryExA;

typedef int(WINAPI* MYMessageBoxA)
(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
MYMessageBoxA MyMessageBoxA;

typedef BOOL(WINAPI* MYVirtualProtect)
        (LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
MYVirtualProtect MyVirtualProtect;

HMODULE gKernelBase = 0;
HMODULE gUser32Base = 0;
DWORD gImageBase;
HWND gParentWnd = 0;

PIMAGE_DOS_HEADER DosHeader(ULONG base)
{
        return (PIMAGE_DOS_HEADER)base;
}
PIMAGE_NT_HEADERS NtHeader(ULONG base)
{
        return (PIMAGE_NT_HEADERS)(DosHeader(base)->e_lfanew + base);
}
PIMAGE_FILE_HEADER FileHeader(ULONG base)
{
        return &NtHeader(base)->FileHeader;
}
PIMAGE_OPTIONAL_HEADER OptionalHeader(ULONG base)
{
        return &NtHeader(base)->OptionalHeader;
}

extern "C"
{
        // 定义一个全局变量,用于保存当前程序的加载基址
        unsigned long base = 0;

        // 这里导出了之后,加壳器就可以通过 GetProcAddress 获取了
        __declspec(dllexport) SHAREDATA share;

        // 获取当前程序的加载基址
        __declspec(naked) void GetBase()
        {
                __asm
                {
                        mov eax, fs: [0x30]
                        mov eax, [eax + 0x08]
                        mov base, eax
                        ret
                }
        }

        // 获取当前程序的加载基址
        __declspec(naked) void JmpOep()
        {
                __asm
                {
                        mov eax, base
                        add eax, share.old_oep
                        jmp eax
                }
        }

        // 从 LDR 获取 kernel32.dll 的基址
        DWORD GetKernelBase()
        {
                DWORD addr = 0;
                __asm
                {
                        mov eax, dword ptr fs : [0x30]
                        mov eax, dword ptr[eax + 0x0C]
                        mov eax, dword ptr[eax + 0x0C]
                        mov eax, dword ptr[eax]
                        mov eax, dword ptr[eax]
                        mov eax, dword ptr[eax + 0x18]
                }
        }

        _declspec(naked) void Asm()
        {
                __asm call SIGN
                __asm _emit 0XE9
                __asm _emit 0XEB
                __asm _emit 0X04
                SIGN:
                _asm pop eax
                _asm inc eax;
                _asm push eax
                _asm ret
        }

        // 自己的查找函数的函数
        DWORD MyGetProcAddress(DWORD Module, LPCSTR FunName)
        {
                // 获取 Dos 头和 Nt 头
                auto DosHeader = (PIMAGE_DOS_HEADER)Module;
                auto NtHeader = (PIMAGE_NT_HEADERS)(Module + DosHeader->e_lfanew);
                // 获取导出表结构
                DWORD ExportRva = NtHeader->OptionalHeader.DataDirectory[0].VirtualAddress;
                auto ExportTable = (PIMAGE_EXPORT_DIRECTORY)(Module + ExportRva);
                // 找到导出名称表、序号表、地址表
                auto NameTable = (DWORD*)(ExportTable->AddressOfNames + Module);
                auto FuncTable = (DWORD*)(ExportTable->AddressOfFunctions + Module);
                auto OrdinalTable = (WORD*)(ExportTable->AddressOfNameOrdinals + Module);
                // 遍历找名字
                for (DWORD i = 0; i < ExportTable->NumberOfNames; ++i)
                {
                        // 获取名字
                        char* Name = (char*)(NameTable[i] + Module);
                        if (!strcmp(Name, FunName))
                                return FuncTable[OrdinalTable[i]] + Module;
                }
                return -1;
        }

        // 动态的获取到所有的函数地址
        VOID GetApis()
        {
                ULONG kernelbase = GetKernelBase();
                MyVirtualProtect = (MYVirtualProtect)MyGetProcAddress(kernelbase, "GetProcAddress");
                pVirtualProtect = (FuncVirtualProtect)MyGetProcAddress(kernelbase, "VirtualProtect");
                pLoadLibraryA = (funcLoadLibraryA)MyGetProcAddress(kernelbase, "LoadLibraryA");
                pGetProcAddress = (funcGetProcAddress)MyGetProcAddress(kernelbase, "GetProcAddress");
                pVirtualAlloc = (funcVirtualAlloc)MyGetProcAddress(kernelbase, "VirtualAlloc");
                MyLoadLibraryExA = (MYLoadLibraryExA)MyGetProcAddress(kernelbase, "LoadLibraryExA");
                gUser32Base = MyLoadLibraryExA("User32.dll", NULL, NULL);
                MyRegisterClassA = (MYRegisterClassA)pGetProcAddress(gUser32Base, "RegisterClassA");
                MyCreateWindowExA = (MYCreateWindowExA)pGetProcAddress(gUser32Base, "CreateWindowExA");
                MyGetModuleHandleA = (MYGetModuleHandleA)MyGetProcAddress(kernelbase, "GetModuleHandleA");
                MyShowWindow = (MYShowWindow)pGetProcAddress(gUser32Base, "ShowWindow");
                MyUpdateWindow = (MYUpdateWindow)pGetProcAddress(gUser32Base, "UpdateWindow");
                MyGetMessageA = (MYGetMessageA)pGetProcAddress(gUser32Base, "GetMessageA");
                MyTranslateMessage = (MYTranslateMessage)pGetProcAddress(gUser32Base, "TranslateMessage");
                MyDispatchMessageA = (MYDispatchMessageA)pGetProcAddress(gUser32Base, "DispatchMessageA");
                MyDefWindowProcA = (MYDefWindowProcA)pGetProcAddress(gUser32Base, "DefWindowProcA");
                MyPostQuitMessage = (MYPostQuitMessage)pGetProcAddress(gUser32Base, "PostQuitMessage");
                MyGetClientRect = (MYGetClientRect)pGetProcAddress(gUser32Base, "GetClientRect");
                MyGetWindowTextA = (MYGetWindowTextA)pGetProcAddress(gUser32Base, "GetWindowTextA");
                MyGetDlgItem = (MYGetDlgItem)pGetProcAddress(gUser32Base, "GetDlgItem");
                HMODULE hVcruntime = MyLoadLibraryExA("vcruntime140.dll", NULL, NULL);
                Mymemcmp = (MYmemcmp)pGetProcAddress(hVcruntime, "memcmp");
                MyExitProcess = (MYExitProcess)pGetProcAddress(gUser32Base, "ExitProcess");
                MySendMessageA = (MYSendMessageA)pGetProcAddress(gUser32Base, "SendMessageA");
                MyMessageBoxA = (MYMessageBoxA)pGetProcAddress(gUser32Base, "MessageBoxA");

        }

        // 解密被加密的区段
        void XorSection()
        {
                /*
                        1. 计算出被加密区段的 va
                        2. 使用加壳器提供的大小和 key 解密区段
                        3. 由于代码段不可读写,所以需要修改属性
                */
                auto section = (unsigned char*)(base + share.xorsection);

                DWORD protect = 0;
                pVirtualProtect(section, share.xorsize, PAGE_READWRITE, &protect);
                for (unsigned long i = 0; i < share.xorsize; ++i)
                {
                        section[i] ^= share.xorkey;
                }
                pVirtualProtect(section, share.xorsize, protect, &protect);
        }

        // 修复被加密的导入表
        VOID FixIat()
        {
                /*
                        1. 找到原始程序的导入表
                        2. 遍历导入表,加载每一个导入表的 dll
                        3. 遍历 int,获取所有的函数名称
                        4. 使用 GetProcAddress 获取函数并写入 iat
                */

                auto import_table = (PIMAGE_IMPORT_DESCRIPTOR)(base + share.intrva);
                static BYTE shellcode[] = "\xB8\x00\x00\x00\x00\x35\x15\x15\x15\x15\xFF\xE0";

                while (import_table->Name)
                {
                        auto name = (char*)(import_table->Name + base);
                        HMODULE module = pLoadLibraryA(name);

                        ULONG* int_table = (ULONG*)(import_table->OriginalFirstThunk + base);
                        ULONG* iat_table = (ULONG*)(import_table->FirstThunk + base);

                        for (int i = 0; int_table[i]; ++i)
                        {
                                DWORD address = 0;
                                DWORD protect = 0;
                                pVirtualProtect(&iat_table[i], 4, PAGE_READWRITE, &protect);
                                if (int_table[i] & 0x80000000)
                                {
                                        address = (ULONG)pGetProcAddress(module, (LPCSTR)LOWORD(int_table[i]));
                                }
                                else
                                {
                                        auto name = (PIMAGE_IMPORT_BY_NAME)(int_table[i] + base);
                                        address = (ULONG)pGetProcAddress(module, name->Name);
                                }

                                PBYTE buffer = (PBYTE)pVirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
                                memcpy(buffer, shellcode, 13);
                                address ^= 0x15151515;
                                *((ULONG*)&buffer[1]) = address;
                                iat_table[i] = (ULONG)buffer;
                                pVirtualProtect(&iat_table[i], 4, protect, &protect);
                        }
                        import_table++;
                }

        }
        //回调函数
        LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
        {
                CHAR Buff[0x11] = { 0 };
                HWND h1000 = 0;
                DWORD Len = 0;
                switch (message)
                {
                case WM_CREATE:
                        MyCreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 200, 30, hWnd, (HMENU)0x1000, NULL, NULL);
                        MyCreateWindowExA(WS_EX_CLIENTEDGE, "BUTTON", "确定", WS_CHILD | WS_VISIBLE, 10, 40, 80, 30, hWnd, (HMENU)0x1001, NULL, NULL);
                        MyCreateWindowExA(WS_EX_CLIENTEDGE, "BUTTON", "取消", WS_CHILD | WS_VISIBLE, 100, 40, 80, 30, hWnd, (HMENU)0x1002, NULL, NULL);
                }
                if (hWnd == gParentWnd)
                {
                        switch (message)
                        {
                        case WM_CLOSE:
                                MyPostQuitMessage(0);
                                if (lParam != 100)
                                {
                                        MyExitProcess(0);
                                }
                                break;
                        case WM_COMMAND:
                        {
                                int nId = LOWORD(wParam);
                                switch (nId)
                                {
                                case 0x1001:
                                        if (HIWORD(wParam) == BN_CLICKED)
                                        {
                                                h1000 = MyGetDlgItem(gParentWnd, 0x1000);
                                                Len = MyGetWindowTextA(h1000, Buff, 0x10);
                                                if (Len == 0)
                                                {
                                                        MyMessageBoxA(0, "密码不能为空", "提示", 0);
                                                }
                                                else if (!Mymemcmp("1234", Buff, Len)) {
                                                        MyMessageBoxA(0, "继续", "提示", 0);
                                                        MySendMessageA(gParentWnd, WM_CLOSE, 0, 100);
                                                }
                                                else {
                                                        MyMessageBoxA(0, "退出", "Error", 0);
                                                }
                                        }
                                        break;
                                case 0x1002:
                                        MyExitProcess(0);
                                        break;
                                default:
                                        break;
                                }
                        }
                        }
                }
                return  MyDefWindowProcA(hWnd, message, wParam, lParam);
        };

        //密码弹框
        void PasswordDbg() {
                WNDCLASSA wc = { 0 };
                HMODULE hInstance = MyGetModuleHandleA(NULL);
                wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_DROPSHADOW | CS_NOCLOSE;
                wc.lpfnWndProc = WndProc;
                wc.cbClsExtra = 0;
                wc.cbWndExtra = 0;
                wc.hInstance = hInstance;//实例句柄,代表此程序
                wc.hIcon = 0;
                wc.hCursor = 0;
                wc.hbrBackground = 0;//BRUSH)GetStockObject(WHITE_BRUSH);
                wc.lpszMenuName = 0;//菜单
                wc.lpszClassName = "Password";
                MyRegisterClassA( & wc);
                gParentWnd = MyCreateWindowExA(
                        0,
                        "Password",
                        "密码",
                        WS_OVERLAPPEDWINDOW,
                        100, 200, 300, 130, 
                        NULL,               
                        NULL,               
                        hInstance,          
                        NULL                
                );
                //显示、更新窗口
                MyShowWindow(gParentWnd, SW_SHOW);
                MyUpdateWindow(gParentWnd);
                MSG msg = { 0 };
                while (MyGetMessageA(&msg, 0, 0, 0))
                {
                        MyTranslateMessage(&msg);
                        MyDispatchMessageA(&msg);
                }
                return;
        }

        //调用TIS
        void CallTls()
        {
                if (share.TlsVirtualAddress)
                {
                        //////恢复数据
                        //DWORD OldProtect = 0;
                        //MyVirtualProtect(&(OptionalHeader(gImageBase)->DataDirectory[9].VirtualAddress),
                        //        0x1000, PAGE_EXECUTE_READWRITE, &OldProtect);

                        //OptionalHeader(gImageBase)->DataDirectory[9].VirtualAddress = share.TlsVirtualAddress;
                        //MyVirtualProtect(&(OptionalHeader(gImageBase)->DataDirectory[9].VirtualAddress),
                        //        0x1000, OldProtect, &OldProtect);

                        //auto TlsTable = (PIMAGE_TLS_DIRECTORY)(OptionalHeader(gImageBase)->DataDirectory[9].VirtualAddress + gImageBase);
                        auto TlsTable = (PIMAGE_TLS_DIRECTORY)(share.TlsVirtualAddress + base);
                        //调用Tls
                        auto CallTlsTable = (PIMAGE_TLS_CALLBACK*)(TlsTable->AddressOfCallBacks);
                        while (*CallTlsTable)
                        {
                                (*CallTlsTable)((PVOID)gImageBase, DLL_PROCESS_ATTACH, NULL);
                                CallTlsTable++;
                        }
                }
        }

        // 修复重定位
        VOID FixReloc()
        {
                typedef struct _TYPEOFFSET
                {
                        WORD Offset : 12;
                        WORD Type : 4;
                }TYPEOFFSET, * PTYPEOFFSET;

                // 1.找到 DLL 重定位表,遍历其中的重定位块,以全 0 结构结尾
                auto reloc = (PIMAGE_BASE_RELOCATION)(share.dwRelocRva + base);

                // 2.解析重定位块,找到所有 Type 为 3 的项,使用上面的公式重定位
                while (reloc->SizeOfBlock)
                {
                        auto item = (PTYPEOFFSET)(reloc + 1);
                        ULONG count = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;

                        for (ULONG i = 0; i < count; i++)
                        {
                                DWORD old_protect = 0;
                                ULONG* address = (ULONG*)(item[i].Offset + reloc->VirtualAddress + base);
                                pVirtualProtect(address, 4, PAGE_READWRITE, &old_protect);
                                *address = *address - share.OldImageBase + base;
                                pVirtualProtect(address, 4, old_protect, &old_protect);
                        }
                        reloc = (PIMAGE_BASE_RELOCATION)((ULONG)reloc + reloc->SizeOfBlock);
                }
        }

        //反调试之 PEB+0x68
        VOID CheckNtGlobalFlag()
        {
                int NtGlobalFlag = 0;
                __asm {
                        push eax
                        mov eax, dword ptr fs : [0x30]
                        mov eax, dword ptr[eax + 0x68]
                        mov NtGlobalFlag, eax
                        pop eax
                }
                if (NtGlobalFlag == 0x70)
                {
                        MyMessageBoxA(0, "程序正在被调试", 0, 0);
                        //exit(-1);
                }
        }
        __declspec(dllexport) __declspec(naked) void start()
        {
                __asm
                {
                        xor eax,eax
                        test eax,eax
                        je text1
                        jne text2
                text2:
                        __asm _emit 0xE8
                text1:
                        call GetBase
                        call GetApis
                        call PasswordDbg
                        call XorSection
                        call FixIat
                        call FixReloc
                }
                CheckNtGlobalFlag();
                CallTls();
                __asm
                {
                        call JmpOep
                }
        }
}






温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
已有 1 人评分学币 理由
yxw88665588 + 1 感谢您的作品,赞一个!

总评分: 学币 + 1   查看全部评分

发表于 2021-4-3 18:51:58
格式有问题
发表于 2021-4-3 18:53:47
我给你修复了
Print动 发表于 2021-4-3 21:23 详情  回复
谢谢
发表于 2021-4-3 21:23:01

谢谢
发表于 2021-4-8 11:38:36
非常不错啊,感谢楼主无私的共享精神!

    发表于 2021-4-14 10:13:28
    感谢楼主分享

      发表于 2021-4-14 16:19:25
      感谢

        发表于 2021-11-13 20:06:55
        AddSection中有个bug,将data free掉后,new_section变成了野指针。修改PE后,不知道为什么崩溃在call Jmpoep那
        发表于 2021-11-15 12:54:20
        咸蛋超人 发表于 2021-11-13 20:06
        AddSection中有个bug,将data free掉后,new_section变成了野指针。修改PE后,不知道为什么崩溃在call Jmpo ...

        可以附加跟上去看一下

          发表于 2023-8-25 23:24:31
          太给力了,这么多好东西!

          小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

          GMT+8, 2024-4-27 07:42 , Processed in 0.113454 second(s), 83 queries .

          Powered by Discuz! X3.4

          Copyright © 2001-2021, Tencent Cloud.

          快速回复 返回顶部 返回列表