已测环境 :
  XP SP2 ' SP3
  原版 OD + StrongOD 0.4.1.716

这个壳最近好像很夯. 最常见到的帖子就是 "无法下断点"
壳用的方法虽非首创, 但用得好杀伤力很大.
研究一个壳若 *无法下断点 的话, 只能在上面飞来飞去的,
这是不行的, 没办法研究的.

后面会提供一个附件(一个Crackme), 正常 Run 起会有 8 个 Thread.
Main Thread 不说, 其它全是 Anti 调试.

这时刚好可先确定你的 OD 不下任何断点时, 按 F9 能执行起来才行.
否则请先检查你的 OD.

原理可能你下面的内容边看就能边了解到了.

----
开始
----

用OD载入后要怎么弄呢? 首先我们在 KiUserExceptionDispatcher 的第 1 条
指令按 F2 设软断, 按 F9 Run

 第 1 次断下时, 此时 : [ESP+8]=80000003
   此时模块己 Shadow 进来, 且尚未建立 Anti 的 Thread

 第 2 次断下时, 此时 : [ESP+8]=80000004
   看 CPU 窗口, 记下 Dr0~3 四个值.
   看 Stack 窗口, 记下 [ESP+14] 值. 此样本为 42F765
   
 这 5 个值为这 Case 专用的.

OD 重新载入 ...
断'停在第 1 次 KiUserExceptionDispatcher , 不要乱动.
完成下面5项,就任你调试了.

(1)
 在内存里找 CreateThread 的 Shadow :
 了他. 请将第一条指令改成 ret 18, 如 :

代码:
shadow_CreateThread
00D1FB55   8BFF         mov   edi, edi      ;改成 ret 18
00D1FB57   55           push  ebp
00D1FB58   8BEC         mov   ebp, esp
00D1FB5A   FF75 1C      push  dword ptr [ebp+1C]
00D1FB5D   FF75 18      push  dword ptr [ebp+18]
00D1FB60   FF75 14      push  dword ptr [ebp+14]
00D1FB63   FF75 10      push  dword ptr [ebp+10]
00D1FB66   FF75 0C      push  dword ptr [ebp+C]
00D1FB69   FF75 08      push  dword ptr [ebp+8]
00D1FB6C   6A FF        push  -1
00D1FB6E   E8 D9FDFFFF  call  00D1F94C
00D1FB73   5D           pop   ebp
00D1FB74   C2 1800      ret   18
原因应该不用讲了吧. 那些反调试选项每打个勾就占一个 Thread.
我是看到 nevsayno 的贴图才想到 一个选项 一个 Thread 的, 借
他的图贴一下 :)





(2)
 在内存里(跟上面是同一段的)找 GetThreadContext 的 Shadow :
代码:
Shadow_GetThreadContext
00D488DD     8BFF            mov     edi, edi
00D488DF     55              push    ebp
00D488E0     8BEC            mov     ebp, esp
00D488E2     FF75 0C         push    dword ptr [ebp+C]
00D488E5     FF75 08         push    dword ptr [ebp+8]
00D488E8     FF15 EA0ED100   call    [D10EEA]
00D488EE     85C0            test    eax, eax
00D488F0     0F8C 57B60000   jl      00D53F4D
00D488F6     33C0            xor     eax, eax
00D488F8     40              inc     eax
00D488F9     5D              pop     ebp
00D488FA     C2 0800         ret     8      ;jmp 00E41F90
00D488FD     90              nop
00D488FE     90              nop
00D488FF     90              nop
00D48900     90              nop
00D48901     90              nop
上面的 ret 8 改成跳到没用之处, 并增写下列代码 :

代码:
00E41F90     50          push   eax
00E41F91     8B4424 0C   mov    eax, [esp+C]
00E41F95     8038 10     cmp    byte ptr [eax], 10
00E41F98     75 16       jnz    short 00E41FB0
00E41F9A     33D2        xor    edx, edx
00E41F9C     8950 04     mov    [eax+4], edx   ;clr Dr0~3
00E41F9F     8950 08     mov    [eax+8], edx
00E41FA2     8950 0C     mov    [eax+C], edx
00E41FA5     8950 10     mov    [eax+10], edx
00E41FA8     52          push   edx
00E41FA9     6A 04       push   4               ;Index
00E41FAB     E8 457C9C7B call   kernel32.TlsSetValue
00E41FB0     58          pop    eax
00E41FB1     C2 0800     ret    8
原因:
  壳总是会判断这 TlsValue 是否等于 Dr0+Dr1+Dr2+Dr3 之 Total 值
  我们在壳欲取得 Drx 的值时,将之清为 0,并设 TlsValue 为 0

  至于 SetTlsValue 的 Index 应为多少才对, 很多方法可以得知.
  例如: 断 Shadow 的 SetTlsValue
  我这里 XP SP2 用的 Index 是 4 , XP SP3 则是 6

注: 因为这样本只有 Anti Debugger 时会调用 Shadow_GetThreadContext
   所以若新代码你不想用串接的话,直接覆盖也行.



(3)
 在内存里找 SetThreadContext 的 Shadow :
  并将开头改为:
代码:
  mov     al, 1
  ret     8
原因:
  若不了这函数的话,到时可能我们自己调试用的硬断会被抢走.



(4)
 之前我们有记下一个值为 42F765, 其实这是 VM 的 ds:[imm] 指令 :

代码:
vm.ds:[imm]

