首页
社区
课程
招聘
[原创]菜鸟脱壳---Themida
发表于: 2014-9-29 22:49 24507

[原创]菜鸟脱壳---Themida

2014-9-29 22:49
24507

【文章标题】:菜鸟脱壳---Themida
【文章作者】: xross
【下载地址】: TMKIHD.rar

第一次脱壳成功,还是来分享一下。
前几天看大牛脱Themida的壳,很有启发。
我果然是菜鸟,几天才脱壳成功,看了还是无法找出主要算法,主要它有跳转表,不知怎么办,。
也没有必要找出,只要找到OEP,IAT,API就可以了,果然我还是菜鸟。
先用PEID查壳,查不出来,但估计是Themida。
将程序运行一次,然后在CE中搜索4D5A,发现两个可疑地址,
在OD中,在10000000处查看PE文件头,它是DLL.查看窗口句柄,发现100012BC。OD中搜索"BC 12 00 10",100010FB.
在100012BA下断,断后,F8到返回。

查看ebp,跳到10002BD9附近看看,
在10002BCB改为:jmp 10002BD9,跳过CDCheck,

然后在代码设访问断点,断在2362261。删除内存断点,运行到下一指令,再在代码段设断,
断在
20C901F:
020C901F    8F02            pop dword ptr ds:[edx]                                        

  ; 056B0000
020C9021  ^ E9 7DF6FFFF     jmp RealLive.020C86A3

看看edx=5F20A8,猜想是对IAT的写入。
在GetCommandLineA处下硬件访问断点,返回到5CCA3A。
往上翻,到5CC928。堆栈中没有任何信息,猜想是jmp过来的。
搜索"jmp 5CC928",
找到:
005CCB08    E8 61520000     call RealLive.005D1D6E   ;可能是OEP
005CCB0D  ^ E9 16FEFFFF     jmp RealLive.005CC928

在刚才的IAT处查看,可以确定IAT的范围为:
5F2000~5F2590

在kernel32的EAT下内存访问断点,
为了方便,直接写脚本:
bphwcall
bphws 10002BCB
esto
bphwc
mov [10002BCB],#EB0C#
bphws  5CCB08,"x"    //OEP设硬件执行
bpcnd 20C901F,"edx>=5F20A8&&edx<5F2590"
esto
gma "kernel32",EDATATABLE
bprm $RESULT,A9B1

断在23712C6:
023712C6    66:AD           lods word ptr ds:[esi]
023712C8    60              pushad
023712C9    60              pushad
023712CA    8BCE            mov ecx,esi
023712CC    E9 10000000     jmp RealLive.023712E1
023712D1    AC              lods byte ptr ds:[esi]
023712D2    54              push esp
023712D3    90              nop
023712D4    E5 31           in eax,31
023712D6    0BDF            or ebx,edi
023712D8    8F              ???                                      ; 未知命令

Step Into下去,
023716DE    015A 4F         add dword ptr ds:[edx+4F],ebx
023716E1    F5              cmc
023716E2    2130            and dword ptr ds:[eax],esi
023716E4    FFD3            call ebx
023716E6    60              pushad      //此时eax为API,之前有出现过字符串
023716E7    81DB D595871B   sbb ebx,1B8795D5
023716ED    E9 06000000     jmp RealLive.023716F8
023716F2    BE 366874F3     mov esi,F3746836

尝试修复IAT:
var apiadd
var iatadd
bphwcall
bphws 10002BCB
esto
bphwc
mov [10002BCB],#EB0C#
bphws  5CCB08,"x"
bpcnd 20C9021,"edx>=5F20A8&&edx<5F2590"
bphws 23716E6,"x"

api:
esto
cmp eip,23716E6
jne fixiat
mov apiadd,eax
jmp api

fixiat:
cmp eip,20C9021
jne exit
cmp edx,63CA0000
jge api
mov [edx],apiadd
jmp api

exit:
bc

运行中发现还有无名地址5F20E4,下硬件写入断点。
bphwcall
bphws 10002BCB
esto
bphwc
mov [10002BCB],#EB0C#
bphws  5CCB08,"x"
bpcnd 20C9021,"edx>=5F20A8&&edx<5F2590"
esto
bc 20C9021
bphws 5F20E4,"w"
esto
断在2373D47:
02373D42    890C24          mov dword ptr ss:[esp],ecx
02373D45    8F00            pop dword ptr ds:[eax]
02373D47    60              pushad

重写修复IAT的脚本:
var apiadd
var iatadd
bphwcall
bphws 10002BCB
esto
bphwc
mov [10002BCB],#EB0C#
bphws  5CCB08,"x"
bpcnd 20C9021,"edx>=5F2000&&edx<5F25F0"
bphws 2373D47,"x"
bphws 23716E6,"x"

api:
esto
cmp eip,23716E6
jne fixiat1
mov apiadd,eax
jmp api

