首页
社区
课程
招聘
[原创]写壳的一些成果[TLS完美处理,压缩功能实现,AntiDump-过LordPE,调用sprintf?,IAT重定向]
发表于: 2017-9-26 22:34 19385

[原创]写壳的一些成果[TLS完美处理,压缩功能实现,AntiDump-过LordPE,调用sprintf?,IAT重定向]

2017-9-26 22:34
19385

如果阅读本文,发现一些框架性的东西难以理解,可以先阅读这两篇文章

https://bbs.pediy.com/thread-206804.htm

https://bbs.pediy.com/thread-206873.htm

本来想自己写个系列的,结果已经有前辈写好了,我就分享一下自己独有的吧

项目有加壳和解壳两部分,这两个部分通过结构体PACKINFOPackInfo来连接,具体实现是PACKINFOg_PackInfo定义在解壳的项目(dll项目,名为Stub)中,加壳部分通过

(PPACKINFO)GetProcAddress(hStub ,"g_PackInfo")来操作这个结构体.

这样就能将原PE文件的信息存入到解壳部分,减轻解壳部分的信息获取压力,在某些置0操作后,解壳部分依然能获取到信息.而且还可以获取到具体的加壳选项信息.下面将这个结构体称为PackInfo

加壳部分最后将解壳部分Stub.dll的某些区段添加到原PE文件上

一开始处理TLS部分不知道怎么弄,看了看别人的帖子,结果豁然开朗,不就是循环调用TLS回调函数嘛.然后给自己来了个”高难度”的进行加壳,结果就出错了,果然是纸上得来终觉浅

测试程序是这样的:TLS回调函数首先使用TLS全局变量弹出对话框,接着主程序使用TLS全局变量弹出对话框,接着创建线程,线程中调用了MessageBox,其使用了TLS全局变量

// TLS测试程序

#include"stdafx.h"

#include"windows.h"

__declspec(thread)charg_tlsNum[10]="ffff";

voidNTAPIt_TlsCallBack_A(PVOIDDllHandle,DWORDReason,PVOIDRed)

{

   if(DLL_PROCESS_ATTACH==Reason)

   {

       MessageBoxA(0 , g_tlsNum , 0 , 0);

   }

}

#pragmadata_seg(".CRT$XLB")

PIMAGE_TLS_CALLBACKp_thread_callback[]={

   t_TlsCallBack_A,

   NULL

};

#pragmadata_seg()

DWORDWINAPIMyThreadProc(

   _In_LPVOIDlpParameter

)

{

   MessageBoxA(0 , g_tlsNum , 0 , 0);

   return0;

}

intmain()

{

   MessageBoxA(0 , g_tlsNum , 0 , 1);

   CreateThread(NULL, 0, MyThreadProc,NULL, 0,NULL);

   system("pause");

   return0;

}

        结果能弹出对话框,可是MessageBox上的字符是随机的.

可以看到,这里的数据”ffff”和数据块开始和结束在汇编层面是看不出有什么关系的,后来查阅更多的资料得知,当线程创建时,系统会从数据块开始VA和结束VA这一块空间中读取内容保存到pMem中,pMem地址存在fs:[0x2c]指向的指针数组中的一个,而索引变量则是用于找到pMem.也就是说如果每创建一个线程,就会从数据块开始VA和结束VA读取一次,保存到当前线程的空间,内存地址保存到fs:[0x2c]指向的指针数组中,通过索引变量找到数据地址.

那么,如果一开始没能让系统正确读取到你的TLS数据块,主线程之后就在也不能正确使用TLS全局变量(如果再创建线程,并且TLS数据块已经恢复好了,依然可以正确使用TLS全局变量,此为测试所得,也符合各资料所言),所以必须一开始就构建好TLS.

接下来,怎么构建呢?

逐个分析:

首先看TLS表存在哪?



是的,它存在rdata段,那么考虑压缩功能,在解压之前必定是不能正确读取了.

处理方法:Stub工程中添加一个TLS全局变量,并做做样子使用一下

_declspec(thread)intg_num;    Stub初始化函数中:  g_num;//使用tls变量,产生tls节表,

这里还有一个前置条件,

#pragmacomment(linker,"/merge:.data=.text")

#pragmacomment(linker,"/merge:.rdata=.text")

#pragmacomment(linker,"/section:.text,RWE")

也就是Stub.dll中.rdata段被合到.text段,这样只要拷贝了.text段(也是其他主要功能的载体)就可以使用其就可以其提供的tls表.

那么,首先就需要将原pe文件的目录表第10项指向Stub的这个tls表(由于会添加Stub.dll的text段作为解壳段,所以地址自然会有转换关系).

还需要将Stub的tls表中的值更改,接下来看TLS表中重要的值,


第一项和第二项其实就是代表TLS区段(注意这里是区段),所以处理是:TLS区段不能更改,原TLS表中的值设置到Stub的Tls表中

