【文章标题】: UPX脱壳全程分析

【保护方式】: 本地验证
【使用工具】: OllyDBG
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------

004629D0         > 60                 pushad                                                     //保存现场(pushad 相当于 push 所有的寄存器)
  004629D1         BE 00F04300         mov esi, 0043F000                                         //把代码段放到esi寄存器
  004629D6         8DBE 0020FCFF         lea edi, dword ptr [esi+FFFC2000]                         //得到基址
  004629DC         C787 9CC00400 7>    mov dword ptr [edi+4C09C], 46CD167B                     //将第一个函数的地址放到[edi+ 4C09C]
  004629E6         57 push edi                                                                 //将基址压栈
  004629E7         83CD FF or ebp, FFFFFFFF                                                     //将0012FFC0与 FFFFFFFF或
  004629EA         EB 0E jmp short 004629FA
  004629EC         90 nop
  004629ED         90 nop
  004629EE         90 nop
  004629EF         90 nop
  004629F0         8A06                 mov al, byte ptr [esi]                                     //取出0043F004的一个字节
  004629F2         46                     inc esi                                                 //指向下一个字节
  004629F3         8807                 mov byte ptr [edi], al                                     //从00401000开始,开始还原代码
  004629F5         47                     inc edi                                                 //指向下一个地址
  004629F6         01DB                 add ebx, ebx                                             //ebx + ebx,当ebx不等于零的时候跳转,下面的adc如果为,就取出下一个地址,并放到ebx中
  004629F8         75 07                 jnz short 00462A01
  004629FA         8B1E                 mov ebx, dword ptr [esi]                                 //将0043F000放到ebx中
  004629FC         83EE FC             sub esi, -4                                             //0043F000加4
  004629FF         11DB                 adc ebx, ebx                                             //进位加法器
  00462A01         ^ 72 ED             jb short 004629F0                                         // 向上跳转,ebx做为是否回跳的标志,循环处理代码
  00462A03         B8 01000000         mov eax, 1                                                 // eax = 1
  00462A08         01DB                 add ebx, ebx                                             // ebx依然作为循环的标志
  00462A0A         75 07                 jnz short 00462A13
  00462A0C         8B1E                 mov ebx, dword ptr [esi]                                 //esi指向的地址放到ebx里面
  00462A0E         83EE FC             sub esi, -4                                             //esi + 4
  00462A11         11DB                 adc ebx, ebx                                             //进位加法
  00462A13         11C0                 adc eax, eax                                             //进位加法
  00462A15         01DB                 add ebx, ebx                                             //ebx + ebx
  00462A17         73 0B                 jnb short 00462A24
  00462A19         75 28                 jnz short 00462A43                                         //跳到下面

  00462A95         81FD 00FBFFFF         cmp ebp, -500                                             //迷惑指令
  00462A9B         83D1 02             adc ecx, 2                                                 //进位加法
  00462A9E         8D142F                 lea edx, dword ptr [edi+ebp]                             //edi + ebp的地址装载到edx,即原来的代码段的地址
  00462AA1         83FD FC             cmp ebp, -4                                             //判断跳转标志,EBP小于等于-4就跳
  00462AA4         76 0E                 jbe short 00462AB4
  00462AA6         8A02                 mov al, byte ptr [edx]                                     //取出代码段的一字节
  00462AA8         42                     inc edx                                                 //指向下一个地址
  00462AA9         8807                 mov byte ptr [edi], al                                     //取出的代码放到edi里面
  00462AAB         47                     inc edi                                                 //指向下一个代码
  00462AAC         49                     dec ecx                                                 //计数器
  00462AAD         ^ 75 F7             jnz short 00462AA6                                         //关于计数器(ecx)的跳转
  00462AAF         ^ E9 42FFFFFF         jmp 004629F6                                             //向上面跳,跳到add ebx,ebx
  00462AB4         8B02                 mov eax, dword ptr [edx]                                 //处理输入表
  00462AB6         83C2 04             add edx, 4                                                 //edx + 4,指向下一个地址
  00462AB9         8907                 mov dword ptr [edi], eax                                 //将代码放到edi
  00462ABB        83C7 04             add edi, 4                                                 // edi + 4, 存放代码的地址
 
  00462AC3         01CF                 add edi, ecx                                             //edi + ecx,指向接收代码的地址的最后一个字节
  00462AC5         ^ E9 2CFFFFFF         jmp 004629F6                                             //跳到 add ebx,ebx

  00462AD2         8A07                 mov al, byte ptr [edi]                                     //指向我们原来代码段的代码,取出到AL里面
  00462AD4         47                     inc edi                                                 //指向下一个字节
  00462AD5        2C E8                 sub al, 0E8                                             //处理CALL
  00462AD7         3C 01                 cmp al, 1                                                 //判断al是否大于1
  00462AD9         ^ 77 F7             ja short 00462AD2                                        //循环,到下一个CALL的第一个字节为止

  00462AE0         8B07                 mov eax, dword ptr [edi]                                 //取出里面的地址,里面的地址是定位CALL的绝对地址要用到的
  00462AE2         8A5F 04             mov bl, byte ptr [edi+4]                                 //得到下条地址的开始字节放到AL里面,CALL绝对地址就是下条指令开始+刚才上面取出的那个数字
  00462AE5        66:C1E8 08             shr ax, 8                                                 //ax右移8位
  00462AE9         C1C0 10             rol eax, 10                                             //eax算术左移 8位
  00462AEC         86C4                xchg ah, al                                             //交换内容
  00462AEE         29F8                 sub eax, edi                                             //eax - edi
  00462AF0         80EB E8             sub bl, 0E8                                                //再减去E8
  00462AF3         01F0                 add eax, esi                                             //eax + esi,其中 esi是代码段开始的地方
  00462AF5         8907                 mov dword ptr [edi], eax                                 //这里处理CALL的地址,算出CALL的偏移到EDI里面
  00462AF7         83C7 05             add edi, 5                                                 //edi + 5,指向call的后面
  00462AFA         88D8                 mov al, bl                                                 //bl的内容放到al中
  00462AFC         ^ E2 D9             loopd short 00462AD7                                     //循环处理CALL,其中ecx作为计数器
  00462AFE         8DBE 00F00500         lea edi, dword ptr [esi+5F000]                             //代码段的起始地址 + 5F000
  00462B04         8B07                 mov eax, dword ptr [edi]                                 //现在EDI指向我们的代码的输入表
  00462B06         09C0                 or eax, eax                                             //eax 或 eax ,判断eax是否为零
 
  00462B0A         8B5F 04             mov ebx, dword ptr [edi+4]                                 //取得这个地址的数据放到ebx
  00462B0D         8D8430 AC2D0600     lea eax, dword ptr [eax+esi+62DAC]                         // 取得外壳段的KERNEL32.DLL的地址放eax
  00462B14         01F3                 add ebx, esi                                             //我们代码段的起始地址加上刚才取出的那个数据
  00462B16         50                     push eax                                                 //kernel32.dll的地址
  00462B17         83C7 08             add edi, 8                                                 //edi + 8
  00462B1A         FF96 4C2E0600         call dword ptr [esi+62E4C]                                 //装载kernel32.dll
  00462B20         95                     xchg eax, ebp                                             //交换数据,即eax指向kernel32.dll的地址
  00462B21         8A07                 mov al, byte ptr [edi]                                     //取得现在的EDI的地址指向的数据放到AL
  00462B23         47                     inc edi                                                 //指向下一个函数
  00462B24         08C0                 or al, al                                                 //al 或 al,判断al是否为零
  00462B26         ^ 74 DC             je short 00462B04
  00462B28         89F9                 mov ecx, edi                                             //取出的函数的名字放到ecx里面
  00462B2A         57                     push edi                                                 //函数名字压栈
  00462B2B         48                     dec eax                                                 //eax - 1
  00462B2C         F2:AE                 repne scas byte ptr es:[edi]
  00462B2E         55                     push ebp                                                 //kernel32.dll的基址
  00462B2F         FF96 502E0600         call dword ptr [esi+62E50]                                 //外壳的GetProcaddress
  00462B35         09C0                 or eax, eax                                             //eax或eax,得到函数的地址
  00462B37         74 07                 je short 00462B40
  00462B39         8903                 mov dword ptr [ebx], eax                                 //处理输入表
  00462B3B         83C3 04             add ebx, 4                                                 //ebx + 4,指向下一个输入表的地址
 
  00462B46         8BAE 542E0600         mov ebp, dword ptr [esi+62E54]                             //VirtualProtect的地址放到ebp
  00462B4C         8DBE 00F0FFFF         lea edi, dword ptr [esi-1000]                             //指向PE头,即映像基址
  00462B52         BB 00100000         mov ebx, 1000                                             //把1000放到ebx,即ebx = 1000

  00462B5D         FFD5                 call ebp                                                 //改变属性
  00462B5F         8D87 1F020000         lea eax, dword ptr [edi+21F]                             //现在eax指向PE头中区段的偏移起始位置
  00462B65         8020 7F             and byte ptr [eax], 7F                                     //改写区段名字
  00462B68         8060 28 7F             and byte ptr [eax+28], 7F                                 //改写区块属性第一个区块的属性

  00462B75         61                     popad                                                     //恢复现场
  00462B76         8D4424 80             lea eax, dword ptr [esp-80]
  00462B7A         6A 00                 push 0
  00462B7C         39C4                 cmp esp, eax
  00462B7E         ^ 75 FA             jnz short 00462B7A
  00462B80         83EC 80             sub esp, -80
  00462B83         ^ E9 109FFEFF         jmp 0044CA98                                             //跨区段的转移,跳到OEP