fixiat1:
cmp eip,20C9021
jne fixiat2
cmp [edx],63AC0000
jge api
mov [edx],apiadd
jmp api

fixiat2:
cmp eip,2373D47
jne exit
cmp [eax],63AC0000
jge api
mov [eax],apiadd
jmp api

exit:
bc

执行完后发现IAT确实都修复了,但无法用RecImport修复,原因未知,有谁知道吗。
看来只能手动修复了,
先确定各模块名的地址
5F2000:advapi32
5F2030:comctl32
5F203C:dsound
5F2044:gdi32
5F20A8:kernel32
5F22B8:oleaut32
5F22E8:shell32
5F22FC:user32
5F24D4:version
5F24E4:winmm
5F2554:ole32
再写个输出文件的脚本:
var addr
var str
mov addr,5F2000

mov str,0

advapi32:
wrta "C:\\qw.txt",str,0
cmp addr,5F2000
jne comctl32
mov str,"advapi32.dll"
add str,0
jmp loop

comctl32:
cmp addr,5F2030
jne dsound
mov str,"comctl32.dll"
add str,0
jmp loop

dsound:
cmp addr,5F203C
jne gdi32
mov str,"dsound.dll"
add str,0
jmp loop

gdi32:
cmp addr,5F2044
jne kernel32
mov str,"gdi32.dll"
add str,0
jmp loop

kernel32:
cmp addr,5F20A8
jne oleaut32
mov str,"kernel32.dll"
add str,0
jmp loop

oleaut32:
cmp addr,5F22B8
jne shell32
mov str,"oleaut32.dll"
add str,0
jmp loop

shell32:
cmp addr,5F22E8
jne user32
mov str,"shell32.dll"
add str,0
jmp loop

user32:
cmp addr,5F22FC
jne version
mov str,"user32.dll"
add str,0
jmp loop

version:
cmp addr,5F24D4
jne winmm
mov str,"version.dll"
add str,0
jmp loop

winmm:
cmp addr,5F24E4
jne ole32
mov str,"winmm.dll"
add str,0
jmp loop

ole32:
cmp addr,5F2554
jne exit
mov str,"ole32.dll"
add str,0

loop:
cmp addr,5F2590
jge exit
cmp [addr],0
add addr,4
je advapi32
gn [addr-4]
add str,11  //hint
add str,$RESULT_2
add str,0
jmp loop
exit:
此文件需要将30替换为0,31替换为1,ntdll的函数改为kernel32,写到227B0F0。

再次重写脚本:
bphwcall
bphws 10002BCB
esto
bphwc
mov [10002BCB],#EB0C#
bphws  5CCB08,"x"
esto

运行后,记录下伪IAT的值(我是菜鸟,不知如何用脚本修复nop地址,于是读文件修复nop地址)。

好,OD的工作完成了,接着就是最接近汇编的高级语言登场了。。
然后先是修复IAT,
  HANDLE hFile=CreateFile("RealLive_fixed.exe",GENERIC_READ|GENERIC_WRITE,0,NULL,
    OPEN_EXISTING,0,NULL);
  HANDLE hFileMap=CreateFileMapping(hFile,NULL,PAGE_READWRITE,
    0,0,NULL);
  BYTE *p=(BYTE*)MapViewOfFile(hFileMap,FILE_MAP_READ|FILE_MAP_WRITE,0,
    0,0);
  CloseHandle(hFileMap);
        CloseHandle(hFile);
  BYTE *pBeg=p;
  int arr[]=
  {
    0X1F2000,0X1F2030,0X1F203C,0X1F2044,
    0X1F20A8,0X1F22B8,0x1F22E8,0X1F22FC,
    0X1F24D4,0X1F24E4,0X1F2554
  };
  char *szModule[11]=
  {
    "advapi32.dll","comctl32.dll","dsound.dll","gdi32.dll",
    "kernel32.dll","oleaut32.dll","shell32.dll","user32.dll",
    "version.dll","winmm.dll","ole32.dll"
  };
  int i;
  IMAGE_IMPORT_DESCRIPTOR* pIAT=(IMAGE_IMPORT_DESCRIPTOR*)(pBeg+0X227B000);
  BYTE* pszModule=(BYTE*)(p+0X227b0f0);
  for (i=0;i<11;i++)
  {
    pIAT->OriginalFirstThunk=pIAT->TimeDateStamp=pIAT->ForwarderChain=0;
    while(1)
    {
      if(strstr((const char*)pszModule,szModule[i])!=NULL)
        break;
    }
    pIAT->Name=pszModule-pBeg;
    pIAT->FirstThunk=arr[i];
    
    DWORD *pThunk=(DWORD*)(pIAT->FirstThunk+pBeg);
    while(*pszModule!=0)
    {
      while(*pszModule!=0)pszModule++;
      pszModule++;
      if(*pszModule!=0)
        *pThunk=pszModule-pBeg;
      pThunk++;
    }
    pszModule++;
    pIAT++;
  }
  UnmapViewOfFile(pBeg);
