Sothink SWF Decompiler MX 2005a Build 50318 (Arm 4)脱壳
注:网上很早就有破解版,但有加壳压缩了还有1.9M多,原因你也看一下,脱壳后更利害20多M,不能跨平台,懒得用

我也来一下,什么,自己脱壳!我自己优化后(不是最优)2M多点加壳才695K,再脱壳也不是这个20多M的天文数字

我不会提供程序,想练手可以自己到网上找一下这个版本吧

【脱壳保护】:双进程调试保护 CopyMEM2,IAT乱序,Stolen Code远程跳转,CC,壳注册保护

【脱壳难度】:熟悉了解了就不是难的事。做成脚本运行,就是好玩!

【作者声明】:写此文只是感兴趣,同时我也很想借此机会锻炼一下自己的语文(主要原因),经常是人家听不懂,说话又结巴的。失误之处敬请诸位大侠赐教

【调试环境】:WinXP、OllyDbg1.10_Diy(我喜欢玩自己DIY的)_Anti、PEiD、LordPE、ImportRec

一、探望OEP

PEid0.93 查得是 Armadillo 3.78 -> Silicon Realms Toolworks

【OD设置】:忽略所有异常,同时忽略异常范围勾上: 
          C000001D(ILLEGAL ISTRUCTION)
          C0000005(ACCESS ViO)
          C000001E(INVALID LOCK SEQUENCE)

OD载入停在入口处,隐藏好调试标记

代码:
005C5000 >pushad               //停在入口 005C5001  call 005C5006        ; SWFDecom.005C5006 005C5006  pop ebp 005C5007  push eax 005C5008  push ecx 005C5009  bswap edx 005C500B  not edx 005C500D  pushfd 005C500E  not edx 005C5010  bswap edx 005C5012  jmp short 005C5023   ; SWFDecom.005C5023


在"OpenMutexA", "kernel32.dll"上先进行单转双的操作,有很多的教程都有,脚本又有,不多说了

转换成功后,取消所有断点
命令行设置断点:
he OutputDebugStringA
he SetProcessWorkingSetSize

点F9运行,中断在 OutputDebugStringA 上,说明是arm4 以上的版本加的壳
这个反调试手段,没两下,就会人识穿,如果你没自己玩一下 DIY ,按 Fly 等说的办


取消这个断点,点F9运行,
中断在 SetProcessWorkingSetSize 上,取消这个断点。
Alt+F9 返回,找一下“armVersion”
加壳版本显示变成这样,要运行它前面一大堆的代码才能出来的,没有以前的直接Push版本号了

代码:
00D6E613  add esp,18 00D6E616  push eax                           //这个应该是版本号 00D6E617  push 0D96008                       ; ASCII "   <armVersion xsi:type=""xsd:string"">%s</armVersion>",LF 00D6E61C  lea eax,dword ptr ss:[ebp-2200] 00D6E622  push 0 00D6E624  push eax 00D6E625  call esi


Ctrl+S 在当前位置下搜索命令序列:

sub ecx, edx
call ecx

有两处如下:

代码:
00D8C7E5  sub ecx,edx 00D8C7E7  call ecx          //这里估计也是OEP,可能是校验或解码出错跑这吧 00D8C7E9  jmp short 00D8C806 00D8C7EB  cmp edi,1 00D8C7EE  jnz short 00D8C808 00D8C7F0  push dword ptr ds:[esi+4] 00D8C7F3  push dword ptr ds:[esi+8] 00D8C7F6  push 0 00D8C7F8  push edx 00D8C7F9  mov edx,dword ptr ds:[eax+74] 00D8C7FC  xor edx,dword ptr ds:[eax+60] 00D8C7FF  xor edx,dword ptr ds:[eax+2C] 00D8C802  sub ecx,edx 00D8C804  call ecx  //*** 这里是前往OEP 4B2BCD ***//


二、Magic Jump,避开IAT加密

重来,方法是用fly的定位方式,到达Magic Jump的地方,方便避开了反跟踪,

代码:
00D74588  call dword ptr ds:[D92104]         ; kernel32.GetModuleHandleA 00D7458E  mov ecx,dword ptr ds:[D9F67C]      //返回这里 00D74594  mov dword ptr ds:[esi+ecx],eax 00D74597  mov eax,dword ptr ds:[D9F67C] 00D7459C  cmp dword ptr ds:[esi+eax],ebx 00D7459F  jnz short 00D745B7 00D745A1  lea eax,dword ptr ss:[ebp-14C] 00D745A7  push eax 00D745A8  call dword ptr ds:[D9210C]         ; kernel32.LoadLibraryA 00D745AE  mov ecx,dword ptr ds:[D9F67C] 00D745B4  mov dword ptr ds:[esi+ecx],eax 00D745B7  mov eax,dword ptr ds:[D9F67C] 00D745BC  cmp dword ptr ds:[esi+eax],ebx 00D745BF  je 00D746F4                        //传闻很久的Magic Jump,改跳就是啦 00D745C5  xor ecx,ecx 00D745C7  mov eax,dword ptr ds:[edi] 00D745C9  cmp dword ptr ds:[eax],ebx 00D745CB  je short 00D745D3


