2010-08-22_ximo_也来谈谈VMP2.05的脱壳

2023-10-14 05:30
文章标签 22 08 谈谈 2010 ximo 脱壳 vmp2.05

本文主要是介绍2010-08-22_ximo_也来谈谈VMP2.05的脱壳,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://hi.baidu.com/ximo2006/blog/item/dc630103b080f00d728da567.html

VMP的外壳部分不能说难,只能说烦。特别是IAT的修复,由于函数调用的错位(并非是规则的call xxxx nop或者nop call xxxx系列)、寄存器使用的随机性、大量的乱序等,使得写脚本修复是个非常蛋疼的事情,而且往往会修复错,修复漏,而VM代码里的IAT更是无法得到修复。于是,目前公开的方法中,最简单的也是最治本的修复方式,就是先生成张调用关系的表,然后写个DLL去读,在程序运行前,修正一些值,来达到跨平台。其他的,还真想不到有更完美的方法。或许牛人间有更好的处理方法,我这种菜鸟实在想不到了。。

至于修复IAT,牛人的文章不少了,比如kissy牛的2个视频,以及aa1ss2牛的学习笔记,这里就不再多说了。

下面写下个人脱壳的记录,当算是个简单的笔记,跟步骤的总结,没什么技术含量,一切都是按牛人的脚步学习的。

试练品是个XP记事本,加上VMP外壳的全选项,顺便把OEP处的代码也给和谐掉。下面开始脱壳:

1.CTRL+G,VirtualProtect,在VirtualProtectEx的调用处下好断点:

7C801AE3    E8 75FFFFFF          call kernel32.VirtualProtectEx

接着,在数据窗口定位到代码段,比如,这个样本的为01001000.主要是为了观察是否已经解码,找返回的时机。

2.一直F9,一直到代码段解码,取消断点。ALT+F9,返回到程序代码区。

3.HOOK VM_RETN,找程序的入口。

先来看下VM_RETN这条handler长成啥样吧:

01071753 Main     pushad                                  //VM_Retn
01071754 Main     xchg ax,di                                ; EAX=0000F694, EDI=0006000E
01071756 Main     jmp NOTEPAD_.0106FB88
0106FB88 Main     sub ch,bl                                 ; ECX=01072F53
0106FB8A Main     mov esp,ebp
0106FB8C Main     movzx cx,al                               ; ECX=01070094
0106FB90 Main     xadd cl,ah                                ; EAX=00009494, ECX=0107008A
0106FB93 Main     call NOTEPAD_.0107152C
0107152C Main     mov ecx,dword ptr ss:[esp+4]              ; ECX=00000246
01071530 Main     xchg eax,esi                              ; EAX=01018E26, ESI=00009494
01071531 Main     mov eax,dword ptr ss:[esp+8]              ; EAX=0006FFB0
01071535 Main     jmp NOTEPAD_.0107147E
0107147E Main     bswap cx                                  ; ECX=00000000
01071481 Main     aaa                                       ; EAX=0006FF00
01071482 Main     mov eax,dword ptr ss:[esp+C]              ; EAX=F035F4BE
01071486 Main     pushfd
01071487 Main     adc esi,A8EF9681                          ; ESI=A8F02B15
0107148D Main     jmp NOTEPAD_.0107163C
0107163C Main     std
0107163D Main     mov esi,dword ptr ss:[esp+14]             ; ESI=0100CB51
01071641 Main     xor di,dx                                 ; EDI=00060248
01071644 Main     neg di                                    ; EDI=0006FDB8
01071647 Main     shld si,sp,cl
0107164B Main     btr bp,0E                                 ; EBP=0006BF84
01071650 Main     mov edi,dword ptr ss:[esp+18]             ; EDI=524DB0B9
01071654 Main     sub esi,734AB4D1                          ; ESI=8DB61680
0107165A Main     lea ebp,dword ptr ds:[edi+DB6A88FF]       ; EBP=2DB839B8
01071660 Main     mov esi,dword ptr ss:[esp+1C]             ; ESI=80A871EF
01071664 Main     inc bp                                    ; EBP=2DB839B9
01071667 Main     rcr bp,cl
0107166A Main     mov ebp,dword ptr ss:[esp+20]             ; EBP=E137F11A
0107166E Main     cmp bl,bh
01071670 Main     movzx bx,dl                               ; EBX=C71A0046
01071674 Main     mov cl,byte ptr ss:[esp+4]                ; ECX=00000098
01071678 Main     bt bx,0F
0107167D Main     mov ebx,dword ptr ss:[esp+24]             ; EBX=05B50161
01071681 Main     rol dh,cl
01071683 Main     mov ecx,dword ptr ss:[esp+28]             ; ECX=213EBC0B
01071687 Main     dec dx                                    ; EDX=00000245
0107168A Main     mov edx,dword ptr ss:[esp+2C]             ; EDX=DA74A7B8
0107168E Main     clc
0107168F Main     add esp,30
01071692 Main     je NOTEPAD_.0106FD6C
01071698 Main     popfd
01071699 Main     pushad
0107169A Main     mov dword ptr ss:[esp],AD22F63E
010716A1 Main     push dword ptr ss:[esp]
010716A4 Main     pushfd
010716A5 Main     push dword ptr ss:[esp+28]
010716A9 Main     retn 2C

