系统 : Windows xp

程序 : 某游戏客户端

程序下载地址 :不提供

要求 : 远程注入 & 获取MD5值

使用工具 : vc++6.0 & OD

案例说明:

该游戏客户端对自身进行散列计算,并将md5值打包加密发给服务端。由于客户端本体带有病毒和压缩壳,索性采用硬件断点,和Debug API获取该MD5的内存地址。

逆向该客户端:

客户端启动时,先初始化md5内存:

00419DE4    B9      mov     ecx,
00419DE9 33C0 xor eax, eax
00419DEB 8DBD B8610200 lea edi, dword ptr [ebp+261B8]
00419DF1 F3:AB rep stos dword ptr es:[edi] ; (initial cpu selection)

然后开始计算散列值:

004EA3E2    BE B8610200     mov     esi, 261B8
004EA3E7 33D2 xor edx, edx
004EA3E9 8D45 EE lea eax, dword ptr [ebp-]
004EA3EC 8A543D B4 mov dl, byte ptr [ebp+edi-4C]
004EA3F0 push edx
004EA3F1 E06D5300 push 00536DE0 ; %02x
004EA3F6 push eax
004EA3F7 E8 ABEE0100 call 005092A7
004EA3FC 8B15 943C5400 mov edx, dword ptr [543C94]
004EA402 :8B4D EE mov cx, word ptr [ebp-]
004EA406 83C4 0C add esp, 0C
004EA409 inc edi
004EA40A :890C16 mov word ptr [esi+edx], cx
004EA40E 83C6 add esi,
004EA411 81FE D8610200 cmp esi, 261D8
004EA417 ^ 7C CE jl short 004EA3E7

跳出循环后,md5值就计算完毕了。我们利用DebugAPI模拟以上操作就可以。

但是要注意一点,传参 DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS调用CreateProcess函数会将exe占用。这时,程序打开自身的CreateFile函数将失败:

0012FC98   004EA381  /CALL to CreateFileA from xxx.004EA37F
0012FC9C 0012FCC4 |FileName = "xxx.exe"
0012FCA0 80000000 |Access = GENERIC_READ
0012FCA4 00000000 |ShareMode = 0
0012FCA8 00000000 |pSecurity = NULL
0012FCAC 00000003 |Mode = OPEN_EXISTING
0012FCB0 00000000 |Attributes = 0
0012FCB4 00000000 \hTemplateFile = NULL

解决办法很简单,将ShareMode改成FILE_SHARE_READ即可。

最后整理一下我们分析的结果:

1.对程序下硬件断点,保存md5的内存地址。

2.patch掉ShareMode,改为0x01(FILE_SHARE_READ)。

3.对计算完md5之后的指令下断,并读取md5.

部分实现代码:

//用于createprocess的两个参数
STARTUPINFO si;
PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO); char ReadBuffer[] = {};
bool WhileDoFlag = true; //创建进程
if ( !CreateProcess( FileName,NULL,NULL,NULL,FALSE,
DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS,NULL,NULL,&si,&pi ) ){
MessageBox( "打开程序失败!" ); DWORD dwRet = GetLastError();
CString strText(_T(""));
strText.Format(_T("%d"), dwRet);
AfxMessageBox("错误代码:"+strText); return ;
}
m_Pi = pi; DEBUG_EVENT DBEvent;
CONTEXT Regs;
DWORD dwSSCnt = ;
//存放md5地址
DWORD READ_ADDRESS; Regs.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS ; //设置程序在Single Step模式下执行
GetThreadContext( pi.hThread,&Regs );
Regs.EFlags |= 0x100;
SetThreadContext( pi.hThread,&Regs ); ResumeThread( pi.hThread ); while (WhileDoFlag) {
WaitForDebugEvent (&DBEvent, INFINITE);
switch (DBEvent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT: switch (DBEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_SINGLE_STEP :
{
++dwSSCnt ;
if (dwSSCnt == )
{
//当收到第一个EXCEPTION_SINGLE_STEP异常信号,表示中断在程序的第一条指令,即入口点
//把Dr0设置成程序的入口地址 GetThreadContext(pi.hThread,&Regs); Regs.Dr0=Regs.Eax;
Regs.Dr7=0x101; SetThreadContext(pi.hThread,&Regs); }
else if (dwSSCnt == )
{
//第二次中断在起先设置的入口点,在BP_MOLLC处设置硬件断点 GetThreadContext(pi.hThread, &Regs) ; Regs.Dr0 = BP_MOLLC;
Regs.Dr7 = 0x101 ; SetThreadContext(pi.hThread, &Regs) ;
}
else if (dwSSCnt == )
{
//第三次中断,己到指定的地址,读取EDI寄存器的数据
GetThreadContext(pi.hThread, &Regs) ; Regs.Dr0 = BP_INITMD5;
Regs.Dr7 = 0x101 ; READ_ADDRESS = Regs.Edi; BYTE NewMode = 0x01;
int a = WriteProcessMemory( pi.hProcess,(LPVOID)SET_SHAREMODE,&NewMode,, ); SetThreadContext(pi.hThread, &Regs) ; /*
//挂起进程
SuspendThread( pi.hThread );
//通知进程异常已处理
ContinueDebugEvent(DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE) ;
//卸载调试器
int a = _DebugSetProcessKillOnExit( FALSE );
int b = _DebugActiveProcessStop(DBEvent.dwProcessId);
//最后运行线程
ResumeThread( pi.hThread ); //int b = GetLastError();
WhileDoFlag=FALSE;
*/
}
else if (dwSSCnt == )
{
//第四次中断,MD5算出,读取数据.
GetThreadContext(pi.hThread, &Regs) ; Regs.Dr0 = Regs.Dr7 = ; ReadProcessMemory( pi.hProcess,(LPVOID)READ_ADDRESS,ReadBuffer,,NULL );
SetDlgItemText( IDC_EDITMD5,ReadBuffer ); SetThreadContext(pi.hThread, &Regs) ;
}
break;
}
}
break ; case EXIT_PROCESS_DEBUG_EVENT :
WhileDoFlag=FALSE;
break ;
}
//pi.dwProcessId和pi.dwThreadId 要改成如下的代码
ContinueDebugEvent(DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE) ;
} //.end while

