李沉舟 发表于 2020-7-20 20:29

EProtect Ver:1.0.6.4 脱壳

https://www.52pojie.cn/thread-1191986-1-1.html
在吾爱破解论坛看到的,这壳又出新版了。

Step.1 寻找OEP

找到标题为 “进入软件” 这一按钮的按钮事件。

在按钮事件上下断点。
中断后,不断单步步过CALL指令,如果经过某CALL后,程序跑飞,则进入该CALL内部。继续单步步过CALL指令。
在重复几次后,我来到了这个CALL。
004B4B40    50            push eax                                 ; ep_hello.0045D9A7
004B4B41    FF75 FC         push dword ptr ss:            ; ep_hello.004B693D
004B4B44    FF75 CC         push dword ptr ss:
004B4B47    E8 C81D0000   call ep_hello.004B6914

然后打开内存页面

在代码区块上下一个访问断点,F9运行时到达OEP。

0045D9A7/.55            push ebp


用OD把它dump出来,不过把重建输入表去掉。

Step.2 IAT修复


随便找到一个API调用,解码,找到IAT地址,下一个硬件写入断点,中断后回溯,来到此处。
004B528A    FF75 E4         push    dword ptr
004B528D    FF75 14         push    dword ptr
004B5290    E8 66F1FFFF   call    004B43FB

这里就在填充IAT,有两种类型,一种填进去的就是真实API地址,还有一类填进去的是一个stub函数地址,通过这个stub函数来解码出真实的API地址。

现在我选中的是真正无效的,删掉就好了。

这一次选中的是有效的,但是指向的是stub函数,我们要修复IAT,就必须解码出真实的API地址写入IAT表。




随便挑一个,给各位看一下stub函数的样子。


显然,stub函数经过ret指令后会跳转到真正的api地址,现在我们开始考虑如何进行跟踪。
简单说下我的思路:
1.搜集所有stub函数首地址
2.创建新线程执行stub函数
3.设置tf位,如果单步一次后程序的eip变化较大(比如>1000),这就说明程序肯定跳进其它模块里面了,这个时候取程序eip写进IAT里面就好了

P.S. :
程序每次运行时候stub函数的生成是随机的,也就是程序会随机挑选一些API生成stub函数。所以我给出的代码里记得修改getStubAddr()函数里的地址!!!!!!!!!

下面给出代码。
// FixIAT.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <tlhelp32.h>
#include <stdlib.h>
#include <vector>

#define SE_DEBUG_PRIVILEGE 20

using namespace std;

typedef DWORD(WINAPI *PRtlAdjustPrivilege) (
        ULONG    Privilege,
        BOOLEAN Enable,
        BOOLEAN CurrentThread,
        PBOOLEAN Enabled);

DWORD pid;
vector<DWORD> stub_addr;
vector<DWORD> iat_addr;
HANDLE hp;

void AdjustPrivilege() {
        BOOLEAN Enabled;
        PRtlAdjustPrivilege RtlAdjustPrivilege = (PRtlAdjustPrivilege)GetProcAddress(LoadLibraryA((LPCSTR)"ntdll.dll"), "RtlAdjustPrivilege");
        RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &Enabled);
}

bool getStubFunc() {
        DWORD addr;
        DWORD t;
        for (DWORD i = 0x47D170; i <= 0x47D1D0; i += 4) {
                ReadProcessMemory(hp, (LPCVOID)i, &addr, sizeof(DWORD), &t);
                if (t != sizeof(DWORD)) {
                        printf("What the fuck stub addr?\r\n");
                        getchar();
                        return false;
                }
                stub_addr.push_back(addr);
                iat_addr.push_back(i);
        }
        ReadProcessMemory(hp, (LPCVOID)0x47D1EC, &addr, sizeof(DWORD), &t);
        stub_addr.push_back(addr);
        iat_addr.push_back(0x47D1EC);
        if (t != sizeof(DWORD)) {
                printf("What the fuck stub addr?\r\n");
                getchar();
                return false;
        }
        ReadProcessMemory(hp, (LPCVOID)0x47D1E4, &addr, sizeof(DWORD), &t);
        stub_addr.push_back(addr);
        iat_addr.push_back(0x47D1E4);
        if (t != sizeof(DWORD)) {
                printf("What the fuck stub addr?\r\n");
                getchar();
                return false;
        }
        ReadProcessMemory(hp, (LPCVOID)0x47D310, &addr, sizeof(DWORD), &t);
        stub_addr.push_back(addr);
        iat_addr.push_back(0x47D310);
        if (t != sizeof(DWORD)) {
                printf("What the fuck stub addr?\r\n");
                getchar();
                return false;
        }
/*        ReadProcessMemory(hp, (LPCVOID)0x47D200, &addr, sizeof(DWORD), &t);
        stub_addr.push_back(addr);
        if (t != sizeof(DWORD)) {
                getchar();
                printf("What the fuck stub addr?\r\n");
                return false;
        }
        ReadProcessMemory(hp, (LPCVOID)0x47D398, &addr, sizeof(DWORD), &t);
        stub_addr.push_back(addr);
        if (t != sizeof(DWORD)) {
                getchar();
                printf("What the fuck stub addr?\r\n");
                return false;
        }*/
        return true;
}

