Re_绕过tls_与_smc保护

在main函数前,还有什么

TLS

1、何为tls

TLS回调函数是指,每当创建/终止进程的线程时会自动调用执行的函数。创建的主线程也会自动调用回调函数,且其调用执行先于EP代码。

2、编写tls函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <windows.h>
#include<stdio.h>
#include <winnt.h>
#include <stdlib.h>
#include <tlhelp32.h>
////////////////////////////////////////////////////////////////////////////////
//使用tls 回调函数
//使用TLS 的宏
#pragma comment(linker, "/INCLUDE:__tls_used")
void lookupprocess()
{
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // 在快照中包含系统中所有的进程
BOOL bMore = Process32First(hProcessSnap, &pe32); // 获得第一个进程的句柄
while (bMore)
{
_wcslwr_s(pe32.szExeFile, wcslen(pe32.szExeFile)+1);
if (!wcscmp(pe32.szExeFile, L"ollyice.exe"))
{
printf("///////WARNING///////\n");
exit(0);
}
if (!wcscmp(pe32.szExeFile, L"ollydbg.exe"))
{
printf("///////\nWARNING\n///////\n");
exit(0);
}
if (!wcscmp(pe32.szExeFile, L"peid.exe"))
{
printf("///////\nWARNING\n///////\n");
exit(0);
}
if (!wcscmp(pe32.szExeFile, L"ida.exe"))
{
printf("///////\nWARNING\n///////\n");
exit(0);
}
if (!wcscmp(pe32.szExeFile, L"idaq.exe"))
{
printf("///////\nWARNING\n///////\n");
exit(0);
}
bMore = Process32Next(hProcessSnap, &pe32); // 获取下一个进程的句柄
}
CloseHandle(hProcessSnap);
}
void Debugger(void) {
int result = 0;
__asm {
mov eax, dword ptr fs:[30h]//TEB偏移30H处
movzx eax, byte ptr ds:[eax + 2h]//取PEB中BeingDebug,若为1则被调试
mov result, eax
}
if (result) {
printf("///////\nWARNING\n///////\n");
exit(0);
}
}
void NTAPI tls_callback(PVOID h, DWORD reason, PVOID pv)
{
lookupprocess();
Debugger();
MessageBox(NULL, L"Not_Main_this_is_tls!", L"tls", MB_OK);
return;
}
#pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK p_thread_callback[] = { tls_callback, 0 };
#pragma data_seg()
////////////////////////////////////////////////////////////////////////////////
int main()
{
MessageBox(NULL, L"Main!", L"ESE", MB_OK);
return 0;
}

3、实践

TLS callback函数的定义

1
2
3
4
5
6
7
8
9
10
11
12
typedef VOID
(NTAPI *PIMAGE_TLS_CALLBACK) (
PVOID DllHandle, //模块句柄,即加载地址
DWORD Reason,
PVOID Reserved
);
其中reason有以下几种:(winNT.h)
#define DLL_PROCESS_ATTACH 1 进程启动
#define DLL_THREAD_ATTACH 2 线程启动
#define DLL_THREAD_DETACH 3 线程退出
#define DLL_PROCESS_DETACH 0 进程退出

3、手动去除TLS函数

例如:ida打开是这样的

那就有TLS函数
1、OD去除TLS函数
OD运行,f9直接退出,因为会先执行TLS函数,这时需要设置成这样

这就可以停在系统断点,可以看看tls函数做了什么,一般都是判断是否使用工具,ida,od,peid,如果有使用其中一种,程序直接退出,不会执行main函数
接着就一步一步的找TLS函数,找到直接把tls函数nop。
2、利用PEviewEXE和winhex去掉TLS函数
利用PEviewEXE查看PE文件的结构体,发现TLS结构体

修改1

修改为

修改2


修改为

将修改后的文件另存为111.exe,ida打开

这是已经去掉TLS函数了,收工

SMC

SMC是一种局部代码加密技术,通过对一段代码进行加密来达到增加逆向工程难度或者免杀的目的。SMC 技术是病毒常用的技巧。SMC不仅能使用汇编上实现,还能很容易的使用VC实现,但是有一个比较致命缺陷:要精准的定位某个函数非常麻烦,所以我们就要以区块为加密的基础单位。

预备知识

需要一点点的PE结构基础就ok啦。加密需要一个加密函数,这里我用简单的xor函数

1
2
3
4
5
6
7
8
9
//加密函数
void enc(char *start,int len)
{
int i;
for(i=0;i<len;i++) //这里对地址进行简单的加密>
{
*(start+i) ^=0x88;
}
}

编写SMC

所谓SMC(Self Modifying Code)技术,就是一种将可执行文件中的代码或数据进行加密,防止别人使用逆向工程工具(比如一些常见的反汇编工具)对程分序进行静态析的方法,只有程序运行时才对代码和数据进行解密,从而正常运行程序和访问数据。计算机病毒通常也会采用SMC技术动态修改内存中的可执行代码来达到变形或对代码加密的目的,从而躲过杀毒软件的查杀或者迷惑反病毒工作者对代码进行分析。
因为定位一个具体的函数很繁琐,所以我们选择直接定位一个节表。把敏感的代码放入节表中,然后在需要的时候进行解密,这就是SMC动态加密技术的精髓。

如何把敏感代码放入一个节表中?

1
#pragma comment(linker, "/SECTION:.text,ERWS")

将这句话放在开始程序的开始(也就是include下面),主要是让text节区可以执行(E)读(R)写(W)分享(S)

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#pragma comment(linker, "/SECTION:.text,ERWS")
void enc(char *start,int len)
{
int i;
for(i=0;i<len;i++) //这里对地址进行简单的加密>
{
*(start+i) ^=0x88;
}
}
//需要保护的函数
void ck()
{
printf("this is a test of smc");
}
//加密数据结束的地址
void end(){}
int main()
{
char *lp_s = 0;
char *lp_e = 0;
int len=0;
lp_s = (char *)ck; //获取需要加密函数的起始地址
lp_e = (char *)end; //获取需要加密函数的结束地址
len=lp_e-lp_s;
enc(lp_s,len); //smc加密函数
ck();
}

现在,现在可以编译通过,生成test,但是无法运行,因为ck()函数的地址已经被打乱啦,这时候就利用OD进行修改,载入生成的程序,当程序运行enc()函数完成时,这时ck就已经完成加密啦,然后将程序dump下来test1。这时就可以运行啦。若拿
test去静态看时,完全看不懂ck的代码(这就进行smc加密啦)。

解密SMC

1、找到smc的加密函数,当运行完成smc解密函数时,将程序dump下来。
2、smc对程序动态完全没有用,可以用OD来调试程序,找到受保护代码

Donate
-------------本文结束感谢您的阅读-------------