第三项:索引,有些文件存在.data段,有的文件中找不到VA对应的文件偏移,总之反正不在TLS表,也就是说会被压缩或被其他的处理,所以就在解析原pe文件的时候把它获取出来保存到信息结构体PackInfo中,这里取变量名为TlsIndex,将Stub的TLS表中索引地址指向变量TlsIndex,当然注意转化为VA

//如果在文件中找不到VA对应的内容,就说明会初始化为0,如果找得到,就读取其在文件中的内容

//获取tlsIndex的Offset

       DWORDindexOffset = RvaToOffset(g_lpTlsDir->AddressOfIndex - dwImageBase);

       //读取设置tlsIndex的值

       pPackInfo->TlsIndex = 0;//index一般默认值为0

       if(indexOffset != -1)

       {

           pPackInfo->TlsIndex = *(DWORD*)(indexOffset + m_pNewBuf);

       }

第四项:回调表VA,这个首先将Stub的TLS表的这一项设置为0,在解压缩等操作完成之后设置回去,然后手动调用

void CallTls()

{

   IMAGE_DOS_HEADER* lpDosHeader = (IMAGE_DOS_HEADER*)g_dwImageBase;

   IMAGE_NT_HEADERS* lpNtHeader = (IMAGE_NT_HEADERS*)(lpDosHeader->e_lfanew + g_dwImageBase);

   //如果tls可用,调用tls

   if(g_PackInfo.bIsTlsUseful == TRUE)

   {

       //将tls回调函数表指针设置回去

       PIMAGE_TLS_DIRECTORY pTlsDir =

          (PIMAGE_TLS_DIRECTORY)(lpNtHeader->OptionalHeader.DataDirectory[ 9 ].VirtualAddress + g_dwImageBase);

       pTlsDir->AddressOfCallBacks = g_PackInfo.TlsCallbackFuncRva;

      //手动调用TLS

       PIMAGE_TLS_CALLBACK* lptlsFun =

           (PIMAGE_TLS_CALLBACK*)(g_PackInfo.TlsCallbackFuncRva - lpNtHeader->OptionalHeader.ImageBase + g_dwImageBase);

       while((*lptlsFun) != NULL)

       {

           (*lptlsFun)((PVOID)g_dwImageBase , DLL_PROCESS_ATTACH , NULL);

           lptlsFun++;

       }

   }

}

这样关于TLS相关的问题就可以完美解决了

一开始实现压缩功能的时候虽然有思路,但暗暗感觉这背后处理的定是极其复杂.在看雪上搜索到了几篇文章

https://bbs.pediy.com/thread-131361.htm

https://bbs.pediy.com/thread-161315.htm

https://bbs.pediy.com/thread-145947.htm系列

扒下来apilib的使用代码后尝试按照自己的思路去写.

        考虑到对TLS全局变量的引用和程序启动是对资源段的使用,不压缩tls和rsrc段.

其中关于tls段的定位需要参考tls表中的数据起始位置StartAddressOfRawData或终止位置,

rsrc段参考目录表第三项.

//获得tls表指针

PIMAGE_TLS_DIRECTORY32g_lpTlsDir =(PIMAGE_TLS_DIRECTORY32)(RvaToOffset(m_pNt->OptionalHeader.DataDirectory[9].VirtualAddress)+ m_pNewBuf);

//获得tls数据起始rva ,用于判断tls区段位置

m_pTlsDataRva

= g_lpTlsDir->StartAddressOfRawData - m_pNt->OptionalHeader.ImageBase;

//用于判断资源段rva

m_pResRva = m_pNt->OptionalHeader.DataDirectory[2].VirtualAddress;

        接着是我压缩过程中对这些区段进行的处理,

首先遍历区段,在此过程中:

①  获取tls和rsrc分别保存到buf中,并且做好标记;②获取其余要压缩的区段也保存到一个CompressBuf中,同时将这些区段的文件中大小SizeofRawData以及前后顺序index保存到交互结构体PackInfo,便于解压缩使用,也就是DWORDPackInfomation[50][2];//压缩区段中每个区段的index和大小

接着需要处理CompressBuf了,压缩代码是

PCHARCPe::Compress(PVOIDpSource,longlInLength,OUTlong&lOutLenght)

{

   //packed保存压缩数据的空间,workmem为完成压缩需要使用的空间

   PCHARpacked , workmem;

   if((packed =(PCHAR)malloc(aP_max_packed_size(lInLength)))==NULL||

       (workmem =(PCHAR)malloc(aP_workmem_size(lInLength)))==NULL)

   {

       returnNULL;

   }

   //调用aP_pack压缩函数

   lOutLenght= aPsafe_pack(pSource, packed ,lInLength, workmem ,NULL,NULL);

   if(lOutLenght==APLIB_ERROR)

   {

       returnNULL;

   }

   if(NULL!= workmem)

   {

       free(workmem);

       workmem =NULL;

   }

   returnpacked;//返回保存地址

}