IAT处理可以运行我本人推荐的脚本进行修复,不懂不想用你也可以自已写代码修复,网上也留传很多修复方案,很简单的事!

多说几句,如果你用我的IAT修复脚本,那么在完成第4步,你可以先将整个申请内存块复制下来备用,
在OEP处(或重来在你认为适当的时机,申请同样大小的内存块,将备份块弄回去,注意要参数要对应,一般我不推荐这样做 ,但若你申请到的块地址是一样的就不用改参数)运行第5个进行修复。
我脚本修复的最终特点是:IAT没有重复的API,按模块排序,方便更改跨平台API(一般指NT.dll的API);另外,我所说的“未必通用”是指前往 Magic JMP 的脚本1(脚本1是用来修改Magic Jmp 和到达 Iat 正式处理的地方),其它的可以套用,关键你看懂了脚本参数没有。


三、Stolen Code远程跳转

代码:
004010A0  jmp 03530000            //这里就是Stolen Code远程跳转的块首地址 004010A5  push edi 004010A6  pop edi 004010A7  mov eax,dword ptr fs:[0] 004010AD  jmp 03530023 004010B2  push ecx 004010B3  xchg ebx,edx 004010B5  bswap edi 004010B7  bswap edi 004010B9  bswap edi 004010BB  bswap edi 004010BD  xchg ebx,edx 004010BF  pop ecx 004010C0  call 00503183                      ; SWFDecom.00503183


脱壳后的程序需要有这个Stolen Code远程跳转块,才能正常运行,没有的话...嘿嘿
解决的办法,可以简单处理,也可以变态还原处理,一般我们建议简单处理。

简单处理:在脱壳后的程序增开一个节,将该节的RVA设置为当时动态获得的Stolen Code 的RVA
变态还原:指将在Stolen Code块隐藏的程序原本的代码,逐一还原到代码段。

我们来到一下这个处理的地方:
现在的新版,已经不再使用 VirtualAlloc 这个函数申请空间,而是采用 msvcrt.operator new
当然这个名称是 OD 打印给我们的,实际上是这样的形式:"??2@YAPAXI@Z", "msvcrt.dll"

经过修改Magic Jmp后 中断这个函数,注意观察函数申请大小的变化,变成 142000 的要提神了。

