前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在非托管Main入口前加载函数(反调试机制)

在非托管Main入口前加载函数(反调试机制)

作者头像
江湖评谈
发布2023-08-31 21:35:36
1310
发布2023-08-31 21:35:36
举报
文章被收录于专栏:天下风云天下风云

1.前言 在非托管的C++里面,用户态下,Main函数入口是毫无疑问的首先运行。那么如果想要在Main入口前运行一些函数,应该怎么做呢?本篇看下

2.概括 其实PE里面提供了一个TLS回调函数,它是一个全局的可以存储全局变量,全局方法的RVA数据段。可以利用这个特点,来在Main之前运行方法。也可以利用这个特点,进行反调试机制。比如在TLS回调里面一旦发现调试,就直接退出程序。 这里搞一个小例子看下,以下x86环境下:

代码语言:javascript
复制
#include <windows.h>
#include<stdio.h>

//x86
#pragma comment(linker, "/INCLUDE:__tls_used")
//x64
//#pragma comment(linker, "/INCLUDE:_tls_used")

void print_console(char* szMsg)
{
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    WriteConsoleA(hStdout, szMsg, strlen(szMsg), NULL, NULL);
}

void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
    char szMsg[80] = { 0, };
    wsprintfA(szMsg, "TLS_CALLBACK1() : DllHandle = %X, Reason = %d\n", DllHandle, Reason);
    print_console(szMsg);
}

void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
    char szMsg[80] = { 0, };
    wsprintfA(szMsg, "TLS_CALLBACK2() : DllHandle = %X, Reason = %d\n", DllHandle, Reason);
    print_console(szMsg);
}

//x86
#pragma data_seg(".CRT$XLX")
PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, 0 };
#pragma data_seg()

//x64
//#pragma const_seg (".CRT$XLB")
//const
//PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, 0 };
//#pragma const_seg ()

DWORD WINAPI ThreadProc(LPVOID lParam)
{
    char szMsg[20] = { 0, };
    wsprintfA(szMsg, "ThreadProc() start\n");
    print_console(szMsg);

    char szMsg1[20] = { 0, };
    wsprintfA(szMsg1, "ThreadProc() end\n");
    print_console(szMsg1);

    return 0;
}

int main(void)
{
    HANDLE hThread = NULL;

    char szMsg[20] = { 0, };
    wsprintfA(szMsg, "main() start\n");
    print_console(szMsg);

    hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
    WaitForSingleObject(hThread, 60 * 1000);
    CloseHandle(hThread);

    char szMsg1[20] = { 0, };
    wsprintfA(szMsg1, "main() end\n");
    print_console(szMsg1);

    getchar();
    return 0;
}

运行结果:

代码语言:javascript
复制
TLS_CALLBACK1() : DllHandle = F80000, Reason = 1
TLS_CALLBACK2() : DllHandle = F80000, Reason = 1
main() start
TLS_CALLBACK1() : DllHandle = F80000, Reason = 2
TLS_CALLBACK2() : DllHandle = F80000, Reason = 2
ThreadProc() start
ThreadProc() end
TLS_CALLBACK1() : DllHandle = F80000, Reason = 3
TLS_CALLBACK2() : DllHandle = F80000, Reason = 3
main() end

可以看到在main函数之前,运行了TLS_CALLBACK1和TLS_CALLBACK2函数。

比如可以在TLS_CALLBACK1函数里面添加如下检测是否调试的代码:

代码语言:javascript
复制
void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
    if (IsDebuggerPresent() == 1)
    {
        exit(1);
    }
    char szMsg[80] = { 0, };
    wsprintfA(szMsg, "TLS_CALLBACK1() : DllHandle = %X, Reason = %d\n", DllHandle, Reason);
    print_console(szMsg);
}

如果调试当前程序,则IsDebuggerPresent()==1,直接退出当前程序。这是最简单的反调试思路。

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-08-27,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 江湖评谈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com