直接在010716A9下好断点,F9运行,断下后取消断点,F7,来到下面的地方:

0102A32B    9C                   pushfd
0102A32C    9C                   pushfd
0102A32D    8F0424               pop dword ptr ss:[esp]
0102A330    F5                   cmc
0102A331    81F5 EA0E31E1        xor ebp,E1310EEA
0102A337 ^ E9 29E3FEFF          jmp NOTEPAD_.01018665
0102A33C    AF                   scas dword ptr es:[edi]

4.继续F7几次,就可以来到下面的地方:

01007568    68 BA750001          push NOTEPAD_.010075BA
0100756D    64:A1 00000000       mov eax,dword ptr fs:[0]
01007573    50                   push eax
01007574    8B4424 10            mov eax,dword ptr ss:[esp+10]
01007578    896C24 10            mov dword ptr ss:[esp+10],ebp
0100757C    8D6C24 10            lea ebp,dword ptr ss:[esp+10]
01007580    2BE0                 sub esp,eax
01007582    53                   push ebx
01007583    56                   push esi
01007584    57                   push edi
01007585    8B45 F8              mov eax,dword ptr ss:[ebp-8]
01007588    8965 E8              mov dword ptr ss:[ebp-18],esp
0100758B    50                   push eax
0100758C    8B45 FC              mov eax,dword ptr ss:[ebp-4]
0100758F    C745 FC FFFFFFFF     mov dword ptr ss:[ebp-4],-1
01007596    8945 F8              mov dword ptr ss:[ebp-8],eax
01007599    8D45 F0              lea eax,dword ptr ss:[ebp-10]
0100759C    64:A3 00000000       mov dword ptr fs:[0],eax
010075A2    C3                   retn

这是多么熟悉的代码啊。因为VM并不支持CALL的嵌套,这就给我们可趁之机。先dump一份。

5.下面就来补代码:

此时看堆栈窗口:

0006FFB8   0101654F 返回到 NOTEPAD_.0101654F 来自 NOTEPAD_.0101BFA7 //CALL的出口,注意
0006FFBC   01001898 NOTEPAD_.01001898
0006FFC0   00000070

于是,在代码段,随便找个地址,补入如下代码:

01008890 > 6A 70                push 70
01008892    68 98180001          push dumped1.01001898
01008897    68 4F650101          push dumped1.0101654F
0100889C ^ E9 C7ECFFFF          jmp dumped1.01007568
010088A1    90                   nop

补完后,保存一下,顺便把OEP设置成8890.

OK,程序能够正常。不过此时还不能跨平台。

6.下面开始修复跨平台,这部分我就不说了,自己看牛人的文章跟视频,跑份IAT调用的对应关系表,部分如下:

1013360,DE02099D,comdlg32,PageSetupDlgW
102B3D6,E53997CF,comdlg32,ChooseFontW
1014ABD,4443359,comdlg32,PrintDlgExW
103107A,F8A5F191,comdlg32,ReplaceTextW
1019B4F,8F70D755,comdlg32,GetFileTitleW
101403B,AB122473,comdlg32,FindTextW
101CF16,7495EB47,comdlg32,CommDlgExtendedError
1016371,D8A0FB6B,comdlg32,GetOpenFileNameW
1014D62,BED81FBF,shell32,DragAcceptFiles
10230B9,A0524363,shell32,DragFinish
1022832,F10CB8C9,shell32,DragQueryFileW
101D8F2,4AD7BE0D,comdlg32,GetSaveFileNameW
10314C3,F6D99DC5,shell32,ShellAboutW
102A015,5B0DDC5B,winspool,GetPrinterDriverW
1023366,181A1537,winspool,OpenPrinterW

7.下面就简单的写个DLL,来完成工作,原理很简单,比如某个函数调用中,关键代码如下:

01031019    BA A2390001          mov edx,dump.010039A2
010328AE    8B92 FD430000        mov edx,dword ptr ds:[edx+43FD] //注意这里
010328BE    8D92 DB73ECD6        lea edx,dword ptr ds:[edx+D6EC73DB] //这句出真实的地址

ds:[01007D9F]=A594FBB8
edx=010039A2 (dump.010039A2)

找下对应的关系表:

1007D9F,D6EC73DB,kernel32,GetCommandLineW

可知,在地址01007D9F中存着解密的key,而解密的key为多少,即为真实的API地址-表中对用的key

其实也就是这句的逆过程:lea edx,dword ptr ds:[edx+D6EC73DB]

由于不同的平台,API的地址有差异,所有想要跨平台,就需要修正这个解密的key值,方法是在当前的用户平台上,先获取当前用户平台的API地址,再减去表中对应的那个KEY值即可。

知道了原理,就可以写代码了,代码写的很挫,仅供参考:

#include <windows.h>
#include <stdio.h>

extern "C" BOOL __declspec(dllexport) FkVMPIAT();

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call,LPVOID lpReserved)
{
if (ul_reason_for_call==DLL_PROCESS_ATTACH)
{
   FkVMPIAT();
}
return TRUE;
}

BOOL FkVMPIAT()
{
DWORD dwImageBase=(DWORD)GetModuleHandle(NULL);
PIMAGE_DOS_HEADER pDosHeader=(PIMAGE_DOS_HEADER)dwImageBase;
if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
{
   return FALSE;
}
    PIMAGE_NT_HEADERS pNtHeader=(PIMAGE_NT_HEADERS)(dwImageBase+pDosHeader->e_lfanew);
if (pNtHeader->Signature!=IMAGE_NT_SIGNATURE)
{
   return FALSE;
}
UINT NumOfSection=pNtHeader->FileHeader.NumberOfSections;
    PIMAGE_SECTION_HEADER pSectionHeader=(PIMAGE_SECTION_HEADER)((UINT_PTR)pNtHeader+0x18+
   (UINT_PTR)(pNtHeader->FileHeader.SizeOfOptionalHeader));
for(int i=0;i<NumOfSection;i++)
{
   DWORD dwSecVA=pSectionHeader->VirtualAddress+dwImageBase;
   DWORD dwSecSize=pSectionHeader->Misc.VirtualSize;
   DWORD dwOldProtect;
   VirtualProtect((LPVOID)dwSecVA,dwSecSize,PAGE_EXECUTE_READWRITE,&dwOldProtect);
   pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader+sizeof(IMAGE_SECTION_HEADER));
}
FILE *fp;
fp=fopen("FkIAT.txt","r");
    if (fp==NULL)
    {
   MessageBox(NULL,"请把fkiat.txt放当前目录下!","ximo",MB_OK|MB_ICONINFORMATION);
    }
char buf[256]={0};
while(!feof(fp))
{
       fgets(buf,256,fp);
    DWORD dwIATAddr,dwKey;
    char szIATAddr[10]={0};
    char szKey[10]={0};
    char szDllName[50]={0};
    char szFunName[100]={0};
    char *p;
    int i=0;
    if ((p=strchr(buf,','))==NULL)
    {
     continue;
    }
    while(buf[i]!=',')
    {
     szIATAddr[i]=buf[i];
     i++;
    }
    sscanf(szIATAddr,"%08x",&dwIATAddr);
    p=strchr(buf,',');
    i=0;
    while(p[i+1]!=',')
    {
     szKey[i]=p[i+1];
     i++;
    }
    sscanf(szKey,"%08x",&dwKey);
   
    p=strchr(p+1,',');
    i=0;
    while(p[i+1]!=',')
    {
     szDllName[i]=p[i+1];
     i++;
    }
    p=strchr(p+1,',');
    i=0;
    while(p[i+1]!=0x0A)
    {
     szFunName[i]=p[i+1];
     i++;
    }
    //特殊处理下,不知道是否还有其他动态库也是如此的,想不出好的,只能硬编码了,汗

   if (strcmp(szDllName,"winspool")==0)
    {
     wsprintf(szDllName,"%s","winspool.drv");
    }
    //特殊处理2
    /*
    if ((p=strchr(szDllName,0x20))!=0)
    {
     wsprintf(szDllName,"%s",p+1);
    }*/
    if ((p=strstr(szDllName,"offset"))!=0)
    {
     wsprintf(szDllName,"%s",p+7);
    }
    HMODULE hdll=GetModuleHandle(szDllName);
    if (!hdll)
    {
     hdll=LoadLibrary(szDllName);
    }
   DWORD dwIAT=(DWORD)GetProcAddress(hdll,(LPCSTR)szFunName);
   DWORD dwWrite=dwIAT-dwKey;
   __asm
   {
    pushad
    mov eax,dwIATAddr
    mov ecx,dwWrite
    mov dword ptr [eax],ecx
    popad
   }
}
fclose(fp);