代码:
00D880EC  call 00D91726                          ; jmp to msvcrt.operator new 00D880F1  pop ecx                                //返回这里 00D880F2  mov dword ptr ss:[ebp+FFFFAFD0],eax 00D880F8  mov eax,dword ptr ss:[ebp+FFFFAFD0] 00D880FE  mov dword ptr ss:[ebp-2A34],eax 00D88104  mov eax,dword ptr ss:[ebp-2A34] 00D8810A  mov dword ptr ss:[ebp-2A2C],eax 00D88110  mov eax,dword ptr ss:[ebp-2A38] 00D88116  add eax,10000                          ; UNICODE "=::=::\" …… 00D88185  push 0D98A20                        ; ASCII "Location ES1" 00D8818A  mov eax,dword ptr ss:[ebp+8] 00D8818D  push dword ptr ds:[eax+4] 00D88190  call 00D917BA                       ; jmp to msvcrt.strcpy 00D88195  pop ecx 00D88196  pop ecx 00D88197  xor eax,eax 00D88199  jmp 00D8AA42 00D8819E  cmp dword ptr ss:[ebp-2A44],0 00D881A5  jnz short 00D881A9 00D881A7  jmp short 00D881C0 00D881A9  mov eax,dword ptr ss:[ebp-2A2C] 00D881AF  add eax,dword ptr ss:[ebp-2A44] 00D881B5  mov dword ptr ss:[ebp-2A2C],eax 00D881BB  jmp 00D8812C 00D881C0  mov eax,dword ptr ss:[ebp-2A2C]     ; // 401000 块的首次解码内容的首地址 00D881C6  sub eax,dword ptr ss:[ebp-2A34]     ; //应该是401000解码后的 最后地址 00D881CC  mov dword ptr ss:[ebp-2A30],eax     ; // 保存41000段解码后的 大小 00D881D2  mov eax,dword ptr ss:[ebp-2A30] 00D881D8  cmp eax,dword ptr ss:[ebp-2A38]     ; // 比较是否与小于内存映像块的大小 00D881DE  jnb short 00D881FD 00D881E0  mov eax,dword ptr ss:[ebp-2A38]     ; // 默认是小于 00D881E6  sub eax,dword ptr ss:[ebp-2A30]     ; // 求它们之间的差:size 00D881EC  push eax                            ; // 将其差值空间置 0 00D881ED  push 0 00D881EF  push dword ptr ss:[ebp-2A2C] 00D881F5  call 00D91732                       ; jmp to msvcrt.memset 00D881FA  add esp,0C 00D881FD  cmp dword ptr ss:[ebp-2800],0     ; // 应该是一个表来的,地址为:1007360 00D88204  je 00D8837D                       ; // 为 0 表示不处理或结束吧 00D8820A  mov eax,dword ptr ss:[ebp-27F4]   ; // 程序基址 00D88210  add eax,dword ptr ss:[ebp-2A3C]   ; // 基址 + 本块的 RVA 00D88216  mov ecx,dword ptr ss:[ebp-2800] 00D8821C  cmp dword ptr ds:[ecx],eax        ; // 比较是否少于该块的基地 00D8821E  jb 00D8837D                       ; // 小于也不处理 00D88224  mov eax,dword ptr ss:[ebp-27F4]   ; // 基址 00D8822A  add eax,dword ptr ss:[ebp-2A3C]   ; // 本块的 RVA 00D88230  add eax,dword ptr ss:[ebp-2A38]   ; // + size = 计算出下一个块的地址 00D88236  mov ecx,dword ptr ss:[ebp-2800]   ; // 表 00D8823C  cmp dword ptr ds:[ecx],eax        ; // 是否超越边界 00D8823E  jnb 00D8837D 00D88244  mov ecx,0D9B448 00D88249  call 00D8B9DE 00D8824E  mov byte ptr ss:[ebp-2A48],al 00D88254  movzx eax,byte ptr ss:[ebp-2A48] 00D8825B  shl eax,18 00D8825E  movzx ecx,byte ptr ss:[ebp-2A48] 00D88265  shl ecx,10 00D88268  or eax,ecx 00D8826A  movzx ecx,byte ptr ss:[ebp-2A48] 00D88271  shl ecx,8 00D88274  or eax,ecx 00D88276  movzx ecx,byte ptr ss:[ebp-2A48] 00D8827D  or eax,ecx 00D8827F  mov dword ptr ss:[ebp-2A4C],eax 00D88285  mov eax,dword ptr ss:[ebp-2800] 00D8828B  mov dword ptr ss:[ebp-2A50],eax 00D88291  mov eax,dword ptr ss:[ebp-2A50] 00D88297  cmp dword ptr ds:[eax],0          ; // 表指针,是否完成 00D8829A  je 00D8837D 00D882A0  mov eax,dword ptr ss:[ebp-2A50] 00D882A6  mov eax,dword ptr ds:[eax]        ; //取出补丁地址 00D882A8  mov dword ptr ss:[ebp-2A58],eax 00D882AE  mov eax,dword ptr ss:[ebp-2A50] 00D882B4  add eax,4                         ; // 表指针 +4 00D882B7  mov dword ptr ss:[ebp-2A50],eax 00D882BD  mov eax,dword ptr ss:[ebp-2A50] 00D882C3  mov eax,dword ptr ds:[eax]        ; // 取跳转偏移量 00D882C5  mov dword ptr ss:[ebp-2A54],eax 00D882CB  mov eax,dword ptr ss:[ebp-2A50] 00D882D1  add eax,4 00D882D4  mov dword ptr ss:[ebp-2A50],eax 00D882DA  mov eax,dword ptr ss:[ebp-27F4] 00D882E0  add eax,dword ptr ss:[ebp-2A3C] 00D882E6  cmp dword ptr ss:[ebp-2A58],eax 00D882EC  jbe short 00D8836A 00D882EE  mov eax,dword ptr ss:[ebp-27F4] 00D882F4  add eax,dword ptr ss:[ebp-2A3C] 00D882FA  add eax,dword ptr ss:[ebp-2A38] 00D88300  cmp dword ptr ss:[ebp-2A58],eax   ; // 比较代码段的补丁地址是否大于代码段地址 00D88306  jnb short 00D8836A 00D88308  mov eax,dword ptr ss:[ebp-27F4] 00D8830E  add eax,dword ptr ss:[ebp-2A3C] 00D88314  mov ecx,dword ptr ss:[ebp-2A58] 00D8831A  sub ecx,eax                       ; // 取本块补丁地址偏移量, 如:4010A1 - 401000 = A1 00D8831C  mov dword ptr ss:[ebp-2A5C],ecx 00D88322  mov al,byte ptr ds:[D9B86C] 00D88327  mov byte ptr ss:[ebp+FFFFAE38],al 00D8832D  movzx eax,byte ptr ss:[ebp+FFFFAE> 00D88334  test eax,eax 00D88336  je short 00D88354 00D88338  mov eax,dword ptr ss:[ebp-2A54] 00D8833E  xor eax,dword ptr ss:[ebp-2A4C] 00D88344  mov ecx,dword ptr ss:[ebp-2A34] 00D8834A  add ecx,dword ptr ss:[ebp-2A5C] 00D88350  mov dword ptr ds:[ecx],eax 00D88352  jmp short 00D88368 00D88354  mov eax,dword ptr ss:[ebp-2A34]   ; // 取代码段首地址 00D8835A  add eax,dword ptr ss:[ebp-2A5C]   ; // + 补丁地址偏移量 = 计算出修复的地址 00D88360  mov ecx,dword ptr ss:[ebp-2A54]   ; // 取跳转偏移量,补丁的机会 First: 00D88366  mov dword ptr ds:[eax],ecx        ; // 写入跳转偏移量 00D88368  jmp short 00D88378 00D8836A  mov eax,dword ptr ss:[ebp-2A58] 00D88370  mov ecx,dword ptr ss:[ebp-2A54]   ; // 取跳转偏移量, 也是机会 Second: 00D88376  mov dword ptr ds:[eax],ecx        ; // 写入偷取代码块的跳转偏移量 00D88378  jmp 00D88291