再接着,就是再造PE文件了,首先将Pe头复制到新的内存中,压缩区段的区段头的文件偏移和大小置为0,但是Rva和内存大小不动,这样起到占位的作用.(主要是之前懒得保存压缩区段总内存大小,并且还要专门创建一个对应的占位区段,不过这种也需要相应的处理,就是如果不加长pe头,后面再添加区段的时候,新添加的区段头可能会越过文件头范围).接着就是按照之前做的关于tls和rsrc的标记,将tls段和rsrc段按顺序原封不动复制到Pe头后面中,接着将CompressBuf添加到新区段.这样就完成了压缩部分功能.

解壳时,首先进行将压缩区段解压缩到DecompressBuf,根据PackInfo结构体中的压缩区段d的文件偏移大小和顺序,将其中的信息分别填到对应的区段即可

voidDecompress()

{

   // 1.获取节区头首地址

   PIMAGE_DOS_HEADERpDosHeader =(PIMAGE_DOS_HEADER)g_dwImageBase;

   PIMAGE_NT_HEADERSpNtHeader =(PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + g_dwImageBase);

   PIMAGE_SECTION_HEADERpSecHeader =IMAGE_FIRST_SECTION(pNtHeader);

   // 2.解压压缩区段

   PCHARlpPacked =((PCHAR)g_dwImageBase + g_PackInfo.packSectionRva);//内存地址

   DWORDdwPackedSize = aPsafe_get_orig_size(lpPacked);//获取解压后的大小

   PCHARlpBuffer =(PCHAR)g_VirtualAlloc(NULL, dwPackedSize ,MEM_COMMIT,PAGE_EXECUTE_READWRITE);//申请内存

   aPsafe_depack(lpPacked , g_PackInfo.packSectionSize , lpBuffer , dwPackedSize);//解压

                                                                                // 3.将各区段还原回去

   DWORDoffset = 0;

   for(inti = 0; i < g_PackInfo.PackSectionNumber; i++)

   {

       //区段的标号

       intindex = g_PackInfo.PackInfomation[i][0];

       //这个区段的SizeOfRawData

       intsize = g_PackInfo.PackInfomation[i][1];

       PCHARdestionVA =(PCHAR)g_dwImageBase + pSecHeader[index].VirtualAddress;

       PCHARsrcVA = lpBuffer + offset;

       memcpy_s(destionVA , size , srcVA , size);

       offset += size;


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-4-12 10:11 被树梢之上编辑 ,原因:
上传的附件:
收藏
免费 2
支持
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  cvcvxk   +1.00 2017/09/26
最新回复 (27)
雪    币: 4889
活跃值: (2275)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享。
2017-9-26 22:50
0
雪    币: 7006
活跃值: (4217)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2017-9-26 22:55
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
4
收藏了。1块送上
2017-9-26 22:58
0
雪    币: 545
活跃值: (167)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
5
cvcvxk 收藏了。1块送上
3Q大佬
2017-9-26 23:00
0
雪    币: 7885
活跃值: (2285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享  应该加个赞的功能  没钱赏
2017-9-27 08:41
0
雪    币: 6566
活跃值: (4526)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
7
好东西,感谢分享
2017-9-27 09:27
0
雪    币: 12332
活跃值: (5103)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8

看中楼主地OD鸟,肿么办
2017-9-27 09:37
0
雪    币: 202
活跃值: (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
牛逼,对于我们这些连门都没有摸到的新手来说,楼主太强大了
2017-9-27 09:53
0
雪    币: 274
活跃值: (87)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mark  多谢,学习了
2017-9-27 09:59
0
雪    币: 216
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
赞一个  感谢分享
2017-9-28 12:59
0
雪    币: 6566
活跃值: (4526)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
12
方便传一个编译好的吗,用vs2010dll部分错误有点多
2017-9-28 15:38
0
雪    币: 8901
活跃值: (4213)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
看起来很不错的!
2017-9-28 17:36
0
雪    币: 9793
活跃值: (2186)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
xie风腾 [em_13] 看中楼主地OD鸟,肿么办
估计得去读个15pb才行吧,这是专用的。
2017-9-29 16:12
0
雪    币: 545
活跃值: (167)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
15
pxhb 方便传一个编译好的吗,用vs2010dll部分错误有点多
转2015吧,我编译好了,你又不能调
2017-9-29 18:12
0
雪    币: 1
活跃值: (152)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
优秀文章
2017-10-3 19:56
0
雪    币: 6818
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
不错!!!!
2017-10-5 20:32
0
雪    币: 74
活跃值: (748)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
很好,学习一下
2017-10-9 17:11
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
很好,学习一下
2017-10-10 02:16
0
雪    币: 135
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
很好,学习一下
2017-10-10 02:37
0
雪    币: 123
活跃值: (326)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
感谢分享。
2017-10-12 08:35
0
雪    币: 286
活跃值: (67)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
xjj
22
mark一下,感谢分享
2017-10-12 09:14
0
雪    币: 861
活跃值: (683)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
23
感谢,目测是学长?
2017-12-14 14:14
0
雪    币: 790
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
好吧,发现是自己的错误,debug正常,release的要改下设置
2018-1-26 20:22
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
感谢分享,楼主有没有一些写dll壳的思路呢?
2018-5-4 17:16
0
游客
登录 | 注册 方可回帖
返回
//