使用免费工具进行逆向和利用:第13部分

admin 2022年4月15日10:27:57使用免费工具进行逆向和利用:第13部分已关闭评论50 views字数 4580阅读15分16秒阅读模式

使用免费工具进行逆向和利用:第13部分

原作者:Ricardo Narvaja

翻译作者:梦幻的彼岸

更新日期:2022年1月21日

64位练习的解决方案

今天我开始了第13部分,添加了shellcode,分析并调整了一个64位的解决方案。

这个shellcode不是我的,我打算解释一下,但它是很公开的,它适合于本案例。

完整解决方案脚本

以下是运行NOTEPAD的完整解决方案,只需稍作更改。

让我们解释一下它的工作原理:

使用免费工具进行逆向和利用:第13部分

在这里,我们看到了迄今为止存在的部分解决方案的补充部分。

上面是带有解析器的shellcode,我们将在后面解释。

有一个gadget可以改变

rop+=struct.pack("<Q",0x1400060b7)# ADD RAX, 0x20 # CHANGED to have more space

这个gadget在跳转运行前给RAX增加了0x28,我把它改成了一个类似的gadget,但增加了0x20,以免浪费空间,因为空间很小。

请记住,memcpy不会将我们发送的所有内容复制到VirtualAlloc堆栈中的保留空间。

使用免费工具进行逆向和利用:第13部分

我们看到它只分配和复制了0x64字节,所以最好是避免浪费空间。

我们看到一个由我制作的代码,memmove将复制在堆中创建的保留区中,它将为执行最终的shellcode准备一切,我们将在执行时看到它。

而shellcode在堆栈中的ROP下面没有执行权限,你能告诉我为什么不把shellcode放在堆里,而直接把那段代码放在堆里执行。

答案是,堆中的空间不适合,我们已经看到它只保留0x64字节,最重要的是,我们跳过时丢失了前0x20字节,剩下的0x44字节不属于这个小空间。

让我们运行它并解释一下。

我运行脚本,它在我放置的断点处停止。

使用免费工具进行逆向和利用:第13部分

在那里我分配0x64字节。

使用免费工具进行逆向和利用:第13部分

我们看到它实际上分配了超过0x64个字节,问题是它严格地只复制0x64个字节。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

在那里,我们不要忘记,rop从一开始就中断了几个字节,要跳转我必须避开它们,我唯一找到的gadget是add rax, 20,这给我留下了很少的shellcode空间。

跟踪shellcode直到它到达VirtualAlloc。

使用免费工具进行逆向和利用:第13部分

我带着正确的参数到达那里,我可以转到 RET,把光标放在那里,按F4键,这样我就不会跟踪太多了。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

这就是GADGET,在RAX中加入0x20来跳转执行,避免了开始时被中断的字节。

然后我们跳转到执行。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

你可以看到我做的代码,它的作用是在堆栈中寻找shellcode,并在下面复制它,因为有地方,memmove在复制时没有完整地复制它,因为size=0x64的限制,但我是可以完整地复制它。

RSI tendr el source
RDI el destino
RCX el size a copiar en dwords

当我到达REP时,MOVSD复制了shellcode,我做了一个PUSH RDI来保存我复制的目的地的地址,这个地址被留在RDI中。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

我可以把光标放在那里按F4。

使用免费工具进行逆向和利用:第13部分

我们看到,它将以NOTEPAD字符串作为参数调用WinExec,该参数将执行NOTEPAD。

好吧,我有shellcode可以运行,我只是需要解释一下,在x64dbg中不是很好,所以我将运行脚本,并用Windbg给我附上,这样我可以看到需要的结构和符号,即使在我给它RUN之前,我验证它运行一个NOTEPAD。

使用免费工具进行逆向和利用:第13部分

我们看到,NOTEPAD运行后进入ExitProcess并关闭。

使用免费工具进行逆向和利用:第13部分

如果我在没有调试的情况下运行它,我看到它运行NOTEPAD并正确关闭。

好吧,我打算用Windbg运行它来追踪RESOLVER。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

在那之后

.reload /f

并在它完成下载所有的符号后。

lm

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分
吧,我有了这些符号。

使用免费工具进行逆向和利用:第13部分

我在那里设置了断点。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

现在要追溯到shellcode,我可以在VirtualAlloc中设置一个断点

使用免费工具进行逆向和利用:第13部分

bp KERNELBASE!VirtualAlloc

我用G运行并接受MessageBoxA,到VirtualAlloc在启动时被程序调用时,我继续用G。

使用免费工具进行逆向和利用:第13部分