//表:1007360 的组成很有规律的,对应动态申请的 Stolen Code ,自己看一下就明白了。
//上面这段是处理Stolen Code JMP偏移量的计算处理,因为是块动态申请的,所以壳要做这部分工作
//看到了吧,跟一下,就能体会到的,这时还没写入IAT,过了这个步骤,就快要解码处理IAT的代码!
//现在你可以做的事,不管它,直接到IAT处理的部分;来个小小的处理,使DUMP文件一脱下来就有 Stolen Code 部分(这个要在入口处做个复制粘贴的工作,我是用脚本完成的)

找个空间地方写类似下面的代码,主要是将 JMP 的偏移地址改到你认为合适的程序地址,我选择了壳的运行代码块 585000
First: 4010000
 壳申请首地址(1B80000)--动态的
 -跳转偏移值(ecx)
自定义Stolen Code首地址(585000)

D88360  Call (First) //改到你补丁的地方
D88365  nop
D88366  mov dword ptr ds:[eax],ecx

First:
  mov ecx,dword ptr ss:[ebp-2A54] //失去的指令
  push eax
  mov eax,1B80000
  sub eax,585000
  sub ecx,eax
  pop eax
  retn
  nop
  nop


Second: 585000
D88370  call (Second)  //改到你补丁的地方
D88375  nop

Second:
  mov ecx,dword ptr ss:[ebp-2A54]
  push eax
  mov edx,1B80000
  add eax,4
  add ecx,eax
  sub eax,edx
  add eax,585000
  sub ecx,eax
  pop eax
  retn
  nop
  nop

//在 00D88378 的下一个指令下断(即出口),运行中断后,撤消刚才的代码,免得校验出问题!
//接下来是 IAT 的处理部分,我不多说了,fxyang等已经介绍过很多了!

