Arm壳的 StolenCode ,很有规律,想试手编程,OD的纯脚本运行会慢得很惊人,至少在我的慢机很常见

我的 Dll Delphi源码 还没完成的。。。,只做了一部分,小测试过一下,不是很好


贴上来: 

先附用 OllyMachines 记录数据的脚本
// 一个字,“乱”
// Arm 的StolenCode 记录数据脚本
__asm
{
pushfd
pushad
push 40
push 1000
push 20000
push 0
call KERNEL32.VirtualAlloc
}

cmp eax, 0
je verr
mov reg11, eax   // dwOpLenTab 的值
mov reg15, eax
invoke logtext, "★★★★★ 成功申请下面的空间地址:"
invoke loglong, reg11
invoke GotoDumpAddr, reg11

__asm
{
popad
popfd
}

add reg15, 0x10000   // 划分一个空间给 记录 dwLogAddressTab 值的表
mov reg10, 0x587000  // StolenCode 节首地址 dwStolenCodeSection 的值
mov reg00, reg10

mov reg12, 0
mov reg13, 0
mov reg14, reg11
invoke GotoDumpAddr, reg11

loop:
cmp reg10, 0x596FC2  // 此处是比较 StolenCode 块的结束地址
je end

mov reg16, reg10
invoke ReadMemLong, reg16, 1
cmp reg00, 0xE9
jne skip
inc reg16
invoke ReadMemLong, reg16, 4
cmp reg00, 0
je skip
dec reg16
mov reg18, reg00
invoke WriteMemLong, reg15, reg16, 4
add reg15, 4
add reg16, 5
add reg16, reg18  // 取得返回地址

checking:
invoke GetPrevOpAddr, reg16, 1  // 逆向扫描返回地址
mov reg16, reg00
invoke ReadMemLong, reg16, 1
cmp reg00, 0xE9
jne checking                    // 直到找到JMP指令
invoke WriteMemLong, reg15, reg16, 4
add reg15, 4

skip:
invoke GetNextOpAddr, reg10, 1
mov reg12, reg00
sub reg12, reg10
mov reg10, reg00
invoke WriteMemLong, reg11, reg12, 1
inc reg11
inc reg13
jmp loop

end:
invoke LogText, "☆☆☆☆☆记录指令数量为:"
invoke LogLong, reg13 
invoke DumpMem, reg14, 0x20000, "OpLen_Tab.bin"
invoke msg, "Well Done!"
halt

verr:
__asm
{
popad
popfd
}
invoke msg, "发生一个申请内存的错误!"
halt





///////////////////////////////////////////////////////

library RestoreStolen;

uses
  SysUtils,
  Windows,
  Classes;
  
{$R *.RES}
// 小弟感觉这是自己真正的编程的头一次开始,所以写得很烂...
// 变量定义得比较奢侈,牛哥们可以指点指点..., 有值得优化的地方指点指点
// Nop 垃圾指令还在测试中,所以还缺一个移动还原动作的代码。。。
Type
  Tpackvar = record
      PatchAddr    :^Dword; // 这个正式还原时用,暂未用
      LenTab       :Dword;  // 指令长度表起始地址
      Sbegin       :Dword;  // 一个小的 StolenCode 块的起始地址
      Send         :Dword;  // 一个小的 StolenCode 块的结束地址
      pNextAddr    :^Dword; // 指向第 n 个块表的指针
      count        :Dword;  // 作临时计算地址过渡用
      len          :Byte;   // 保存取指令长度表一个索引指向的size
      abyte        :Byte;   // 临时用的字节保存变量
      aword        :Word;   // 作用同上(字),可能会用上
      adword       :Dword;  // 作用同上(双字),可能会用上
      pLen         :^Byte;  // 全局用的指令长度表指针变量
      pbyte        :^Byte;  // 单个 StolenCode 块的指针变量
      tbyte        :^Byte; // pbyte 某位置的临时保存
      cbyte        :^Byte; // pbyte 某位置的临时保存
      pword        :^Word; // 作保存,需要时取用
      tword        :^Word; // 作用同上
      cword        :^Word;
      pdword       :^Dword; // 作保存,需要时取用
      tdword       :^Dword; // 作用同上
      cdword       :^Dword;
      temp         :Pointer; // 保存指针变量,作取用
      i            : integer; // 这个没有用上,以后不知是否会用
  end;