0042F763    8B01      mov   eax, [ecx]      ;jmp 00534FC5
0042F765    8D1C33    lea   ebx, [ebx+esi]
0042F768  ^ 7E B9     jle   short 0042F723
0042F76A  ^ 7F CB     jg    short 0042F737
 我们得 Hook 它.跳到没用处并写下列代码 :
 这里的 4 个 cmp , 为一开头我们记录下来的那 Dr0~3

代码:
00534FC5    81F9 C4754000   cmp     ecx, 004075C4
00534FCB    74 18           je      short 00534FE5
00534FCD    81F9 49754000   cmp     ecx, 00407549
00534FD3    74 10           je      short 00534FE5
00534FD5    81F9 B4744000   cmp     ecx, 004074B4
00534FDB    74 08           je      short 00534FE5
00534FDD    81F9 AF744000   cmp     ecx, 004074AF
00534FE3    75 09           jnz     short 00534FEE
00534FE5    9C              pushfd                       ;/
00534FE6    66:810C24 0001  or      word ptr [esp], 100  ;手动产生 80000004 中断
00534FEC    9D              popfd                        ;\
00534FED    90              nop
00534FEE    8B01            mov     eax, [ecx]           ;补上原指令
00534FF0    8D1C33          lea     ebx, [ebx+esi]       ;补上原指令
00534FF3  ^ E9 70A7EFFF     jmp     0042F768             ;跳回

原因:
  壳总是会设那 4 个值到 Dr0~3, 并设 Dr7 为 33335555h
  意思是只要读取那 4 处, 就会产生 80000004 的例外,
  壳特意去读取时,若没发生 80000004 的话是不行的.
  这就像是壳自己给自己下硬断' 给自己调试一样

  当你 OD 设了断点断下来后,任何将控制权再交给 Target 的动作前,
  OD 都会用 User 设的值(没用到的则是零)重新设定到 Dr0~3 ,导致
  壳在该断的地方没发生中断,这就是很多人讲的:只要一断不管什么断
  ,就没办法正常 Run 下去了的原因.

  一开头被我们删掉的 7 个 Thread 里也充满了这些对 Drx 的占用.



(5)
 改 VM 的 rdtsc 指令

  vm.rdtsc 原样为 :

代码:
  rdtsc
  sub  ebp, 8
  mov  [ebp+0], edx
  mov  [ebp+4], eax
 中间当然被插入好多垃圾,我们主要是要让 eax = 0, 本样本如下 :

代码:
00437C98    8D2424  lea   esp, [esp]    ;改为xor eax,eax / nop
00437C9B    895500  mov   [ebp], edx
刚好可将 lea esp,[esp] 这垃圾指令改为   xor eax,eax / nop (因原指令占3字节)

原因:
  壳总是利用 rdtsc.eax 来乱数做内存校验
  我们有改了 ds:[imm], 而且我们可能日后会下一大堆软件断点(CC)
  改了后,他就只固定去校验第0小块.

引用:
[补充]
  若你认为 vm.rdtsc 不好找的话, 可用市面上任一款 fakerdtsc.sys
  但为避免被壳检测到你用这东西, 所以请找下列特微码 :

    00415E0A    9C               pushfd
    00415E0B    810C24 00010000  or      dword ptr [esp], 100
    00415E12    9D               popfd
    00415E13    0F31             rdtsc         <- nop 掉

  将这条 rdtsc 给 nop 掉即可

     下载处 http://www.pediy.com/tools/Debuggers.htm
完成上面5项,对壳里对软件里对云里雾里,就跟调试记事本一样了.
你可完全的分析此壳了.

不信你看! 试着在 401020 下硬件写入断点. 在断下几次后, 看到壳在填真正代码了, 如下 :

代码:
00401000  E8 FD FB 11 00 C3 90 90 90 90 90 90 90 90 90 90
00401010  B8 D8 21 40 00 C3 90 90 90 90 90 90 90 90 90 90
00401020  56 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
反汇编为:

代码:
00401000    E8 FDFB1100     call    00520C02
00401005    C3              ret
00401006    90              nop
00401007    90              nop
00401008    90              nop
00401009    90              nop
0040100A    90              nop
0040100B    90              nop
0040100C    90              nop
0040100D    90              nop
0040100E    90              nop
0040100F    90              nop
00401010    B8 D8214000     mov     eax, 004021D8
00401015    C3              ret
00401016    90              nop
这是平常看不到也来不到的地方喔.

最后同样的,让我们期待大牛的脱壳脚本吧.


注: 针对 "无法下断点" 这词 :
  若你当平常的壳在调试的话, 调试过程你会有二种现象 :
    1. 你下了断点, 也断了下来, 也能 F9 成功 Run 起.
       不要高兴, 这是因为壳尚未起动 Anti.
    2. 若壳的 Anti 起动了的话, 你的断点断了下来, 但你已无法正常执行了
       可能会得到 "内部错误" 之类的讯息.
    3. 若内存校验被检出的话,可能直接 Crash .

听说 Shielden 欲加壳得连网才能加,所以我也没用过.
手上就只有同学给我的这个样本(Crackme),虽然我已尽量外观一点分析,但可能
也有所漏的情况.所以...若有任何错误或其它情况,请跟帖指正.

一分钱一分贷, 若嫌麻烦...花钱买滴蜡吧. 

thx & 阿门!
上传的附件 Shielden2030.Sample.rar