再修复nop地址,
  DWORD iatapi[11][256]; //伪API地址
  DWORD iatadd[11]=
  {
    0X5F2000,0X5F2030,0X5F203C,0X5F2044,
    0X5F20A8,0X5F22B8,0X5F22E8,0X5F22FC,
    0X5F24D4,0X5F24E4,0X5F2554
  };
  int i,j;
  BYTE* pFile,*pBase;
  BYTE *nopadd;     //需要修复的地址
  DWORD calladd;     //call的地址
  //坏习惯
  HANDLE hFile=CreateFile("RealLive_fixed.exe",GENERIC_READ|

GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
  HANDLE hFileMap=CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,NULL);
  pFile=(BYTE*)MapViewOfFile(hFileMap,FILE_MAP_COPY|FILE_MAP_WRITE,0,0,0);
  pBase=pFile;
  pFile+=0X1000;
  BOOL bCall;   //是call还是jmp
  
  //偷懒的做法
  HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,7968);
  for (i=0;i<11;i++)
  {
    j=0;
    do 
    {
      ReadProcessMemory(hProcess,(LPVOID)(iatadd[i]+4*j),&iatapi[i]

[j],4,NULL);
      j++;
    } while (iatapi[i][j]!=0);
  }
  CloseHandle(hProcess);
  while(pFile<pBase+0x200000)
  {
    nopadd=NULL;
    //pFile指向0X90(nop)
    while(*pFile!=0X90)pFile++;
    // call 地址 nop型
    if(pFile[-5]==0XE8||pFile[-5]==0XE9)
    {
      bCall=(pFile[-5]==0XE8);
      nopadd=pFile-5;
      calladd=*(DWORD*)(nopadd+1)+5+(nopadd-pBase+0X400000);
    }
    //nop call地址 型
    else if(pFile[1]==0XE8||pFile[1]==0XE9)
    {
      bCall=(pFile[1]==0XE8);
      nopadd=pFile;
      calladd=*(DWORD*)(nopadd+2)+5+(nopadd+1-pBase+0X400000);
    }
    if(nopadd!=NULL)
    {
      for (i=0;i<11;i++)
      {
        j=0;
        //在IAT中查找call的地址
        while(iatapi[i][j]!=0&&calladd!=iatapi[i][j])
          j++;
        if(iatapi[i][j]!=0)break;
      }
      if(i!=11)
      {
        *(WORD*)nopadd=bCall==1?0X15FF:0X25FF;
        *(DWORD*)(nopadd+2)=iatadd[i]+4*j;
        
      }
    }
    pFile++;
  }
  CloseHandle(hFileMap);
  CloseHandle(hFile);
  UnmapViewOfFile(pBase);
最后想问一下,ODScript中只能下硬件访问一个字节,有谁知道能下4个字节的断点。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (13)
雪    币: 13209
活跃值: (4271)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
OD的脚本编辑器说明硬断只支持一个字节。。。
2014-9-30 01:22
0
雪    币: 459
活跃值: (398)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
3
收藏了,慢慢看,谢谢楼主
2014-9-30 09:05
0
雪    币: 2401
活跃值: (1402)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
想要下4个字节的断点,可以用 BPRM。
2014-9-30 11:41
0
雪    币: 3277
活跃值: (1992)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
现在的大牛都喜欢装菜。

这贴子精华节奏。
2014-9-30 12:08
0
雪    币: 16412
活跃值: (1625)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
能搞---Themida 的 就是高手。
2014-9-30 20:03
0
雪    币: 33
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
7
高手 高手 高高手
2014-10-1 10:49
0
雪    币: 100
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
虽然我菜得不能再菜,但是也想慢慢学加密解密!
2014-10-23 09:14
0
雪    币: 230
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
确实啊!!已经很了不起了!
2014-10-23 21:49
0
雪    币: 4928
活跃值: (967)
能力值: ( LV9,RANK:175 )
在线值:
发帖
回帖
粉丝
10
膜拜好了!!
2014-10-23 22:51
0
雪    币: 16
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
楼主确实已经很不错了,能脱就行
2014-11-1 22:20
0
雪    币: 55
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
在我眼中,楼主已是高手啊
2015-2-7 12:32
0
雪    币: 198
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
特么的你这也算菜鸟?你是装菜的吧?
2015-2-7 21:55
0
雪    币: 4704
活跃值: (4240)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
在OD中,在10000000处查看PE文件头,它是DLL.查看窗口句柄,发现100012BC。OD中搜索"BC 12 00 10",100010FB.
这句没有理解,OD怎么查看窗口句柄???不是要运行程序才能吗。
2018-11-9 17:12
0
游客
登录 | 注册 方可回帖
返回
//