procedure Checkdust2(myvar: Tpackvar);// 2字节的公用调用检测是否配对 的过程
begin
  myvar.tword  :=  Pointer(myvar.pLen) ; //取当前指令长度表指针
  myvar.tbyte  :=  Pointer(myvar.pLen) ;
  myvar.cword  :=  myvar.temp ;

  While Dword( myvar.cword ) <  myvar.Send  do
    begin
      inc (myvar.tbyte );
      myvar.abyte  :=  myvar.tbyte^ ;
      myvar.count  :=  Dword( myvar.cword ) + myvar.abyte  ;
      myvar.cword  :=  Pointer( myvar.count );
      if ( myvar.abyte =2 ) and ( myvar.pword^ = myvar.cword^ )then
        begin
          myvar.pword^  := $9090 ;
          myvar.cword^  := $9090 ;
          break;
        end;
    end;
end;

Function RestoreStolenCode( dwOpLenTab, dwLogAddressTab, dwStolenCodeSection: Dword ) : boolean ; stdcall ;
var
handle: Thandle;
myvar : Tpackvar;
flag  : boolean;

begin
flag   := false ;
Result := True ;

try

begin

// 下面初始化
myvar.pNextAddr   := Pointer( dwLogAddressTab ) ;
myvar.Sbegin     := dwStolenCodeSection ;
myvar.LenTab     := dwOpLenTab ;
myvar.count      := 0;
myvar.pLen       := Pointer( myvar.LenTab ) ;
 

// 大循环开始
{
While myvar.pLen^ <> 0 do  // 外循环,若中间只存在 Nop 指令的成对 push pop 处理
begin
myvar.Sbegin    := myvar.pNextAddr ;
myvar.tdword    := Pointer( myvar.patchaddr );
}

While myvar.pNextAddr^ <> 0 do  // 中循环,找出壳的某个 StolenCode 块的范围
begin
myvar.len     := myvar.pLen^;
myvar.pbyte   := Pointer( myvar.Sbegin );
myvar.Send    := myvar.pNextAddr^ ;    // 传送表项的块结束地址


While Dword( myvar.pbyte ) <  myvar.Send  do  // 内块循环:相邻的垃圾指令 Nop 掉
begin
myvar.Len     := myvar.pLen^ ;
myvar.temp    := myvar.pbyte ;
myvar.pword   := myvar.temp ;
myvar.pdword  := myvar.temp ;

