一种躲避运行时代码校验的方法

文件上传校验绕过总结 文件上传校验 前端javascript校验(一般只校验后缀名) 服务端校验 文件头content-type字段校验(image/gif) 文件内容头校验(GIF89a) 后缀名黑名单校验 后缀名白名单校验 WAF设备校验(根据不同的WAF产品而定) 其他绕过方式 1.客户端校验         ... 阅读详情
 

关键字:代码校验,内存补丁,hook

我们有时候需要对运行中的程序打内存补丁,或者对它的代码挂一些钩子之类的工作。但是现在相当多软件进行了运行时的代码检测。一旦发现内存中的代码被修改掉,就会进行处理。本文介绍了一种比较特别的办法,用于通过这些检测。

首先需要说一下做运行时代码校验的方法。一般来说,校验者需要取得当前模块的基地址,通过分析PE结构,获得代码节的偏移和大小,然后对内存中的代码进行CRC或者其他的一些校验。

这其中有个很大的问题,校验者默认了通过这种方式取得的代码节就是当前被使用到的代码,但是事实却不一定如此。一般编译器正常生成的代码,绝大部分跳转和call语句都使用相对地址,因此,我们完全可以把代码节或者整个exe文件映像复制到内存其他地方,并操作进程内的所有线程,使得它执行在新复制的那份代码中。这样,校验者仍然在扫描旧的地址,新的那份我们就可以随意修改了。

由于一旦进程开始执行,并且创建其他线程之后,我们通过取得线程Context获得的EIP,多半在系统代码中间,所以难以改变。唯一的方法就是,在exe的EntryPoint被执行前,将EntryPoint重定向到新的代码,并Hook CreateThread,将新线程也重新定位。可以通过下面几个步骤来实现:

1、 如果想处理的进程为a.exe,并且a.exe是由b.exe创建的,那么我们需要hook掉b.exe的进程创建函数,一般是CreateProcess。

2、 在Hook的CreateProcess中,以CREATE_SUSPENDED标志创建a.exe。并向a.exe中注入我们的dll,等待这个dll完成处理之后才ResumeThread a.exe的主线程。

3、 注入的dll需要完成几件事。首先要获得主模块的基地址和大小,并分配足够的空间,将原始映像复制过去。然后Hook掉EntryPoint,并Hook CreateThread,最后恢复a.exe主线程。

4、 Hook掉的EntryPoint中,恢复被Hook的EntryPoint代码,防止在后面被检查出来,然后jmp到新分配的代码区域即可。

5、 Hook的CreateThread中,重新计算代码线程函数地址,并修改后创建。这样,所有线程就都在新分配的代码中执行了。

下面是注入的dll的实现代码:

 

pfnCreateThread g_pCreateThread = ::CreateThread;

PBYTE    g_pbyNewImage = NULL;

 

#pragma pack(push,1)

typedef struct _PUSH_RETN

{

     BYTE byOpcodePush;//0x68

     DWORD dwRetnAddr;

     BYTE byOpcodeRetn;//0xC3

}PUSH_RETN, *PPUSH_RETN;

#pragma pack(pop)

 

BYTE g_abyOldEntry[6] = {0};

PBYTE g_pbyOldEntry = 0;

PBYTE g_pbyNewEntry = 0;

 

//这里使用Detours库Hook掉CreateThread。

BOOL HookThreadCreate()

{

     DetourTransactionBegin();

     DetourUpdateThread( GetCurrentThread());

 

 

     if( DetourAttach( &(PVOID&)g_pCreateThread, Hook_CreateThread) != NO_ERROR)

     {

         DebugOut( TEXT( "Hook CreateThread fail/r/n"));

     }

 

     if( DetourTransactionCommit() != NO_ERROR)

     {

         DebugOut( TEXT( "Hook fail/r/n"));

         return FALSE;

     }

     else

     {

         DebugOut( TEXT( "Hook ok/r/n"));

         return TRUE;

     }

}

 

//Hook的CreateThread里面,重新计算lpStartAddress地址,并按这个地址来创建

HANDLE WINAPI Hook_CreateThread(

                                     LPSECURITY_ATTRIBUTES lpThreadAttributes,

                                      SIZE_T dwStackSize,

                                     LPTHREAD_START_ROUTINE lpStartAddress,

                                     LPVOID lpParameter,

                                     DWORD dwCreationFlags,

                                     LPDWORD lpThreadId

                                     )