劳动节脑洞大开!利用Debug API 获取 加壳客户端的MD5值的更多相关文章

  1. 我的Java开发学习之旅------>工具类:Java获取字符串和文件进行MD5值

    ps:这几天本人用百度云盘秒传了几部大片到云盘上,几个G的文件瞬秒竟然显示"上传成功"!这真让我目瞪口呆,要是这样的话,那得多快的网速,这绝对是不可能的,也许这仅是个假象.百度了一 ...

  2. 如何获取Azure Storage Blob的MD5值

    问题表述 直接使用CloudBlockBlob对象获取的Properties是空的,无法获取到对象的MD5值,后台并未进行属性值的填充 前提:blob属性本省包含md5值,某些方式上传的blob默认并 ...

  3. VS2008 C++ 利用WinHttp API获取Http请求/响应头部Header

    http://www.cnblogs.com/LCCRNblog/p/3833472.html 这一篇博客中,实现了获取http请求/响应后的html源码,现在需要获取http请求/响应的头部Head ...

  4. VS2008 C++ 利用WinHttp API获取任意Http网址的源码

    最近一直在看有关Http的知识,对其基本的理论知识已经有所掌握,想通过一个C++具体的例子进行实际操作..于是上网查找了很多资料,发现在Windows系统上,可以通过WinHttp API接口开啊Ht ...

  5. 爬虫——python——百度地图经纬度查询——经纬度查看地点地名——利用百度API获取地名经纬度——爬取所有的中国地址

    import requests address = '40.8587960,86.866991' url = 'http://api.map.baidu.com/geocoder?output=jso ...

  6. 利用iOS API编写简单微博客户端全过程

    要编写社交网络客户端程序,可以大体上分为4个主要的步骤 下面我们按照这个流程,介绍一下: 1.引入Accounts和Social框架 工 程中需要引入Accounts和Social框架,Account ...

  7. iOS开发,利用文件流,算大文件的MD5值(程序不会导致内存崩溃)

    CFStringRef FileMD5HashCreateWithPath(CFStringRef filePath, size_t chunkSizeForReadingData) { // Dec ...

  8. jni中调用java方法获取当前apk的签名文件md5值

    相应的java方法: void getsign(Context context) throws Exception { PackageInfo localPackageInfo = context.g ...

  9. PHP获取远程http或ftp文件的md5值

    PHP获取本地文件的md5值: md5_file("/path/to/file.png"); PHP获取远程http文件的md5值: md5_file("https:// ...

随机推荐

  1. 15 Best Responsive HTML5 Frameworks 2014

    Best HTML5 frameworks are most popular because with the use of these frameworks you can create websi ...

  2. JAVA 设计模式 享元模式

    用途 享元模式 (Flyweight) 运用共享技术有效地支持大量细粒度的对象. 享元模式是一种结构型模式. 结构

  3. Android布局尺寸思考

    一.初步思考 虽然安卓的这个显示适配的方案有点怪,最初也不容易马上理解,不过这个方案确实有其自己的道理,整个思路是清晰的,方案的也是完整的,没有硬伤 安卓采用的[屏幕密度放缩机制].与web前端对应的 ...

  4. 【转载】jquery validate验证插件,在ajax提交方式下的验证

    正常的表单都是使用submit按钮来提交,jquery  validate插件可以方便的做表单验证. 做一个发送短信的功能,向目标表插入多条记录,界面采用ajax来提交表单,等待效果直接用ext的遮罩 ...

  5. 百度地图API实现地图定位

    1.引用JS: <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0& ...

  6. C#编程总结(十二)断点续传

    C#编程总结(十二)断点续传 我们经常使用下载工具,如bit精灵.迅雷.FlashGet,这些软件都支持断点续传. 断点续传即下载任务暂停后可以继续,而无需重新下载,即下载时需要通知服务器的起始位置. ...

  7. Monotype推出基于HTML5的Web字体平台

    著名字体公司Monotype近日宣布推出基于HTML5的Web字体平台,设计者可以访问近10万字体的目录. Monotype推出基于HTML5的Web字体平台 Monotype推出基于HTML5的We ...

  8. EF6 中tracking log使用方法总结

    先上一段最近项目中的代码,此代码可以放到自己项目中的dbContext中 public override Task<int> SaveChangesAsync() { List<Au ...

  9. 【Java每日一题】20161130

    20161129问题解析请点击今日问题下方的"[Java每日一题]20161130"查看 package Nov2016; public class Ques1130 { publ ...

  10. vim退出后终端保留 退出前的内容

    export TERM=linux 或者 具体选项 可以看看secrecrt的选项