12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
三国霸业 战车-珍宝-觉醒-攻城掠地SF-全新玩法 免费玩新区 攻城掠地私服 进入游戏
手游私服盒子 各类免费游戏 0.1折送海量资源 各类手游私服 进入游戏
皇家MU2 《奇迹 2:传奇》韩国网禅公司《奇迹》正统续作。 3D锁视角Mmrpg 暗黑3+传奇+流放之路+奇迹 进入游戏
查看: 246|回复: 0

反调试技术实现小结

[复制链接]
发表于 2020-6-30 22:43:10 | 显示全部楼层 |阅读模式
前言


随着软件逆向工程技术的快速发展,针对各种软件的分析破解技术层出不穷,动态调试技术也在不断的发展中,那么在这种环境下,就非常需要反调试技术了,反调试成了一种防止破解的一种手段,很好得使用反调试,可以保护软件。接下来,给大家分享一下我实现过的反调试技术及对应的反反调式技术。
BeingDebugged判断法


1.在PEB结构中,有BeingDebugged成员,当程序处于调式状态时,该成员的值会变为1,否则为0.根据这个特性可以判断程序是否处于调式状态,fs寄存器偏移0x18处指向TEB结构,TEB结构偏移0x30处指向PEB结构,PEB结构偏移0x2处即为BeingDebugged成员,TEB和PEB结构如下。
[Asm] 纯文本查看 复制代码typedef struct _NT_TEB{    ........    PVOID ThreadLocalStoragePointer;    // 2Ch    PPEB Peb;                           // 30h  push dword ptr fs:[0]                    ;  添加SEH异常处理器00401078  |.  64:8925 00000>mov dword ptr fs:[0],esp0040107F  |.  90            nop00401080  |.  90            nop00401081  |.  90            nop00401082  |.  90            nop00401083  |.  33C0          xor eax,eax00401085  |.  C700 01000000 mov dword ptr ds:[eax],0x10040108B  |.  90            nop0040108C  |.  0000          add byte ptr ds:[eax],al0040108E  |.  6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL00401090  |.  6A 00         push 0x0                                 ; |Title = NULL00401092  |.  68 20304000   push seh_add1.00403020                   ; |Text = "Debugging"00401097  |.  6A 00         push 0x0                                 ; |hOwner = NULL00401099      E8 C2FFFFFF   call 0040109E  |.  64:8F05 00000>pop dword ptr fs:[0]                     ;  删除SEH程序004010A5  |.  83C4 04       add esp,0x4004010A8  |.  6A 00         push 0x0                                 ; /ExitCode = 0x0004010AA      E8 B7FFFFFF   call 004010AF   .  C3            retn004010B0      90            nop004010B1      90            nop004010B2      90            nop004010B3      90            nop004010B4      90            nop004010B5      90            nop004010B6      90            nop004010B7      90            nop004010B8  /$  8B7424 0C     mov esi,dword ptr ss:[esp+0xC]           ;  结构异常处理程序; Structured exception handler004010BC  |.  64:A1 3000000>mov eax,dword ptr fs:[0x30]004010C2  |.  8078 02 01    cmp byte ptr ds:[eax+0x2],0x1            ;  判断BeingDebugged的值是否为1004010C6  |.  75 0C         jnz short seh_add1.004010D4              ;  没有处于调式状态时,进行跳转004010C8  |.  C786 B8000000>mov dword ptr ds:[esi+0xB8],seh_add1.004>;  把EIP修改为40108e,弹出消息提示框004010D2  |.  EB 0A         jmp short seh_add1.004010DE004010D4  |>  C786 B8000000>mov dword ptr ds:[esi+0xB8],seh_add1.004>;  把EIP修改为原OEP004010DE  |>  33C0          xor eax,eax004010E0  \.  C3            retn
4.在内存窗口,可以看到该汇编代码对应的shellcode。通过手动的方式添加反调试代码必然麻烦,那么就需要开发一个工具来实现seh反调试的添加功能.该工具的实现思路是:加载PE文件到内存中->在代码段处查找空白代码区,记录该区的地址-》搜索空白代码区,添加debugging字符串->计算调用函数的汇编代码-》修改shellcode,导出PE文件到磁盘中。

5.工具实现的重要的代码如下,
[C++] 纯文本查看 复制代码LPVOID CAllToolDlg::PEFileToMemory(LPSTR lpszFile){        FILE *pFile = NULL;        LPVOID pFileBuffer = NULL;        errno_t err;                if (!(err = fopen_s(&pFile, lpszFile, &quot;wr+&quot;)))        {                printf(&quot; 无法打开 EXE 文件! &quot;);                return NULL;        }        //读取文件大小        fseek(pFile, 0, SEEK_END);        fileSize = ftell(pFile);        fseek(pFile, 0, SEEK_SET);        //分配缓冲区        pFileBuffer = malloc(fileSize);        //将文件数据读取到缓冲区        size_t n = fread(pFileBuffer, fileSize, 1, pFile);        if (!n)        {                printf(&quot; 读取数据失败! &quot;);                free(pFileBuffer);                fclose(pFile);                return NULL;        }        //关闭文件        fclose(pFile);        return pFileBuffer;}//搜索代码段空白代码DWORD CAllToolDlg::FindEmptyCodeAndModifyShellCode(){        //把exe文件加载进内存        //pFileBuffer = PEFileToMemory(strpath);        DWORD* DPointer = (DWORD*)pFileBuffer;        BYTE* BPointer = (BYTE*)pFileBuffer;        DWORD ImageBase = *(DPointer + 59);        DWORD AddrEP = *(DPointer + 56);        //修改OEP的值        ModifyShellCode(ImageBase + AddrEP, 0x6E);        //记录空白代码区的起始地址        DWORD BeginAddr = 0;        int i = 0;        //找出空白代码区的起始地址        for (int j = 0x1000; j < 0x1000/4; j++)        {                if (*(DPointer + j) == 0x0)                {                        i++;                        if (i >= 30)                                break;                }                else                {                        i = 0;                        BeginAddr = j+1;                }        }        //AddressOfEntryPoint修改后的值        DWORD AfterAddrEP = BeginAddr*4 + 0x1000;        //修改AddressOfEntryPoint        *(DPointer + 56) = AfterAddrEP;        //获取MessageBoxA和EXitProcess的十六进制编码并修改        DWORD MessageBoxA = AddrMessageBoxA - (0x400000 + AfterAddrEP + 0x2D + 0x5);        ModifyShellCode(MessageBoxA,0x2E);        DWORD EXitProcess = AddrEXitProcess  - (0x400000 + AfterAddrEP + 0x3E + 0x5);        ModifyShellCode(EXitProcess, 0x3F);        return AfterAddrEP;}//搜索数据段空白数据void CAllToolDlg::FindEmptyDataAndAddData(){                int i = 0;        DWORD BeginAddr = 0;        for (int j = 0x3000; j < 0x1000/4; j++)        {                if (*(DPointer + j) == 0x0)                {                        i++;                        if (i >= 3)                                break;                }                else                {                        i = 0;                        BeginAddr = j + 1;                }        }        //修改内存数据        for (i = 0; i < strlen(s); i++)        {                *(BPointer + i + BeginAddr) = s;        }        DWORD AddrData = 0x3000 + BeginAddr * 4 + 0x400000;        ModifyShellCode(AddrData, 0x28);}void CAllToolDlg::WriterToPEFileAndDisk(DWORD Addr){        for (int i = 0; i < len; i++)        {                *(BPointer + i + Addr) = ShellCode;        }        //写入磁盘中        ofstream out(&quot;seh_add.exe&quot;, ios::out | ios::trunc);        if (!out.is_open())        {                cout e_lfanew)) != IMAGE_NT_SIGNATURE)        {                printf(&quot;不是有效的PE标志\n&quot;);                free(pFileBuffer);                return;        }        pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);        //节表数量        NumberOfSection = pPEHeader->NumberOfSections;                //最后节表位置        LastSectionAddr = PEOptionalAddress + pPEHeader->SizeOfOptionalHeader + (NumberOfSection - 1) * 0x28;        DWORD* DPointer = (DWORD*)pFileBuffer;        //PointerToRawData值        LastPointerToRawDataV = *(DPointer + LastSectionAddr+0xC);}//修改字段值VOID CAllToolDlg::ModifyMemoryValue(){        //修改TLS表中的RVA值        *(DPointer + PEOptionalAddress + 0xA8) = LastPointerToRawDataV + 0x200 + (NumberOfSection - 1) * 0x28;        //修改TLS表中的Size值,_IMAGE_TLS_DIRECTORY32结构大小        *(DPointer + PEOptionalAddress + 0xAC) = 0x18;        //SizeOfRawData值加0x200        *(DPointer + LastSectionAddr + 0x8) = *(DPointer + LastSectionAddr + 0x8) + 0x200;        //PointerToRawData值加0x200        *(DPointer + LastSectionAddr + 0xC) = LastPointerToRawDataV + 0x200;        //修改Characteristics值        *(BPointer + LastSectionAddr + 0x1C) = 0xE0;}//给TLS结构体赋值VOID CAllToolDlg::WriterToNewTls(){        DWORD Value = 0x400000 + 0x18 + *(DPointer + PEOptionalAddress + 0xA8);        *(DPointer + fileSize + 0x200) = Value;        *(DPointer + fileSize + 0x204) = Value+0x4;        *(DPointer + fileSize + 0x208) = Value + 0x8;        *(DPointer + fileSize + 0x20C) = Value + 0xC;        *(DPointer + fileSize + 0x224) = 0x400000 +  *(DPointer + PEOptionalAddress + 0xA8)+0x30;}//往PE文件中写入TLS回调函数,同WriterToPEFileAndDisk
解决方案:
删除TLS回调功能
TLS表中的 RVA处存放的是TLS结构体信息,Size字段记录的是TLS结构体的大小,把这两个字段的值设成0,就能删除TLS回调函数。实现的代码如下:
[Asm] 纯文本查看 复制代码//修改TLS表中的RVA值*(DPointer + PEOptionalAddress + 0xA8) = 0;//修改TLS表中的Size值*(DPointer + PEOptionalAddress + 0xAC) = 0;再写入磁盘中,就删除了。












来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-11-25 11:27 , Processed in 0.078125 second(s), 32 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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