再一次是 VirtualAlloc,但我们必须首先在 RET 停止,值得一提的是 VirtualAlloc 的下一站,我们继续,

我就停在那儿

使用免费工具进行逆向和利用:第13部分

再次按g键,现在如果在VirtualAlloc中,shift+F11是STEP OUT,则在RET之后立即退出函数。

使用免费工具进行逆向和利用:第13部分

用f11进行追踪。

我们到达了我的代码。

使用免费工具进行逆向和利用:第13部分

我一直用F10追踪,以传递REP MOVS,这样它就不会重复。

这里开始了SHELLCODE的解决办法,

通过找到KERNEL32的基地址来解决64位问题

使用免费工具进行逆向和利用:第13部分

CDQ:如果SF符号标志为零,则将RDX设为零,可能是XOR RDX, RDX

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

它是零,所以说RDX=0。

回顾一下,在32位中,TEB或TIB是由FS指向的。

使用免费工具进行逆向和利用:第13部分

64位中,GS寄存器被用于TEB。

使用免费工具进行逆向和利用:第13部分

在32位中,我们能够使用dg fs命令来查看FS值。

使用免费工具进行逆向和利用:第13部分

它对GS不起作用。

使用免费工具进行逆向和利用:第13部分

也许我们有更多的窍门,嘿嘿,还有"!teb"命令。

使用免费工具进行逆向和利用:第13部分

在这里我们看到TEB的内容和它在我的机器上的基数0x21f000和我的机器上的PEB的地址0x21e000。

如果我追踪第一条指令,它正在从字段0x60读取PEB。

mov rax, qword ptr gs:[rdx+60h]

由于我知道我的机器上的TEB地址是0x21f000,我可以使用dt命令并更好地看到它。

dt nt!_TEB 0x21f000

使用免费工具进行逆向和利用:第13部分

另外,我还有一个链接显示我需要的GDP。

第二条指令是:

使用免费工具进行逆向和利用:第13部分

读取PEB偏移量0x18中的字段,因为我可以单击链接并查看PEB列表。

使用免费工具进行逆向和利用:第13部分

Lee PEB->Ldr

使用免费工具进行逆向和利用:第13部分

好吧,让我们继续。

我们可以单击LDR或listar _ peb _ ldr _ data

使用免费工具进行逆向和利用:第13部分

请注意,在0x20偏移处,inmemoryordermodulelist加载

Microsoft 上面写着

使用免费工具进行逆向和利用:第13部分

在一些网页中(以及我们做32位RESOLVER部分时),LDR_DATA_TABLE_ENTRY也被称为LDR_MODULE,它更短,但相同。

叫它LDR_DATA_TABLE_ENTRY还是很方便的,因为这样它就被列在Windbg中。

使用免费工具进行逆向和利用:第13部分

正如我们所看到的,第一个字段的类型是TYPE_LIST_ENTRY,正如文档所说,它具有指向与下一个模块相对应的类似结构的Flink,即一个链表。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

因此,正如我们在图片中所看到的,这些结构是通过FLINK和BLINK相互连接的,因为FLINK是一个指向下一个结构的指针,只有找到它的内容,我们才能得到下一个结构的FLINK。

使用免费工具进行逆向和利用:第13部分

mov rsi, [rax + 0x20]

所以在这条指令中,它加载了RSI=InMemoryOrderModuleList,正如我们看到的,它是链接列表的开始,反过来属于LDR_DATA_TABLE_ENTRY链的第一个模块。

那些学习了32位练习教程的人应该记得,第一个InLoadOrderLinks字段是在那里使用的,两个列表都有关于模块的相同信息,它只会改变它们所在的顺序,在本例中,我们不是像InLoadOrderLinks那样位于结构的偏移量0x0,而是我们的Flink始终位于偏移量0x10。

使用免费工具进行逆向和利用:第13部分

RSI在第一个LDR_DATA_TABLE_ENTRY的0x10偏移处,在我的机器上是0x046262fa0。

我可以在Windbg中列出。

使用免费工具进行逆向和利用:第13部分

在这里我们看到,我们在偏移量0x10处,所以我们必须减去0x10来列出结构。

dt LDR_DATA_TABLE_ENTRY (0x0462fa0 -0x10)

我们看到它对应的是可执行模块,它总是在链中的第一个,在那里我们看到它的基地址和它的名字,我们也看到FLINK到第二个模块的结构。

这是通过查找ESI内容以编程方式完成的,因为LODS语句读取ESI内容并将其移动到EAX。

lodsqword ptr [rsi] ds:0x00462fa0=0x0462e10

使用免费工具进行逆向和利用:第13部分

EAX再次位于第二个结构的0x10偏移处,我们可以看一下对应的模块。