代码:
00D8A454      call dword ptr ds:[D92170]                 ; kernel32.VirtualProtect 00D8A45A      mov al,byte ptr ds:[D9B86C]                //经典的更改节属性为可写的跟踪必中点 00D8A45F      mov byte ptr ss:[ebp+FFFFAD30],al 00D8A465      movzx eax,byte ptr ss:[ebp+FFFFAD30] 00D8A46C      test eax,eax 00D8A46E      je short 00D8A48D 00D8A470      push 0 00D8A472      push dword ptr ss:[ebp+FFFFB0C8] 00D8A478      mov eax,dword ptr ss:[ebp-27F4] 00D8A47E      add eax,dword ptr ss:[ebp+FFFFB0B8] 00D8A484      push eax 00D8A485      call 00D8B4A7 00D8A48A      add esp,0C 00D8A48D      mov eax,dword ptr ss:[ebp-2804] 00D8A493      mov esi,dword ptr ss:[ebp-27F4] 00D8A499      sub esi,dword ptr ds:[eax+34] 00D8A49C      call 00D8CFFD 00D8A4A1      neg eax 00D8A4A3      sbb eax,eax 00D8A4A5      and eax,1000 00D8A4AA      add esi,eax 00D8A4AC      mov dword ptr ss:[ebp+FFFFB0C0],esi 00D8A4B2      and dword ptr ss:[ebp+FFFFB0C4],0 00D8A4B9      jmp short 00D8A4C8 00D8A4BB      mov eax,dword ptr ss:[ebp+FFFFB0C4] 00D8A4C1      inc eax 00D8A4C2      mov dword ptr ss:[ebp+FFFFB0C4],eax 00D8A4C8      mov eax,dword ptr ss:[ebp+FFFFB0C4] 00D8A4CE      mov ecx,dword ptr ss:[ebp-26DC] 00D8A4D4      cmp dword ptr ds:[ecx+eax*4],0 00D8A4D8      je 00D8A56E 00D8A4DE      mov eax,dword ptr ss:[ebp+FFFFB0C4] 00D8A4E4      mov ecx,dword ptr ss:[ebp-26DC] 00D8A4EA      mov edx,dword ptr ss:[ebp-27F4] 00D8A4F0      add edx,dword ptr ds:[ecx+eax*4] 00D8A4F3      mov dword ptr ss:[ebp+FFFFB0B4],edx 00D8A4F9      mov eax,dword ptr ss:[ebp+FFFFB0B4] 00D8A4FF      mov eax,dword ptr ds:[eax] 00D8A501      mov dword ptr ss:[ebp+FFFFB0B0],eax 00D8A507      cmp dword ptr ss:[ebp+FFFFB0B0],90909090 00D8A511      je short 00D8A569 00D8A513      mov eax,dword ptr ss:[ebp+FFFFB0B0] 00D8A519      sub eax,dword ptr ss:[ebp+FFFFB0C0] 00D8A51F      mov dword ptr ss:[ebp+FFFFB0B0],eax 00D8A525      push dword ptr ss:[ebp+FFFFB0B0] 00D8A52B      mov eax,dword ptr ss:[ebp+FFFFB0C4] 00D8A531      xor edx,edx 00D8A533      push 10 00D8A535      pop ecx 00D8A536      div ecx 00D8A538      call dword ptr ds:[edx*4+D927EC] 00D8A53F      pop ecx 00D8A540      mov dword ptr ss:[ebp+FFFFB0B0],eax 00D8A546      mov eax,dword ptr ss:[ebp+FFFFB0B0] 00D8A54C      mov ecx,dword ptr ss:[ebp-281C]            ; // Start IAT Position 00D8A552      lea eax,dword ptr ds:[ecx+eax*4] 00D8A555      mov dword ptr ss:[ebp+FFFFB0B0],eax 00D8A55B      mov eax,dword ptr ss:[ebp+FFFFB0B4]        ; // Modify Address 00D8A561      mov ecx,dword ptr ss:[ebp+FFFFB0B0]        ; // Api Address 00D8A567      mov dword ptr ds:[eax],ecx                 ; // Writing Maybe Crypt Api Address 00D8A569      jmp 00D8A4BB


// 我们再来找 Anti Dump ,主要是壳会修改 PE 头的 OffSet 位置(因为他已经映射好了),使得你通过获取程序进程无法分析或 Dump 下来的脱壳文件天生就是错误的 PEheader
// 对付的办法也挺简单,也是 fly 常说的选择来自磁盘文件的 PEheader。想知道壳哪里动手,也很简单,在[基地 + 3C] 这个 Dword 上下访问断点,中断后就知道了,不贴代码了!
// IAT 处理完,就可按上面前往 OEP 的方式抵达 OEP,这时可以将 Stolen Code 的块 复制到 你预定程序的位置 如:585000
// 将程序的所有节权限全部改为完整(点内存窗口就可以右键菜单改),我是用脚本 movedata.txt 完成的,OD 的复制粘贴也是很简单的事!
// 如果你是用我的脚本,现在你看到的一些Call [] 是 壳处理的结果,再运行我第 5个 脚本,嘿嘿,怎么样,不到1 秒钟就很好看了。
// 现在可以拿出 LordPE 和 ImportRec 分别 Dump 出脱壳文件和获取 Iat 信息,ImportRec 只要入口填对,就能获得整齐简洁的IAT,可以先保存成树文件下来。

到现在为止,你如果想获得跨平台,我这里XP没有装 flash 控件,所以要到 98  上运行,就要改 nt.dll 上的 API 为与之对应 的 Kernel32.dll 的API,fly 的arm4.0加壳的精华last版有介绍,就不多说了,改刚才的Iat树文件吧,搞定后Load之, fix Iat!
一运行,嘿嘿,我们就要遇上CC了,好在这个程序没有加上很多的CC,所以手工修复,也是个不错的选择,多数都很好猜是硬插的绝对跳转来的,不猜也行!


四、CC 修复
下面是 CC 手动修复(只有修复到能运行,不是参考snoop汉化版的过程,其它的自己来吧,不会很多,基本上修复的地方与破解是关联的)

在这个阶段大部分是手工活,也是最花时间的 Armadillo 的  Nanomites保护,其特征代码我就不全贴了,没意义,前人的文章多的是。

我们仍然需要取得 4 个表:INT3地址表,跳转类型表,跳转距离表,非跳距离表