提供一份附件,看起来可能更直观:

http://www.2cto.com/uploadfile/2012/1202/20121202072155254.zip

UPX脱壳全程分析(转)的更多相关文章

  1. android 脱壳 之 dvmDexFileOpenPartial断点脱壳原理分析

    android 脱壳 之 dvmDexFileOpenPartial断点脱壳原理分析 导语: 笔者主要研究方向是网络通信协议的加密解密, 对应用程序加固脱壳技术很少研究, 脱壳壳经历更是经历少之甚少. ...

  2. 脱壳——UPX脱壳原理(脱壳helloworld)

    脱壳--UPX脱壳原理 脱壳步骤 1 找到OEP 2 dump(导出)内存文件 3 修复 1 找到OEP 1 程序运行先从壳代码运行,壳代码执行完之后会跳转到真正的OEP,也就是是说第一步,首先要找到 ...

  3. DexHunter在ART虚拟机模式下的脱壳原理分析

    本文博客地址: http://blog.csdn.net/qq1084283172/article/details/78494620 DexHunter脱壳工具在Dalvik虚拟机模式下的脱壳原理分析 ...

  4. UPX源码分析——加壳篇

    0x00 前言 UPX作为一个跨平台的著名开源压缩壳,随着Android的兴起,许多开发者和公司将其和其变种应用在.so库的加密防护中.虽然针对UPX及其变种的使用和脱壳都有教程可查,但是至少在中文网 ...

  5. DexHunter脱壳神器分析

    0x00 这篇文章我们分析Android脱壳神器DexHunter的源码. DexHunter作者也写了一篇介绍它的文章从Android执行时出发.打造我们的脱壳神器.DexHunter源码位于htt ...

  6. 安卓脱壳&&协议分析&&burp辅助分析插件编写

    前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 前言 本文以一个 app 为例,演示对 app脱壳,然后分析其 协 ...

  7. DexHunter在Dalvik虚拟机模式下的脱壳原理分析

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/78494671 在前面的博客<DexHunter的原理分析和使用说明(一)&g ...

  8. UPX压缩

    什么是UPX UPX (the Ultimate Packer for eXecutables)是一款先进的可执行程序文件压缩器,压缩过的可执行文件体积缩小50%-70% ,这样减少了磁盘占用空间.网 ...

  9. LoardPe与Import REC X64dbg脚本 脱壳 Upx

    目录 LoardPe与Import REC X64dbg脚本 脱壳 Upx 一丶X64dbg调试器与脚本 1.1 起因 1.2 脚本的调试 1.3 Upx脱壳脚本 二丶LoardPe 内存Dump与I ...