Case myvar.len of
     1:
       begin
         if myvar.pbyte^ in [ $91..$97 ] then  //如果是32位寄存器 xchg  指令,就查找是否有成对,有则 Nop 掉
            begin
              myvar.tbyte := Pointer(myvar.pLen) ;        //取当前指令长度表指针
              myvar.cbyte := myvar.temp ;

              While Dword( myvar.cbyte ) < myvar.Send  do
                begin
                  inc ( myvar.tbyte );
                  myvar.abyte  :=  myvar.tbyte^ ;
                  myvar.count  :=  Dword( myvar.cbyte ) + myvar.abyte  ; //  下一个指令地址 = 本指令地址+ 指令长度
                  myvar.cbyte  :=  Pointer( myvar.count );
                  if ( myvar.abyte =1 ) and ( myvar.pbyte^ = myvar.cbyte^ )then
                     begin
                       myvar.pbyte^  := $90 ;
                       myvar.cbyte^  := $90 ;
                       break;
                     end;
                end;
            end;  // 32位寄存器 xchg  指令判断结束
            
         if myvar.pbyte^ in [ $50..$57 ] then  // 如果是相邻的Push Pop 32位寄存器指令,就 Nop 掉
            begin
              myvar.abyte := myvar.pbyte^;
              inc(myvar.pbyte);
              if (myvar.pbyte^ - 8) = myvar.abyte  then
                  myvar.pword^ := $9090 ;
            end;    // Push Pop  判断结束
       end;
       
     2:
       begin             // 两字节的垃圾代码有很多

         case  myvar.pbyte^ of

             $0F:          // 是否32位寄存器的 bswap 指令,是则查找它有否配对,有则 Nop
                 begin
                     inc( myvar.pbyte);
                     if myvar.pbyte^ in [$C8..$CF] then
                        CheckDust2(myvar);
                 end;

             $66:
                 begin
                     inc( myvar.pbyte);
                     if myvar.pbyte^ = $90 then  // 特殊情况的 Nop 指令
                        myvar.pword^ := $9090 ;
                     if myvar.pbyte^ in [$91..$97] then  // xchg 16位寄存器
                        CheckDust2(myvar);
                        
                 end;

$70..$7F,$EB,$E3:
                 begin     // 零距离的 Jmp 类指令
                     myvar.cbyte  :=  myvar.temp ;
                     inc( myvar.pbyte);
                     case myvar.pbyte^ of
                         0:
                           begin
                             myvar.pword^ := $9090 ;  // 不是则只 Nop 本条指令
                           end;
                         2: 
                           begin
                             inc( myvar.pbyte );
                             if myvar.pbyte^ = myvar.cbyte^ then //是否同类的垃圾Short jmp
                                myvar.pdword^ := $90909090 ;
                           end;
                 end;       // 零距离的 Jmp 类指令处理结束
                 
             $87:
                  begin
                     inc( myvar.pbyte);
                     
                     if myvar.pbyte^ in [$C0, $C9,$D2,$DB,$E4,$ED,$F6,$FF] then // xchg 相同寄存器 ecx..edi
                        myvar.pword^ := $9090
                     else
                     begin
                        if myvar.pbyte^ in [$C1..$C8,$CA..$CF,$D0..$DA,$DC..$DF,$E0..$E3,$E5..$EF,$F0..$F5,$F7..$FE] then 
                           CheckDust2(myvar);    // 检测是否有成对
                     end; 
                  end;

             $8B:
                 begin
                     inc( myvar.pbyte );
                     if myvar.pbyte^ in [$C0,$C9,$D2,$DB,$E4,$ED,$F6,$FF] then  // mov 同等32位寄存器,如:mov eax,eax
                        myvar.pword^ := $9090 ;
                 end;

             $F7:
                  begin
                     inc( myvar.pbyte );
                     if myvar.pbyte^ in [ $D0..$D7 ] then // not 32位寄存器,是否有成对
                        CheckDust2(myvar);
                  end;
          end;  // case of 两字节处理块结束
       end;              // 两字节处理 End
       
     3:             // 三字节的垃圾代码也有,这个会有很多
       begin
          case  myvar.pbyte^ of
           $66:
               begin
                 inc( myvar.pbyte );
                 if myvar.pbyte^ = $87 then
                   begin
                     inc( myvar.pbyte );
                     if myvar.pbyte^ in [ $F1..$F3,$F9..$FB ]then
                        begin
                          myvar.pword^ := $9090 ;
                          myvar.pbyte^ := $90 ;
                        end
                   end;
               end;
          $67:
              begin
              myvar.count :=  dword( myvar.pbyte ) ;
              inc( myvar.count ) ;
              myvar.pword := Pointer( myvar.count ) ;
              if myvar.pword^ = $E300 then
                 begin
                   myvar.pbyte^ := $90 ;
                   myvar.pword^ := $9090 ;
                 end;
              end;
          end;
       end;

  5:
  begin

    if myvar.pbyte^ = $0E9 then    //  是否绝对偏移跳转

      begin
        myvar.tbyte  := myvar.temp ;
        inc( myvar.tbyte );
        myvar.pdword := Pointer( myvar.tbyte );
        
        if myvar.pdword^ = 0 then    // 是否为垃圾跳转,是则填充nop
           begin
              myvar.pbyte^   := $90 ;
              myvar.pdword^  := $90909090 ;
           end;
      end;

  end;