网上也没有流传 能够一次性完整修复 所有 CC 的方案

当然你喜欢查表,逆向运算表的,自己玩,我可没这本事!

虽然我看过看雪精华6前面兄弟的修复文章,又Nop代码,又移动代码,又加自己代码,一轮又一轮...看得挺烦的,不如按自己理解的来(跳转类型方案还没完全确定下来,不过确定的现在够用),这里我只是用自己写代码 Log 运行程序记录的 4 个表,即属于一种被动修复方式,适用于 CC 修复量较小。

OD设置一样,重来加载程序,He GetThreadContext,中断两次就取消断点来到:

代码:
005A144F  call dword ptr ds:[5D50DC]  ; kernel32.GetThreadContext 005A1455  push eax                    //来到这里 005A1456  not eax 005A1458  bswap eax 005A145A  pop eax ……//向下翻找到这里 005A1614   mov eax,dword ptr ss:[ebp-119C] 005A161A   mov ecx,dword ptr ds:[eax*4+5DBE90] …… 005A170C  add esp,4 005A170F  mov dword ptr ss:[ebp-1480],eax 005A1715  mov eax,dword ptr ss:[ebp-1480] 005A171B  and eax,1 005A171E  test eax,eax                      //计算跳与不跳的关键点,在这里补一下代码 005A1720  je 005A17D4                       ; SWFDecom.005A17D4 005A1726  pushad 005A1727  xor eax,eax


我用 C-pen 的方式确定跳转类型,其实大家的方式是基本一致的,只不过是谁的好理解。

本例中 5A1614 -- 5A171E 是可以借助确定跳转类型的过程

申请一个内存块,用来运行和记录表,我申请了10000h,地址是:E60000

贴上这片代码:
///////////////////////////////////
E60000:
00 00 00 00 00 00 00 00 01 00 00 00 04 00 00 00 40 00 00 00 80 00 00 00 00 08 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 90 90 90 90 8B 85 64 EE FF FF 8B 0C 85 90 BE 5D 00 8B 95 90
EB FF FF 33 C0 8A 04 11 89 85 74 EB FF FF 8B 85 74 EB FF FF 99 83 E2 0F 03 C2 C1 F8 04 89 85 7C
EB FF FF 8B 8D 74 EB FF FF 81 E1 0F 00 00 80 79 05 49 83 C9 F0 41 89 8D 78 EB FF FF 8B 95 7C EB
FF FF 3B 95 78 EB FF FF 75 1B 8B 85 78 EB FF FF 83 C0 01 25 0F 00 00 80 79 05 48 83 C8 F0 40 89
85 78 EB FF FF 8B 8D 74 EB FF FF 8B 95 7C EB FF FF 8B 04 8D E8 AF 5D 00 33 04 95 CC 52 5D 00 8B
8D 78 EB FF FF 33 04 8D CC 52 5D 00 89 85 84 EB FF FF E8 00 00 00 00 5A 81 EA D7 00 00 00 8B 02
8B 54 82 04 52 8B 85 74 EB FF FF 0F BE 88 20 98 5D 00 FF 14 8D 28 99 5D 00 83 C4 04 89 85 88 EB
FF FF 8B 95 44 EC FF FF 52 8B 85 88 EB FF FF 50 FF 95 84 EB FF FF 83 C4 08 50 8B 8D 74 EB FF FF
0F BE 91 20 98 5D 00 FF 14 95 68 99 5D 00 83 C4 04 89 85 80 EB FF FF 8B 85 80 EB FF FF 83 E0 01
90 90 90 90 E8 00 00 00 00 59 81 E9 49 01 00 00 8B 59 04 D1 E3 03 D8 89 59 04 8B 11 42 89 11 83
FA 06 0F 85 C8 FE FF FF 8B C1 05 00 80 00 00 8B 50 FC 89 1C 90 42 89 50 FC 33 C0 89 01 89 41 04
C3 90 90 90 60 8B 8D 64 EE FF FF 8B 0C 8D B0 BD 5D 00 8B 85 90 EB FF FF 33 D2 BE 10 00 00 00 F7
F6 8B 85 90 EB FF FF 8B 0C 81 33 8C 95 8C EE FF FF 8B 95 50 EC FF FF E8 00 00 00 00 58 2D BC 01
00 00 8B D8 81 C3 00 A0 00 00 8B 7B FC 41 89 0C BB 47 89 7B FC 05 00 E0 00 00 8B 78 FC 4A 89 14
B8 47 89 78 FC 61 90 90 90 90 60 8B 85 64 EE FF FF 8B 0C 85 D8 BE 5D 00 8B 95 90 EB FF FF 33 C0
8A 04 11 8B 8D 50 EC FF FF E8 00 00 00 00 5A 81 EA 0E 02 00 00 8B DA 81 C3 00 C0 00 00 8B 7B FC
40 89 04 BB 47 89 7B FC 61 C3 90