bool getIAT() {
        LPVOID addr;
        DWORD tid;
        DWORD t;
        HANDLE ht;
        CONTEXT ct;
        DEBUG_EVENT dbg;
        DWORD last_eip;
        bool state;
        unsigned char c3 = 0xCC;
        char opcode;
        for (unsigned int i = 0; i < stub_addr.size(); i++) {

                addr = (LPVOID)stub_addr;
                ht = CreateRemoteThread(hp, NULL, 0, (LPTHREAD_START_ROUTINE)addr, NULL, CREATE_SUSPENDED, &tid);
                if (ht == INVALID_HANDLE_VALUE) {
                        printf("What the fuck CreateRemoteThread?\r\n");
                        return false;
                }
                /*ct.ContextFlags = CONTEXT_FULL;
                GetThreadContext(ht, &ct);
                last_eip = ct.Eip;
                ct.EFlags &= 0x100; //set IF = 1
                SetThreadContext(ht, &ct);*/
                ReadProcessMemory(hp, addr, &opcode, 1, &t);
                WriteProcessMemory(hp, addr, &c3, 1, &t);
                ResumeThread(ht);
                state = true;
                while (state) {
                        WaitForDebugEvent(&dbg, INFINITE);
                        switch (dbg.dwDebugEventCode) {
                                case EXCEPTION_DEBUG_EVENT:
                                        if (dbg.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) {
                                                ct.ContextFlags = CONTEXT_FULL;
                                                GetThreadContext(ht, &ct);
                                                ct.EFlags |= 0x100; //set IF = 1
                                                if (abs((int)last_eip - (int)ct.Eip) >= 1000) {
                                                        WriteProcessMemory(hp, (LPVOID)iat_addr, &ct.Eip, sizeof(DWORD), &t);
                                                        if (t != 4) {
                                                                printf("Fail: %08X, %08X\r\n", iat_addr, ct.Eip);
                                                        }
                                                        else {
                                                                printf("Succeed: %08X, %08X\r\n", iat_addr, ct.Eip);
                                                        }
                                                        TerminateThread(ht, 0);
                                                        state = false;
                                                }
                                                else {
                                                        last_eip = ct.Eip;
                                                        SetThreadContext(ht, &ct);
                                                }
                                                ContinueDebugEvent(pid, dbg.dwThreadId, DBG_CONTINUE);
                                        }
                                        else if (dbg.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) {
                                                if (dbg.u.Exception.ExceptionRecord.ExceptionAddress == LPVOID((DWORD)addr)) {
                                                        WriteProcessMemory(hp, addr, &opcode, 1, &t);
                                                        ct.ContextFlags = CONTEXT_FULL;
                                                        GetThreadContext(ht, &ct);
                                                        ct.Eip--;
                                                        last_eip = ct.Eip;
                                                        ct.EFlags |= 0x100; //set IF = 1
                                                        SetThreadContext(ht, &ct);
                                                        ContinueDebugEvent(pid, dbg.dwThreadId, DBG_CONTINUE);
                                                }
                                                else {
                                                        ContinueDebugEvent(pid, dbg.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
                                                }
                                               
                                        }
                                        else {
                                                ContinueDebugEvent(pid, dbg.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
                                        }
                                        break;
                                case EXIT_PROCESS_DEBUG_EVENT:
                                        printf("Why does the fuck process has been terminated?\r\n");
                                        ContinueDebugEvent(pid, dbg.dwThreadId, DBG_CONTINUE);
                                        return false;
                                        break;
                                case CREATE_THREAD_DEBUG_EVENT:
                                        ContinueDebugEvent(pid, dbg.dwThreadId, DBG_CONTINUE);
                                        break;
                                default:
                                        ContinueDebugEvent(pid, dbg.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
                        }
                }
                CloseHandle(ht);
        }
        return true;
}

bool supAllThreads() {
        HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
        THREADENTRY32 te = {0};
        HANDLE ht;
        if (h == INVALID_HANDLE_VALUE) {
                return false;
        }
        te.dwSize = sizeof(te);
        BOOL state = Thread32First(h, &te);
        while (state) {
                if (te.th32OwnerProcessID != pid) {
                        state = Thread32Next(h, &te);
                        continue;
                }
                ht = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
                SuspendThread(ht);
                state = Thread32Next(h, &te);
                CloseHandle(ht);
        }
        CloseHandle(h);
        return true;
}

int _tmain(int argc, _TCHAR* argv[])
{
        AdjustPrivilege();
        scanf("%d", &pid);
        hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
        supAllThreads();
        DebugActiveProcess(pid);
        if (hp == NULL) {
                printf("What the fuck pid and uac?\r\n");
                getchar();
                return -1;
        }
        getStubFunc();
        getIAT();
        DebugActiveProcessStop(pid);
        system("pause");
        return 0;
}

运行以后输入进程ID,程序会列出修复结果。


修复完成后再用IMPORT REC重建程序导入表。



注意勾选这个选项,否则它会重建一份新IAT,等于白给。





脱壳后的程序:
链接: https://pan.baidu.com/s/1tDYeXdFRKFMMQNj07g8X9Q 提取码: zi9b


IAT Tree:
链接: https://pan.baidu.com/s/1ZgWev3N3vDolBQ8oR_kz7A 提取码: ms8e


FixIAT完整工程文件(VS2008):
链接: https://pan.baidu.com/s/1RaNPkoRpO-pq6e7lwJE82g 提取码: rqua




yAYa 发表于 2020-7-20 21:33

依旧羡慕玩壳的师傅~

打不死的小强强 发表于 2020-7-20 22:21

太强了 大佬牛逼

pipi9 发表于 2020-7-21 09:25

羡慕大佬 大佬牛逼

leroy特洛伊 发表于 2020-7-21 13:57

牛逼啊最新版

BlackWatch 发表于 2020-8-7 17:34

好东西学到了。thanks!

pansophy 发表于 2020-8-7 23:36

感谢分享,收藏慢慢学习

保安 发表于 2021-12-9 18:28

感谢分享收藏学习

愤怒的亚索 发表于 2022-1-10 17:03

有保存了文件的大哥没

zwc123xyz 发表于 2022-1-10 22:36

学习了!感谢楼主的细致讲解!!!
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: EProtect Ver:1.0.6.4 脱壳