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

文件上传校验绕过总结 文件上传校验 前端javascript校验(一般只校验后缀名) 服务端校验 文件头content-type字段校验(image/gif) 文件内容头校验(GIF89a) 后缀名黑名单校验 后缀名白名单校验 WAF设备校验(根据不同的WAF产品而定) 其他绕过方式 1.客户端校验         ... 阅读详情
 我们有时候需要对运行中的程序打内存补丁,或者对它的代码挂一些钩子之类的工作。但是现在相当多软件进行了运行时的代码检测。一旦发现内存中的代码被修改掉,就会进行处理。本文介绍了一种比较特别的办法,用于通过这些检测。
     首先需要说一下做运行时代码校验的方法。一般来说,校验者需要取得当前模块的基地址,通过分析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之后迅速崩溃。本文仅仅是介绍一种思想,有时候巧妙的构思可以使得复杂问题很快得到解决。
     改良之后,这个技巧可以用到不少地方,呵呵
绕过HS保护的CRC校验 之前写一款游戏辅助研究了下原理 不同版本的HS原理大致相同 编译的时候可能需要更新一下基址 立即下载

相关推荐

LOL走砍躲避连招源码 密码tre.e

LOL走砍躲避连招源码

c++ 在内存中加载 exe/dll (不使用CreateProcess、LoadLibrary 等 API)

背景 在网上搜索了很多病毒木马的分析报告,看了一段时间后,发现还是有很多病毒木马都能够模拟PE加载器,把DLL或者是EXE等PE文件,直接从内存中直接加载到自己的内存中执行,不需要通过API函数去操作,以此躲过一些杀软的...

墨鱼菜鸡 1201

D3D8劫持,跟下硬件断点调试异常可以过CRC校验哦..

D3D8通用游戏劫持,之前在做DNF的时候需要调试一些地址异常,就弄了一个劫持去调试,现在没用了,具体有需要的自己去改,硬件断点调试异常可以过CRC校验哦..,有时间整理一个易语言的版本..

windows API 第九篇 _tcslwr _strlwr _wcslwr _mbslwr

将字符串转化为小写Convert a string to lowercase.函数原型: char *_strlwr( char *string ); //#include <string.h> wchar_t *_wcslwr( wchar_t *string ); //#include <strin...

440

几种常用的单片机系统RAM测试方法

在各种单片机应用系统中,存储器的正常与否直接关系到该系统的正常工作。为了提高系统的可靠性,对系统的可靠性进行测试是十分必要的。通过测试可以有效地发现并解决因存储器发生故障对系统带来的破坏问题。本文针对性地介绍了几种常用的单片机系统RAM测试方法,并在其基础上提出了一种基于种子和逐位倒转的RAM故障测试方法。

别再为SCI论文配图发愁了!手把手教你用PS+AI搞定从数据图到模式图的全流程

本文详细解析了如何利用Photoshop(PS)和Illustrator(AI)高效完成SCI论文配图的全流程,涵盖数据可视化、模式图设计及期刊适配性输出。通过实战案例,帮助科研人员掌握位图与矢量图的处理技巧,提升论文配图质量,满足不同期刊的出版要求。

weixin_28630185的博客 384

C++关键字

static: C语言中的static: (1)生命周期:static修饰的变量,存储在内存的静态存储区,无论是在函数内还是函数外,生命周期都是整个程序运行期间,static修饰的函数其生命周期也是整个程序的运行期间 (2)作用域:static修饰的局部变量的作用域就是定义该变量的那个作用域内,static修饰的全局变量的作用域是从这个变量定义开始到整个程序结束 (3)static修饰的变量都存储在静态区 (4)static修饰的变量只能作用于本文件内,即使被extern修饰也不行 (5)static修饰的

KAIHINGWON的博客 281

汇川EASY系列之以太网通讯(套接字socket做从站)

汇川EASY系列的以太网通讯中的Socket字通讯,不能使用配置的方式实现,只能通过指令完成,本文将详细说明

这是一个长期关注工控行业技术的博客,实现0-1的突破,期待您的关注和留言 3004

Quartus中常见错误·

1.关于“Error: Net “gdfx_temp0”, which fans out to “***:inst4|BIN”, cannot be assigned more than”错误 有些时候,在FPGA的编程时,用原理图输入,运行“complication”后,会出现这个错误:Error: Net “gdfx_temp0”, which fans out to “***:inst4|&...

deniece1的博客 1万+

用angr找到strcpy的栈溢出漏洞

这篇文章其实是分析angr文档里给出的一个挖漏洞的小例子。 原文链接在此:https://docs.angr.io/examples#beginner-vulnerability-discovery-example-strcpy_find 这是第一个用angr在二进制里找可利用条件的教程。第一个例子是一个非常简单的程序。这个angr脚本会从程序的entry到strcpy找到一条路径。(只有我们能够控制strcpy的参数的时候) 为了找到正确的路径,angr需要去算一个密码参数,算这个密码,angr只要2s

^_^ 1220

8、干式变压器

干式变压器的发展,是人类不断挑战材料科学和热物理极限的过程,每一次技术突破,都是在。温度升高,ε_r反而下降(因为分子活动性增强,极化响应变慢)。:固体导热的热阻比液体对流大一个数量级,这是无法逾越的物理规律。Nomex在高温下不是逐渐分解,而是保持性能直到一个临界点。如果 T_a = 40°C,则 T_c = 146.7°C。干式变压器(固体介质分隔):热场、电场、流场(空气)形成三维氢键网络,即使在高温下也能保持机械强度。:不是在现有技术上修修补补,而是寻找新的。仍在H级绝缘允许范围内(≤180°C)

renpeng2692873032的博客 230

13.使用更安全CRT函数(C语言)

CRT函数

wangqifeng10_16的专栏 3675

【零基础入门unity游戏开发——unity3D篇】unity CharacterController 3D角色控制器最详细的使用介绍,并实现俯视角、第三人称角色控制(附项目源码)

【unity小技巧】unity最完美的CharacterController 3d角色控制器,实现移动、跳跃、下蹲、奔跑、上下坡、物理碰撞效果,复制粘贴即用但是我发现很多人还是不理解,都跑来私信问我,所以决定重新做一个更加详细且简单控制器,主要是实现俯视角和第三人称角色控制。添加一个胶囊体,添加Character Controller组件,记得删除Capsule Collider组件,因为Character Controller自带了碰撞,所以不需要Character Controller参数介绍。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 5023

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

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

zfdyq 2708

前端使用二开Thingsboard一、二、三事(四)-部件库

以项目实战为基础,逐步介绍前端在thingsboard系统二次开发中的一些注意事项以及一些thingsboard一些页面功能讲解,为前端人员开发使用thingsboard提供一种可靠思路,打造一个完美的物联网系统。

weixin_43163457的博客 743

Zemax与Matlab交互:双胶合优化详细流程

Zemax与Matlab交互:双胶合优化详细流程

weixin_72050316的博客 630

Linux Rootkit躲避内核检测

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

TCP/IP 5357

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

上一篇: SQLExec.c
下一篇: xp_cmdshell新的恢复办法
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值