//块的顶部是2个变量和4个EFL常量,其它的以后用上的再说。

真正的运行代码如下:
//注:说到的“搬运代码”都是壳的代码,因为要用到表,所以无法统一,只好用“搬”

L004: // 这里地址是:00E6002B
  mov eax,dword ptr ss:[ebp-119C]    //搬运 5A1614 -- 5A171F 的代码来确定 EFL 跳不跳 
  mov ecx,dword ptr ds:[eax*4+5DBE90]
  mov edx,dword ptr ss:[ebp-1470]
  xor eax,eax
  mov al,byte ptr ds:[ecx+edx]
  mov dword ptr ss:[ebp-148C],eax
  mov eax,dword ptr ss:[ebp-148C]
  cdq
  and edx,0F
  add eax,edx
  sar eax,4
  mov dword ptr ss:[ebp-1484],eax
  mov ecx,dword ptr ss:[ebp-148C]
  and ecx,8000000F
  jns L022
  dec ecx
  or ecx,FFFFFFF0
  inc ecx
L022:
  mov dword ptr ss:[ebp-1488],ecx
  mov edx,dword ptr ss:[ebp-1484]
  cmp edx,dword ptr ss:[ebp-1488]
  jnz L034
  mov eax,dword ptr ss:[ebp-1488]
  add eax,1
  and eax,8000000F
  jns L033
  dec eax
  or eax,FFFFFFF0
  inc eax
L033:
  mov dword ptr ss:[ebp-1488],eax
L034:
  mov ecx,dword ptr ss:[ebp-148C]
  mov edx,dword ptr ss:[ebp-1484]
  mov eax,dword ptr ds:[ecx*4+5DAFE8]
  xor eax,dword ptr ds:[edx*4+5D52CC]
  mov ecx,dword ptr ss:[ebp-1488]
  xor eax,dword ptr ds:[ecx*4+5D52CC]
  mov dword ptr ss:[ebp-147C],eax
  call L042
L042:
  pop edx
  sub edx,0D7
  mov eax,dword ptr ds:[edx]
  mov edx,dword ptr ds:[edx+eax*4+4]
  push edx
  mov eax,dword ptr ss:[ebp-148C]
  movsx ecx,byte ptr ds:[eax+5D9820]
  call dword ptr ds:[ecx*4+5D9928]
  add esp,4
  mov dword ptr ss:[ebp-1478],eax
  mov edx,dword ptr ss:[ebp-13BC]
  push edx
  mov eax,dword ptr ss:[ebp-1478]
  push eax
  call dword ptr ss:[ebp-147C]
  add esp,8
  push eax
  mov ecx,dword ptr ss:[ebp-148C]
  movsx edx,byte ptr ds:[ecx+5D9820]
  call dword ptr ds:[edx*4+5D9968]
  add esp,4
  mov dword ptr ss:[ebp-1480],eax
  mov eax,dword ptr ss:[ebp-1480]
  and eax,1                         // 搬运代码结束
  nop
  nop
  nop
  nop
  call L071
L071:
  pop ecx
  sub ecx,149
  mov ebx,dword ptr ds:[ecx+4]
  shl ebx,1
  add ebx,eax
  mov dword ptr ds:[ecx+4],ebx
  mov edx,dword ptr ds:[ecx]
  inc edx
  mov dword ptr ds:[ecx],edx
  cmp edx,6
  jnz L004
  mov eax,ecx
  add eax,8000                      //设定Log跳转类型表的地址
  mov edx,dword ptr ds:[eax-4]
  mov dword ptr ds:[eax+edx*4],ebx
  inc edx
  mov dword ptr ds:[eax-4],edx
  xor eax,eax
  mov dword ptr ds:[ecx],eax
  mov dword ptr ds:[ecx+4],eax
  retn
  nop
  nop
  nop
  pushad
  mov ecx,dword ptr ss:[ebp-119C]     //搬过来的确定跳转距离
  mov ecx,dword ptr ds:[ecx*4+5DBDB0]
  mov eax,dword ptr ss:[ebp-1470]
  xor edx,edx
  mov esi,10
  div esi
  mov eax,dword ptr ss:[ebp-1470]
  mov ecx,dword ptr ds:[ecx+eax*4]
  xor ecx,dword ptr ss:[ebp+edx*4-1174]
  mov edx,dword ptr ss:[ebp-13B0]   //搬运结束
  call L107