end; // case of End


myvar.count  := Dword( myvar.temp ) + myvar.pLen^ ;
myvar.pbyte  := Pointer( myvar.count  ) ;  // 同步移动到下一条指令的地址
inc( myvar.pLen );                       // 指令长度表+1,指向下一条指令的长度

end; // While 内

inc( myvar.pLen ) ;
myvar.Sbegin := myvar.Send +5 ; 
inc( myvar.pNextAddr ) ;
inc( myvar.pNextAddr ) ;
end; // While 中

{
end; // While 外
}
flag := true;
end;

finally
  if not flag then
    begin
    handle := 0 ;
    MessageBoxA(handle, Pchar('可能发生访问异常错误,请重来确定参数可用再试!'), Pchar('异常错误:'), MB_OK);
    Result := false ;
    end;
end;

end;



exports 
    RestoreStolenCode ;

begin
end.
///////////////////////////////////////////


贴一下 Arm StolenCode的垃圾特征:

00587000     6A FF                push -1
00587002     66:96                xchg ax,si
00587004     0FC9                 bswap ecx
00587006     0FC9                 bswap ecx
00587008     66:96                xchg ax,si
0058700A     68 B2E45200          push 52E4B2                         ; 入口地址
0058700F   - E9 A1A0E7FF          jmp 004010B5                        ; SWFDECOM.004010B5
00587014     50                   push eax
00587015     64:8925 00000000     mov dword ptr fs:[0],esp
0058701C     51                   push ecx
0058701D     56                   push esi
0058701E     57                   push edi
0058701F     8B7C24 1C            mov edi,dword ptr ss:[esp+1C]
00587023     8BF1                 mov esi,ecx
00587025     87FE                 xchg esi,edi
00587027     87FE                 xchg esi,edi
00587029     8BCF                 mov ecx,edi
0058702B   - E9 92A0E7FF          jmp 004010C2                        ; SWFDECOM.004010C2
00587030     C74424 14 00000000   mov dword ptr ss:[esp+14],0
00587038     F7D1                 not ecx
0058703A     66:92                xchg ax,dx
0058703C     96                   xchg eax,esi
0058703D     96                   xchg eax,esi
0058703E     66:92                xchg ax,dx
00587040     87DB                 xchg ebx,ebx
00587042     F7D1                 not ecx
00587044     C707 08F25400        mov dword ptr ds:[edi],54F208
0058704A   - E9 8DA0E7FF          jmp 004010DC                        ; SWFDECOM.004010DC
0058704F     0FC8                 bswap eax
00587051     78 00                js short 00587053                   ; SWFDECOM.00587053
00587053     0FC8                 bswap eax
00587055     68 94000000          push 94
0058705A   - E9 8DA0E7FF          jmp 004010EC                        ; SWFDECOM.004010EC
0058705F     C64424 14 01         mov byte ptr ss:[esp+14],1
00587064   - E9 98A0E7FF          jmp 00401101                        ; SWFDECOM.00401101
00587069     C706 B8F25400        mov dword ptr ds:[esi],54F2B8
0058706F     89BE 90000000        mov dword ptr ds:[esi+90],edi
00587075   - E9 93A0E7FF          jmp 0040110D                        ; SWFDECOM.0040110D
0058707A     8977 50              mov dword ptr ds:[edi+50],esi
0058707D     8BC7                 mov eax,edi
0058707F     5F                   pop edi
00587080     50                   push eax
00587081     0FCF                 bswap edi
00587083     87FE                 xchg esi,edi
00587085     87FE                 xchg esi,edi
00587087     71 00                jno short 00587089                  ; SWFDECOM.00587089
00587089     0FCF                 bswap edi
0058708B     75 02                jnz short 0058708F                  ; SWFDECOM.0058708F
0058708D     75 41                jnz short 005870D0                  ; SWFDECOM.005870D0
0058708F     58                   pop eax
00587090     5E                   pop esi
00587091     64:890D 00000000     mov dword ptr fs:[0],ecx
00587098   - E9 84A0E7FF          jmp 00401121                        ; SWFDECOM.00401121
0058709D     8B08                 mov ecx,dword ptr ds:[eax]
0058709F     91                   xchg eax,ecx
005870A0     66:87F3              xchg bx,si
005870A3     7C 02                jl short 005870A7                   ; SWFDECOM.005870A7
005870A5     7C 0C                jl short 005870B3                   ; SWFDECOM.005870B3
005870A7     51                   push ecx
005870A8     8BFF                 mov edi,edi
005870AA     59                   pop ecx
005870AB     66:87F3              xchg bx,si
005870AE     91                   xchg eax,ecx
005870AF     8B11                 mov edx,dword ptr ds:[ecx]
005870B1     50                   push eax
005870B2   - E9 F2A1E7FF          jmp 004012A9                        ; SWFDECOM.004012A9
005870B7     8B01                 mov eax,dword ptr ds:[ecx]
005870B9     8B10                 mov edx,dword ptr ds:[eax]
005870BB     51                   push ecx
005870BC     8BC8                 mov ecx,eax
005870BE   - E9 01A2E7FF          jmp 004012C4                        ; SWFDECOM.004012C4
005870C3     6A FF                push -1
005870C5     66:87D1              xchg cx,dx
005870C8     8BC9                 mov ecx,ecx
005870CA     73 02                jnb short 005870CE                  ; SWFDECOM.005870CE
005870CC     73 6C                jnb short 0058713A                  ; SWFDECOM.0058713A
005870CE     66:87D1              xchg cx,dx
005870D1     68 08E85200          push 52E808
005870D6   - E9 FAA1E7FF          jmp 004012D5                        ; SWFDECOM.004012D5
005870DB     50                   push eax
005870DC     64:8925 00000000     mov dword ptr fs:[0],esp
005870E3     51                   push ecx
005870E4     56                   push esi
005870E5     8BF1                 mov esi,ecx
005870E7     66:96                xchg ax,si
005870E9     F7D3                 not ebx
005870EB     66:90                nop
005870ED     F7D3                 not ebx
005870EF     66:96                xchg ax,si
005870F1     57                   push edi
005870F2     897424 08            mov dword ptr ss:[esp+8],esi
005870F6   - E9 E7A1E7FF          jmp 004012E2                        ; SWFDECOM.004012E2

// 当然还有,不全贴了.. 

  • 标 题: Re: 一个壳的Stolen还原判断编写(想法还没完善),望指点【讨论】
  • 作 者:askformore
  • 时 间:2005-06-10 11:23

引用:
最初由 askformore 发布
Arm壳的 StolenCode ,很有规律,想试手编程,OD的纯脚本运行会慢得很惊人,至少在我的慢机很常见

我的 Dll Delphi源码 还没完成的。。。,只做了一部分,小测试过一下,不是很好


........ 



加精害我,上面的Delphi源码丢了个 case end,应该是亡中贴错了Project的那个草稿,现在打包个缺“回归”的代码,呵呵应该不难写,因为该是垃圾的都Nop去了 

请检验一下有问题不,如果没问题我就打算加“回归代码”
用法在被OD调试的程序先运行脚本,找个小空间call dll完成清Dust
格式不用多说了吧:
push dwStolenCodeSection
push dwLogAddressTab
push dwOpLenTab
call dll
test eax,eax
is true ?

附件:src.rar