使用免费工具进行逆向和利用:第13部分

我们看到第二个LDR_DATA_TABLE_ENTRY对应的是ntdll.dll,第三个被FLINK指向的将是0x463460。

然后用XCHG把它从EAX移到ESI。

使用免费工具进行逆向和利用:第13部分

然后用LODS再次找到内容,当然它匹配的将是0x463460。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

它对应于kernel32.dll,由于EAX被定位在偏移量0x10,要读取kernel32.dll的基数,你必须加上0x20,才能到达它所在的0x30。

使用免费工具进行逆向和利用:第13部分

有了这个,他已经找到了 kernel32.dll基数 ,这是第一个要寻找的目标。

使用免费工具进行逆向和利用:第13部分

查找WINEXEC的地址

一旦找到 Kernel32.dll 的基数 ,在 kernel32 中找到 WinExec 或我们想要的函数的步骤如下。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

这是我们要追踪的代码的一部分,以检查一切是否匹配。

标头部开始的结构,当然是在我们找到的kernel32.dll图像库的地址处,被称为_IMAGE_DOS_HEADER,在那里我们看到了MZ的特征,这两个字节是DOS可执行文件的开头。

使用免费工具进行逆向和利用:第13部分

请注意,shellcode读取0x3c偏移字段

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

值为232十进制或0x 8是_IMAGE_NT_HEADERS64的偏移量

使用免费工具进行逆向和利用:第13部分

将基地址相加以获得地址。

使用免费工具进行逆向和利用:第13部分

RDX中的地址为_IMAGE_NT_HEADERS64

使用免费工具进行逆向和利用:第13部分

然后寻找字段0x88,我们看到它在OptionalHeader里面,它的位置是0x18。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

在0x70是_IMAGE_DATA_DIRECTORY64加上0x18的_IMAGE_OPTIONAL_HEADER64,我们在0x88的时候,shellcode读到了。

这是一个_IMAGE_DATA_DIRECTORY的ARRAY。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

第一个是到EXPORT表的偏移量,其第一个字段是到地址的偏移量。

使用免费工具进行逆向和利用:第13部分

然后加上基数,得到EXPORT TABLE的地址。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

读取0x20偏移地址。

使用免费工具进行逆向和利用:第13部分

因此,在0x1c中有三个addressofnames数组,在0x20中有addressofnames数组,在0x24中有AddressOfNames序数数组。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

所以RSI有命名表或数组。

使用免费工具进行逆向和利用:第13部分

为了找到表中的每一个条目,你必须加上基数,这就是它所做的,它在表中读取偏移量并加上基数,然后与WinExec进行比较(如果你想要另一个函数,你必须在这里改成你想找到的那个函数的名称)。

让我们来看看表中的第一个指向什么。

使用免费工具进行逆向和利用:第13部分

因此,这些偏移中的每一个加上base都指向一个导出函数的名称,因此它循环遍历表,将每个字符串与winexec进行比较。

使用免费工具进行逆向和利用:第13部分

我们可以在JNE后面加一个BREAKPOINT,当它找到这个名字时按RUN停止。

使用免费工具进行逆向和利用:第13部分

当它停止时。

使用免费工具进行逆向和利用:第13部分

我们看到,它正在增加RCX,这是表的索引,所以WinExec在表中的位置是RCX=0x60e。

使用免费工具进行逆向和利用:第13部分

回顾一下,我们在r8上加上0x20,然后再加上基数,就可以找到名字表,如果我们加上0x24,再加上基数,就可以找到序数表。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

在非循环序数表中,使用名称表位置的RCX中的索引值,我们从该表中读取函数的编号。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

它也是0x60e,在最后一个表格中用于查找WinExec函数的偏移。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

因此,RSI+RCX*4为我们提供了WinExec偏移量。

使用免费工具进行逆向和利用:第13部分

我们在其中加上基数,我们就有了WinExec的虚拟地址。

调用winexec

使用免费工具进行逆向和利用:第13部分

就这样,然后设置一个NOTEPAD字符串来传递,跳转到运行WinExec的 "NOTEPAD "参数。

使用免费工具进行逆向和利用:第13部分

使用免费工具进行逆向和利用:第13部分

然后,如果我们用f10传递调用并继续,我们就调用ExitProcess来关闭它。

使用免费工具进行逆向和利用:第13部分

在那里,NOTEPAD一直在运行。

使用免费工具进行逆向和利用:第13部分

好了,64位解决方案的情况到此为止。

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月15日10:27:57
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   使用免费工具进行逆向和利用:第13部分https://cn-sec.com/archives/913059.html