{

     PBYTE pfn = (PBYTE)lpStartAddress;

     HMODULE hMod = ::GetModuleHandle( NULL);

     pfn = g_pbyNewImage + (pfn - (PBYTE)hMod);

    HANDLE hThread = g_pCreateThread( lpThreadAttributes, dwStackSize, (LPTHREAD_START_ROUTINE)pfn, lpParameter, dwCreationFlags, lpThreadId);

     return hThread;

}

 

//Hook掉的入口点,恢复旧代码并跳转到新分配的代码空间

__declspec( naked ) VOID Hook_EntryPoint()

{

     //_asm int 3

     for ( DWORD i = 0; i < sizeof(g_abyOldEntry); i++)

     {//恢复旧的代码

         g_pbyOldEntry[i] = g_abyOldEntry[i];

     }

     _asm jmp g_pbyNewEntry;

}

 

//Hook掉入口点

VOID HookEntryPoint()

{

     DebugOut( _T( "In HookEntryPoint/r/n"));

 

     HMODULE hMod = ::GetModuleHandle( NULL);

     PIMAGE_DOS_HEADER pstDosHeader = (PIMAGE_DOS_HEADER)hMod;

     PIMAGE_NT_HEADERS pstHeader = (PIMAGE_NT_HEADERS)((PBYTE)hMod + pstDosHeader->e_lfanew);

     DWORD dwEntryRVA = pstHeader->OptionalHeader.AddressOfEntryPoint;

     PBYTE pbyRVA = (PBYTE)(hMod) + dwEntryRVA;

     PPUSH_RETN pstHook = (PPUSH_RETN)pbyRVA;

     memcpy( g_abyOldEntry, pbyRVA, sizeof(PUSH_RETN));

     pstHook->byOpcodePush = 0x68;

     pstHook->dwRetnAddr = (DWORD)Hook_EntryPoint;

     pstHook->byOpcodeRetn = 0xC3;

 

     g_pbyOldEntry = pbyRVA;

     g_pbyNewEntry = g_pbyNewImage + dwEntryRVA;

     DebugOut( _T("New image base = 0x%X, New EntryPoint = 0x%X/r/n /

                   Old image base = 0x%X, Old EntryPoint = 0x%X/r/n"), g_pbyNewImage, g_pbyNewEntry, hMod, g_pbyOldEntry);

     DebugOut( _T( "HookEntryPoint OK/r/n"));

}

 

//在DllMain里面Process Attach的时候调用

VOID OnAttachProcess()

{

     HMODULE hMod = ::GetModuleHandle( NULL);

     DWORD dwSize = GetImageSize();

     g_pbyNewImage = new BYTE[dwSize];

 

     DWORD dwOldProtect = 0;

     VirtualProtect( g_pbyNewImage, dwSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);

     VirtualProtect( (LPVOID)hMod, dwSize, PAGE_READWRITE, &dwOldProtect);

     memcpy( g_pbyNewImage, (LPVOID)hMod, dwSize);

 

     HookEntryPoint();

     HookThreadCreate();

}

 

//获得主模块映像大小

DWORD GetImageSize()

{

     HANDLE hShot = NULL;

     BOOL blResult = FALSE;

     MODULEENTRY32 stInfo = {0};

     stInfo.dwSize = sizeof( MODULEENTRY32);

     TCHAR tszTmp[MAX_PATH] = {0};

 

     ::GetModuleFileName( GetModuleHandle(NULL), tszTmp, MAX_PATH);

     _tcslwr( tszTmp);

     size_t s = _tcslen(tszTmp);

     for ( DWORD i = 0; i < s; i++)

     {

         if ( tszTmp[s - i] == '//')

         {

              s = s - i + 1;

              break;

         }

     }

     hShot = ::CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, ::GetCurrentProcessId());

     if ( INVALID_HANDLE_VALUE == hShot)

     {

         DebugOut( _T( "CreateToolhelp32Snapshot fail.Err=%d/r/n"), GetLastError());

         return 0;

     }

 

     blResult = ::Module32First( hShot, &stInfo);

     while ( blResult)

     {

         _tcslwr( stInfo.szModule);

         if ( _tcscmp( stInfo.szModule, tszTmp + s) == 0)

         {

              CloseHandle( hShot);

              return stInfo.modBaseSize;

         }

         blResult = ::Module32Next( hShot, &stInfo);

     }

     CloseHandle( hShot);

     return 0;

}

这种方法对加壳之后的exe作用有限,因为Hook的并不是真实的OEP。这样做常常会造成壳执行过程中,或者跳转到OEP之后迅速崩溃。本文仅仅是介绍一种思想,有时候巧妙的构思可以使得复杂问题很快得到解决。

web渗透—xss攻击防御 1、基于特征的防御 XSS漏洞和著名的SQL注入漏洞一样,都是利用了Web页面的编写不完善,所以每一个漏洞所利用和针对的弱点都不尽相同。这就给XSS漏洞防御带来了困难:不可能以单一特征来概括所有XSS攻击。 传统XSS防御多采用特征匹配方式,在所有提交的信息中都进行匹配检查。对于这种类型的XSS攻击,采用的模式匹配方法一般会需要对“javascript”这个关键字进行检索,一旦发现提交信息中包 阅读详情

相关推荐

安卓逆向实战:LSPatch如何绕过签名校验与内存检测(附检测方法)

本文深入剖析了安卓热修复工具LSPatch的核心隐匿机制,重点解析其如何通过劫持AppComponentFactory、匿名内存加载和伪造LoadedApk等技术,绕过签名校验与内存检测。同时,文章提供了从Java层到Native层的多层次、可操作的检测方法论,包括检查类加载器、扫描匿名内存区域以及监控关键系统调用,为安卓应用安全加固与逆向分析提供了实战指南。

weixin_29327525的博客 378

2010年上半年5月份信息系统项目管理师上午试题答案(分析与解答)之八

2010年上半年5月份信息系统项目管理师上午试题答案(分析与解答)之八(43)参考答案:C(44)参考答案:A(45)参考答案:D(46)参考答案:A(47)参考答案:D

2023跟着小虎玩着去软考 1738

CESM2 实验笔记

文章目录1. 重新启动1.1 关于重启文件2. RUN_TYPE 初始化运行方式startupbranchhybrid3. branch 或者 hybrid运行的示例4. 其他声明5. 关于RESUBMIT 1. 重新启动 参考: https://bb.cgd.ucar.edu/cesm/threads/how-to-restart-cesm2-1-3-fhist-from-a-backup.5245/#post-36275 适用情况:模型运行因时间不足或其它原因中断,需要继续运行 方法1:将CONTIN

qq_38607066的博客 1万+

易语言API HooK CreateThread创建线程

本课对API(Createthread)进行了Hook,首先我们在测试程序里启动一个线程,可以使用易语言的启动线程 (&工作, , 线程句柄)也可以直接调用API(Createthread)我们这里分了两种情况测试,第一,钩子写到测试文件里,第二,单独写一个钩子DLL,通过注入现行hook。我们hook的动作是调用系统的calc,你的系统如果是WIN10要确定是否安装了计算器。当然我们可以下任何钩子。实际应用是这样的,我们首先确定所注入进程是否调用了CreateThread这个API,其次我们应当写

511遇见 6296

基于FPGA的cy7c68013a双向通信实验

基于FPGA的cy7c68013a双向通信实验     本实验是基于FPGA的cy7c68013a的USB双向通信实验,以前折腾过一段时间cy7c68013a,没有入门时感觉好难,入门了就会感觉很简单。本教程主要内容:     1.cy7c68013a的固件编写,以及生成iic固件和下载固件。     2.cy7c68013a的slave模式,以及他的读写时序     3.cy7c6801...

乘风的博客 3万+

团结引擎+OpenHarmony 2实战篇:从零构建鸿蒙应用开发环境

本文详细介绍了如何从零开始构建鸿蒙应用开发环境,重点讲解了团结引擎与OpenHarmony 2的实战配置步骤。内容包括DevEco Studio安装、OpenHarmony SDK配置、团结引擎集成及项目创建等关键环节,帮助开发者快速搭建高效的开发环境,提升鸿蒙应用开发效率。

weixin_29294395的博客 265

CreateThread成功后,紧接CloseHandle,

SDK的文档中,     Multithreaded   Pipe   Server那节有个例子.         fConnected   =   ConnectNamedPipe(hPipe,   NULL)   ?                         TRUE   :   (GetLastError()   ==   ERROR_PIPE_CONNECTED);        

jiangxinyu的专栏 1981

DANN实战:用Python手把手教你实现对抗迁移学习(附完整代码)

本文通过Python实战教程,手把手教你实现DANN对抗迁移学习模型,以解决领域偏移问题。文章详细解析了领域对抗神经网络的核心机制,包括梯度反转层和领域判别器的构建,并提供了从数据准备、模型搭建到训练评估的完整代码,帮助开发者快速掌握这一强大的无监督领域自适应技术。

net55的博客 318

如何忽略eslint的语法检查

忽略ESlint语法检查

qq_44482048的博客 2068

基于FPGA的函数信号发生器设计

设计采用波形查找表和相位累加器的方法实现DDS,查找表的数据位宽为8位,采样点数为4096。波形产生范围是100Hz-20MHz,最小频率间隔为1Hz,用8个数码管显示频率,可产生正弦波、方波、三角波,波形用两个led显示,select信号控制,全灭为正弦波,一亮一灭为方波,全亮为锯齿波。为了使频率和相位便于调节,用3个拨码开关控制步进,用8个led显示状态。

FPGA入门到跑路 5636

FPGA实战:从零构建eMMC控制器(Verilog篇)

本文详细介绍了如何使用Verilog从零构建FPGA上的eMMC控制器,涵盖eMMC接口基础、命令系统解析、关键模块设计及性能优化技巧。通过实战案例,帮助开发者掌握高速数据存储解决方案,提升嵌入式系统开发能力。

weixin_26802933的博客 298

多线程-Hook线程及捕获线程异常

在Thread类中,关于处理运行时运行异常的API总共有四个, 如下所示: public void setUncaughtExcetionHandler(UncaughtExceptionHandler eh) 为某个特定线程指定UnCaughtExceptionHandler public static void setDefaultUncaughtExceptionHandler(Unca...

u010277958的博客 856

AT32F403A ADC采集实战:如何用V2库精准读取可变电阻电压(附完整代码)

本文详细介绍了基于AT32F403A微控制器和V2库实现高精度ADC采集的工程化方法。内容涵盖从基础的单通道轮询配置到多通道扫描与DMA传输的进阶应用,并重点分享了提升ADC采集精度的关键技巧,包括采样时间优化、软件滤波算法以及硬件布局考量,提供了完整的实战代码,帮助开发者解决数据跳动、稳定性等常见问题。

weixin_29189003的博客 93

一种躲避运行时代码校验的方法(Reload And Run)

转自看雪。    我们有时候需要对运行中的程序打内存补丁,或者对它的代码挂一些钩子之类的工作。但是现在相当多软件进行了运行时的代码检测。一旦发现内存中的代码被修改掉,就会进行处理。本文介绍了一种比较特别的办法,用于通过这些检测。     首先需要说一下做运行时代码校验的方法。一般来说,校验者需要取得当前模块的基地址,通过分析PE结构,获得代码节的偏移和大小,然后对内存中的代码进行CRC

zfdyq 2708

语音识别:PyAudio、SoundDevice、Vosk、openai-whisper、Argos-Translate、FunASR(Python)

本文介绍了Python中常用的音频处理库PyAudio,详细解析了其核心功能、核心概念和典型工作流程。PyAudio是一个跨平台的音频I/O库,支持音频录制、播放、实时流处理和低延迟操作。核心概念包括PyAudio类(管理音频设备和流)和Stream类(代表音频流)。文章重点讲解了open()方法的关键参数、回调函数的使用方式以及典型的工作流程,包括设备查询、流配置和资源释放。PyAudio适用于需要实时音频处理的场景,如语音识别和音频效果处理。

算法工程师 706

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Linux Rootkit躲避内核检测

Rootkit在登堂入室并得手后,还要记得把门锁上。 如果我们想注入一个Rootkit到内核,同时不想被侦测到,那么我们需要做的是精妙的隐藏,并保持低调静悄悄,这个话题我已经谈过了,诸如进程摘链,TCP链接摘链潜伏等等,详情参见: https://blog.youkuaiyun.com/dog250/article/details/105371830 https://blog.youkuaiyun.com/dog250/...

TCP/IP 5357

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

十六、代码校验(6)

● 剖析和优化 ○ 优化准则 ● 风格检测 ● 静态错误分析 ● 代码重审 ● 结对编程 ● 重构 ○ 重构基石 ● 持续集成 ● 本章小结

走在bug的路上 6793

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

小游戏制作QQ宠物系列 ----躲避老鼠

点击鼠标左键,控制左侧人物跳跃躲避右侧老鼠的撞击,成功躲避老鼠的撞击则积分+1;老鼠的速度是随机的。本文章是小游戏制作系列,小游戏制作QQ宠物系列 ----躲避老鼠。js代码重点方法(未优化版)

weixin_45101949的博客 600
上一篇: Own Crash Minidump with Call Stack
下一篇: Get File Version in your code
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值