随机推荐

  1. 接口测试工具-Jmeter使用笔记(六:从文本读取参数)

    使用场景:测试一个接口并发处理数据的能力,并且每次请求传入的参数都要不同. 解决方法--- CSV Data Set Config 列举一个实例,步骤中会侧重读取参数操作的说明,其他有疑问的步骤请查阅 ...

  2. vue -about

    j基于webpack4 搭建vue 环境:https://juejin.im/post/5bc30d5fe51d450ea1328877

  3. 从零开始一起学习SLAM | 点云平滑法线估计

    点击公众号"计算机视觉life"关注,置顶星标更快接收消息! 本文编程练习框架及数据获取方法见文末获取方式 菜单栏点击"知识星球"查看「从零开始学习SLAM」一 ...

  4. HDU 3033 分组背包(至少选一个)

    分组背包(至少选一个) 我真的搞不懂为什么,所以现在就只能当作是模板来用吧 如果有大牛看见 希望评论告诉我 &代码: #include <cstdio> #include < ...

  5. Python str byte 互相转换

  6. oracle中实现某个用户truncate 其它用户下的表

    oracle文档中对truncate权限的要求是需要某表在当前登录的用户下,或者当前登录的用户有drop any table的权限. 但是如果不满足第一个条件的情况下,要让某用户满足第二个条件就导致权 ...

  7. java poi 合并 word文档

    import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import jav ...

  8. 利用js和JQuery定义一个导航条菜单

    利用js和JQuery定义一个导航条 效果: 一.html代码: <div class="Maintenance"> <div class="Title ...

  9. linux sar的使用

    sar(System Activity Reporter系统活动情况报告)是目前Linux上最为全面的系统性能分析工具之一,可以从多个方面对系统的活动进行报告,包括:文件的读写情况.系统调用的使用情况 ...

  10. Docker Registry V2 with Nginx

    安装 nginx 修改/etc/yum.repos.d/nginx.repo [nginx] name=nginx repo baseurl=http://nginx.org/packages/cen ...