return TRUE;
}

8,最后就是用PE工具把这个DLL加到脱壳后文件的导入表中了。这个用LORDPE,CFF等工具都能搞定了。

然后把3个文件:脱壳后文件,DLL,以及对应关系的txt这3个文件放在一起,就OK了。放到其他平台测试一下,OK了。

脱壳也就到此结束了。

附上试练品,脱壳后的文件,DLL等吧。

http://u.115.com/file/t063e0b7a9


这篇关于2010-08-22_ximo_也来谈谈VMP2.05的脱壳的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/208493

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到

Science|癌症中三级淋巴结构的免疫调节作用与治疗潜力|顶刊精析·24-09-08

小罗碎碎念 Science文献精析 今天精析的这一篇综述,于2022-01-07发表于Science,主要讨论了癌症中的三级淋巴结构(Tertiary Lymphoid Structures, TLS)及其在肿瘤免疫反应中的作用。 作者类型作者姓名单位名称(中文)通讯作者介绍第一作者Ton N. Schumacher荷兰癌症研究所通讯作者之一通讯作者Daniela S. Thomm

08 增删查功能

划重点: lable 标签keyup:键盘事件标签内添加样式:style使用事件修饰符:preventforEach :遍历 数组indexOf: 可以返回要查询的某个字符串值在整个字符串中首次出现的位置下标findIndex:返回传入一个测试条件(函数)符合条件数组的首个元素的位置splice:向/从数组中添加/删除项目,然后返回被删除后的新的项目数组 黑椒蟹 一对: <!DOCTYPE

2021-08-14 react笔记-1 安装、环境搭建、创建项目

1、环境 1、安装nodejs 2.安装react脚手架工具 //  cnpm install -g create-react-app 全局安装 2、创建项目 create-react-app [项目名称] 3、运行项目 npm strat  //cd到项目文件夹    进入这个页面  代表运行成功  4、打包 npm run build

GUI编程08:画笔paint

本节内容视频链接:10、画笔paint_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1DJ411B75F?p=10&vd_source=b5775c3a4ea16a5306db9c7c1c1486b5 package com.yundait.lesson03;import java.awt.*;import java.awt.event.Wind

Ai+若依(智能售货机运营管理系统---帝可得)-人员管理-点位管理-区域管理-合作商管理----【08篇---0001:上】

项目介绍 售货机简介 帝可得是一个基于物联网概念下的智能售货机运营管理系统 物联网 物联网(IoT:Internet of Things)简单来说,就是让各种物品通过互联网连接起来,实现信息的交换和通信。 这个概念听起来可能有点抽象,但我们可以把它想象成一个超级大的社交网络。不过,这个网络里的成员不是人类,而是各种物品。比如,你的冰箱、洗衣机、甚至是你的汽车,它们都可以通过互联网互

java基础总结08-面向对象4(static关键字)

原来一个类里面的成员变量,每new一个对象,这个对象就有一份自己的成员变量,因为这些成员变量都不是静态成员变量。对于static成员变量来说,这个成员变量只有一份,而且这一份是这个类所有的对象共享。 静态成员变量与非静态成员变量的区别 以下面的例子为例说明 package cn.galc.test;public class Cat {/*** 静态成员变量*/private static

【SpringMVC学习08】SpringMVC对RESTfull的支持

RESTful架构,就是目前流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。 RESTful架构对url进行规范,写RESTful格式的url是什么样子的呢?我们一般请求的url是类似这样子的: http://...../xxx.action?id=001&type=aaa 而REST的url风格是什么样子呢?一般它类似于:

08_Tensorflow2图像处理秘籍:让图片‘听话’,AI也能成艺术家!

1. 图像数据处理 图像处理是指图像在神经网络训练之前的预处理,是人工智能视觉领域的重要组成部分。通过图像处理技术对图像数据集进行处理有两方面的作用:(1)将原始数据集处理成合格的、规范是数据集;(2)通过图像处理技术实现对原始数据集的增广。 # 库引入import matplotlib.pyplot as pltimport tensorflow as tf# 图像读取image_