吾爱汇编论坛

 找回密码
 立即注册

QQ登录

绑定QQ避免忘记帐号

查看: 2702|回复: 89

[原创逆向图文] EProtect Ver:1.0.6.4 脱壳

  [复制链接]

  离线 

李沉舟 发表于 2020-7-20 20:29 | 显示全部楼层 |阅读模式


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

Step.1 寻找OEP

找到标题为 “进入软件” 这一按钮的按钮事件。
1.png
在按钮事件上下断点。
中断后,不断单步步过CALL指令,如果经过某CALL后,程序跑飞,则进入该CALL内部。继续单步步过CALL指令。
在重复几次后,我来到了这个CALL。
[Asm] 纯文本查看 复制代码
004B4B40    50              push eax                                 ; ep_hello.0045D9A7
004B4B41    FF75 FC         push dword ptr ss:[ebp-0x4]              ; ep_hello.004B693D
004B4B44    FF75 CC         push dword ptr ss:[ebp-0x34]
004B4B47    E8 C81D0000     call ep_hello.004B6914

然后打开内存页面
2.png
在代码区块上下一个访问断点,F9运行时到达OEP。

[Asm] 纯文本查看 复制代码
0045D9A7  /.  55            push ebp


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

Step.2 IAT修复


随便找到一个API调用,解码,找到IAT地址,下一个硬件写入断点,中断后回溯,来到此处。
[Asm] 纯文本查看 复制代码
004B528A    FF75 E4         push    dword ptr [ebp-1C]
004B528D    FF75 14         push    dword ptr [ebp+14]
004B5290    E8 66F1FFFF     call    004B43FB

这里就在填充IAT,有两种类型,一种填进去的就是真实API地址,还有一类填进去的是一个stub函数地址,通过这个stub函数来解码出真实的API地址。
3.png
现在我选中的是真正无效的,删掉就好了。
4.png
这一次选中的是有效的,但是指向的是stub函数,我们要修复IAT,就必须解码出真实的API地址写入IAT表。
5.png
6.png


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


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

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

下面给出代码。
[C++] 纯文本查看 复制代码
// 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[i];
		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[i], &ct.Eip, sizeof(DWORD), &t);
							if (t != 4) {
								printf("Fail: %08X, %08X\r\n", iat_addr[i], ct.Eip);
							}
							else {
								printf("Succeed: %08X, %08X\r\n", iat_addr[i], 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,程序会列出修复结果。
19.png

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

29.png

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

30.png

1234.png

脱壳后的程序:
链接: 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




5.png

评分

参与人数 24威望 +1 HB +128 THX +14 收起 理由
xgbnapsua + 1
平安 + 1
fjgh + 2 + 1 [吾爱汇编论坛 52HB.COM]-学破解防破解,知进攻懂防守!
zxjzzh + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
无影无踪 + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
无极剑圣啊 + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
清风而已 + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
我是好人 + 1 [吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意!
playboy + 1
hao11242536 + 1 + 1 [吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意!
kickic + 1
ldljlzw + 1
晚安说给自己听 + 2 + 1 学习了,感谢分享
liugu0hai + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
zwc123xyz + 1 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
bnjzzheng + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
mengzhisuoliu + 1
kaoliu35 + 1
BlackWatch + 1 + 1 大佬,upx 3.96版本下次能讲讲吗,我脱完可修复IAT老是出问题。膜拜大佬
CrackPro + 1 + 1 --------
叩瞳白蓝 + 4 + 1 醒!危!速回!
千里丶 + 5 + 1 我只能默默的评分了!!!
yAYa + 2 + 1 只要是关于壳的就加分~
Shark恒 + 1 + 100 + 1 [快捷评语]--你将受到所有人的崇拜!

查看全部评分

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   56.67%

yAYa 发表于 2020-7-20 21:33 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   86.96%

打不死的小强强 发表于 2020-7-20 22:21 | 显示全部楼层


太强了 大佬牛逼
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   10%

pipi9 发表于 2020-7-21 09:25 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   20%

leroy特洛伊 发表于 2020-7-21 13:57 | 显示全部楼层


牛逼啊  最新版
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   45%

BlackWatch 发表于 2020-8-7 17:34 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   30%

pansophy 发表于 2020-8-7 23:36 | 显示全部楼层


感谢分享,收藏慢慢学习
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   8%

保安 发表于 2021-12-9 18:28 | 显示全部楼层


感谢分享  收藏学习
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   0%

愤怒的亚索 发表于 2022-1-10 17:03 来自手机端 | 显示全部楼层


有保存了文件的大哥没
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM

  离线 

升级   50%

zwc123xyz 发表于 2022-1-10 22:36 | 显示全部楼层


学习了!感谢楼主的细致讲解!!!
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则 警告:本站严惩灌水回复,尊重自己从尊重他人开始!

1层
2层
3层
4层
5层
6层
7层
8层
9层
10层

免责声明

吾爱汇编论坛(www.52hb.com)所发布的破解补丁、注册机、逆向教程、逆向文章等,包含但不限于上述内容,仅限用于学习和研究目的,不得用于非法途径或商业行为。否则,一切后果请用户自行承担。本站内容源于网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除。如果您喜欢某程序,请购买正版,支持正版,获得正版优质服务。如有侵权请邮件或微信与我们联系处理。

站长邮箱:SharkHeng@iCloud.com
站长微信:SharkHeng


QQ|RSS|手机版|小黑屋|帮助|吾爱汇编论坛 ( 京公网安备11011502005403号 , 京ICP备20003498号 )

GMT+8, 2022-5-29 03:11 , Processed in 0.611107 second(s), 78 queries .

Powered by Discuz!

吾爱汇编论坛 www.52hb.com

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