L107:
  pop eax
  sub eax,1BC
  mov ebx,eax
  add ebx,0A000                   //设定Log跳转距离表的地址
  mov edi,dword ptr ds:[ebx-4]
  inc ecx
  mov dword ptr ds:[ebx+edi*4],ecx
  inc edi
  mov dword ptr ds:[ebx-4],edi
  add eax,0E000                   //设定Log跳转类型表的地址
  mov edi,dword ptr ds:[eax-4]
  dec edx
  mov dword ptr ds:[eax+edi*4],edx
  inc edi
  mov dword ptr ds:[eax-4],edi
  popad
  nop
  nop
  nop
  nop
  nop
  pushad
  mov eax,dword ptr ss:[ebp-119C]     //搬过来的确定不跳转距离
  mov ecx,dword ptr ds:[eax*4+5DBED8]
  mov edx,dword ptr ss:[ebp-1470]
  xor eax,eax
  mov al,byte ptr ds:[ecx+edx]
  mov ecx,dword ptr ss:[ebp-13B0]    //搬运结束
  call L135
L135:
  pop edx
  sub edx,20E
  mov ebx,edx
  add ebx,0C000                   //设定Log不跳转距离表的地址
  mov edi,dword ptr ds:[ebx-4]
  inc eax
  mov dword ptr ds:[ebx+edi*4],eax
  inc edi
  mov dword ptr ds:[ebx-4],edi
  popad
  retn //返回 005A172F
  nop
///////////////////////////////////////////
补丁到 Log 的代码
5A171E:
9C 60 33 C0 E8 1D EA 8B 00 61 9D 90 E8 55 EA 8B 00 85 C0 0F 84 9D 00 00 00 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90

005A171E   pushfd
005A171F   pushad
005A1720   xor eax,eax
005A1722   call 00E60144
005A1727   popad
005A1728   popfd
005A1729   nop
005A172A   call 00E60184
005A172F   test eax,eax
005A1731   je 005A17D4      ; SWFDecom.005A17D4
005A1737   nop
……
//////////////////////////////////////////////
运行后,点 Continue 按钮继续试用,这样就已经登记了我们要 Log 的 4 个表了(计算器的就不贴了,在表的上面),如下:
CC地址表(顺序激活发生,好在没有重复,我这里的代码没有排除重复的):
42835B
428367
42838C
4A4B9B
4A4BBC
4A4346
4A4362
4A43EA
4A440B
4283CB
4283EE

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

cc_addr_tab:

0000E000   5B 83 42 00  67 83 42 00  8C 83 42 00  9B 4B 4A 00
0000E010   BC 4B 4A 00  46 43 4A 00  62 43 4A 00  EA 43 4A 00
0000E020   0B 44 4A 00  CB 83 42 00  EE 83 42 00 


jmp_kind_tab:

00008000   1F 00 00 00  1B 00 00 00  04 00 00 00  1F 00 00 00
00008010   1F 00 00 00  1F 00 00 00  14 00 00 00  1F 00 00 00
00008020   1F 00 00 00  04 00 00 00  1F 00 00 00


jmp_of_tab:

0000A000   05 00 00 00  87 00 00 00  10 00 00 00  05 00 00 00
0000A010   05 00 00 00  05 00 00 00  15 00 00 00  05 00 00 00
0000A020   05 00 00 00  1E 00 00 00  05 00 00 00


nojmp_of_tab:
Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

0000C000   05 00 00 00  06 00 00 00  02 00 00 00  05 00 00 00
0000C010   05 00 00 00  05 00 00 00  02 00 00 00  05 00 00 00
0000C020   05 00 00 00  02 00 00 00  05 00 00 00

跳转类型:
1F 是 jmp ->11111
1B 是 jne ->11011
04 是 je  ->00100
14 是 jbe ->10100 //这个不太肯定,CF也可以作用,不过它上面是这条指令:test eax, eax

推出修复:
42835B:
jmp
指令长度为:5字节(不跳距离)
jmp (42835B+5)
EB03 或 E900000000 (5-5)

428367:
jne
指令长度为:6字节(不跳距离)
jne (428367+87)
0F8581000000 (87-6)

42838C:
je
指令长度为:2字节(不跳距离)
je (42838C+10)
740E (10-2)

4A4362:
jbe
指令长度为:2字节(不跳距离)
jbe (4A4362+15)
7613 (15-2)

还有其它的绝对跳转就不再举了。。。一样处理
当然可以再写代码修复,自己玩吧,修复后保存它,现在它可以正常运行了,但只修复到运行,加载swf文件,点其它菜单还有CC没修复,我是在98修的(猜也好玩)-- 我XP没有flash控件会非法操作的,按上述方式玩玩吧。
明白了,你就会玩,不明我也没办法。努力呀,大概在20来个CC,有些破解了,就根本不用修它,因为根本不会再走到那里!

你能从头看到了这行,说明你很有耐心,很适合这份干工作... 你将会得到的奖品是满心喜欢,Good Luck!

Written by askformore