风扫春残雪 发表于 2020-6-30 02:40

(C++/ASM)不使用API获得所有加载DLL的函数入口

老技术了,基本上加密壳人手一个吧……学习结束后暂时告一段落,把这一段程序扔上来记录一下。也方便以后用
主要使用的是c++ + 内联汇编。其实我是想用纯c++的,但是ntdef.h总是和windows.h/winnt.h冲突,只能引用一个太麻烦了。最后就还是用汇编写了。

这个功能的主要实现方法是fs:永远指向TEB(线程环境块),通过读取TEB的0x30处,可以获得当前进程的进程环境块(PEB),PEB的0xC是进程的LDR,保存了所有加载过的DLL信息。
LDR中有三个字段指向了LDR_DATA_TABLE的双向链表,通过双向链表可以得到所有dll的加载基址和dll名称;

得到dll加载基址后,再根据加载入内存中相应dll的PE头结构,可以获取dll的输出表信息。对输出表进行遍历,就可以获得所有函数的入口VA和名称了。

这一部分程序忽略了只能按序号索引的地址,所以……就这样吧。东西都是老东西了,写出来练练手。
我说的比较粗糙,对相关知识比较迷茫的同学可以参考一下这几篇文章,我感觉写得非常好
https://www.52pojie.cn/thread-684432-1-1.html
https://www.52pojie.cn/thread-685272-1-1.html

最后放代码。内联汇编为主,就染色成ASM了。可惜这个染色器不支持//注释

#include <ntdef.h>;
#include <iostream>;
#include <string>;

void GetAllFuncs(unsigned int* intEntry);

int main() {
   
    _UNICODE_STRING* lpBaseDllName = {};
    unsigned int* intBaseAddr = {};

    __asm {
      mov eax, fs: //TEB -> PEB
      add eax, 0ch
      mov eax, //PEB -> LDR
      add eax, 01ch
      mov eax, // LDR -> InInitializationOrderModuleList
      mov edx, eax //Save the first entry
    LIST_ENTRY_RET:
      mov ecx, //DllBase(DOS HEADER)
      mov intBaseAddr, ecx
      lea ecx,
      mov lpBaseDllName, ecx //*BaseDllName *Note, normally kernel32.dll is at the second turn.
      mov eax,
      cmp eax, edx
      je RETNOW
      pushad
    }
    std::wcout << "DllName: " << lpBaseDllName->Buffer << std::hex << ", Entry: " << intBaseAddr << std::endl;
    GetAllFuncs(intBaseAddr);
    _asm {
      popad
      jmp LIST_ENTRY_RET
      RETNOW:
    }
}


void GetAllFuncs(unsigned int *intEntry) {
    char* lpNameOfFunction = {};
    unsigned int* intAddrOfFunction = {};
    __asm {
      mov eax, intEntry
      mov ebx, //DOS_HEADER.e_lfanew
      add eax, ebx
      //now eax points to PE
      mov edx, 078h // PE + 078h = DataDirectory in x86(See IMAGE_NT_HEADERS32 struct)
      mov bx, //Magic, 010Bh for x86, 020Bh for x64 (x86/64 for the HEADER only)
      cmp bx, 020Bh
      jnz x86_next
      add edx, 010h //IMAGE_NT_HEADERS64 has more 10bytes than HEADERS32
      x86_next :
      mov eax, //Export Table DATA_DIRECTORY
      //mov eax, //RVA of Export Table

      mov ebx, intEntry
      add ebx, eax //ebx points to IMAGE_EXPORT_DIRECTORY

      //mov ecx, //NumberOfNames
      //mov eax, //AddressOfFunctions
      //mov edx, //AddressOfNameOrdinals
      // //AddressOfName
      xor edi, edi

    GO_ON_EXPORT :
      imul eax, edi, 4
      mov edx, //RVA Address
      add edx, intEntry
      mov esi, //AddressOfName
      add esi, intEntry
      mov lpNameOfFunction, esi

      imul eax, edi, 2
      mov edx,
      add edx, intEntry
      movzx esi, word ptr //AddressOfNameOrdinals
      imul esi, esi, 4

      mov edx,
      add edx, intEntry
      mov ecx,
      add ecx, intEntry
      mov intAddrOfFunction, ecx
      pushad
    }
    std::cout << "Name: " << lpNameOfFunction << ", Address: " << std::hex << intAddrOfFunction << std::endl;
    __asm{
      popad
      inc edi
      cmp edi,
      jnz GO_ON_EXPORT
    }
}

风扫春残雪 发表于 2020-6-30 12:09

q2510908331 发表于 2020-6-30 11:57
内联汇编完全可以使用较少的汇编来获取主要结构

https://www.nirsoft.net/kernel_struct/vista/PEB. ...

谢谢!我也觉得定义一下会好看很多……一时脑抽(

没有使用结构主要是当时想用ntdef.h里面的_UNICODE_STRING读取dllname结构。如果引用包含有PE结构的<windows.h>的话,就重定义了……单独拎出来定义又懒(现在想来费力不讨好,就一个结构cp一下又不是很难)
其实真要偷懒的话不用_UNICODE_STRING,直接用wchar_t去读UNICODE_STRING后面的那个串是更好的策略

IBinary 发表于 2020-6-30 11:57

本帖最后由 q2510908331 于 2020-6-30 11:59 编辑

内联汇编完全可以使用较少的汇编来获取主要结构

https://www.nirsoft.net/kernel_struct/vista/PEB.html
https://www.nirsoft.net/kernel_struct/vista/TEB.html
https://www.nirsoft.net/kernel_struct/vista/LDR_DATA_TABLE_ENTRY.html

定义好结构在定义PE结构多好.你这样写可读性差.不过如果学习内联汇编写法还行. 真正的要使用还是定义为结构.
遍历结构进行操作. 你这种作为ShellCode还是不错

lifz888 发表于 2020-6-30 08:35

学习了,支持发帖,支持原创

蓝枫冰笛 发表于 2020-6-30 08:44

竟然是前排,仰望大佬

pizazzboy 发表于 2020-6-30 09:11

厉害,谢谢分享。

Xw丶小威 发表于 2020-6-30 09:14

前排支持。用到回来看。

future001 发表于 2020-6-30 09:32

不愧是大神,直接用汇编写了,我都没写过汇编

sxisir 发表于 2020-6-30 09:51

太吊了,完全看不懂

IBinary 发表于 2020-6-30 13:42

风扫春残雪 发表于 2020-6-30 12:09
谢谢!我也觉得定义一下会好看很多……一时脑抽(

没有使用结构主要是当时想用ntdef.h里面的_UNICODE_ ...

是的呀哈哈.你这样做的话 做ShellCode还行. 真要以后自己用自己都不爱维护的.
页: [1] 2
查看完整版本: (C++/ASM)不使用API获得所有加载DLL的函数入口