TOP

C语言编程笔记丨使用C编译器编写shellcode(二)
2019-03-29 22:07:53 】 浏览:325
Tags:语言编程 笔记 使用 编译器 编写 shellcode

样正常工作,你可以利用C提供的全套功能。确保数据为局部变量,一切都OK了。

 

使用库函数

我将这篇文章专注于Windows环境的shellcode。上面所提及的一些规则也适用于Unix系统。Windows环境下的shellcode会更复杂一点,因为我们没有一致公开的方法进行系统调用,就像在Unix中仅需几条汇编代码就可以的那样(对int 80h的调用)。我们需要利用DLL中提供的API函数,来进行系统调用做些像读写文件、网络通信这样的事。这些DLL最终会进行必要的系统调用,而它的实现细节几乎随着每次Windows的发布而变化。像《The Shellcoder’s Handbook》这样的标榜性著作描绘了搜寻内存中DLL和函数的方法。如果想将shellcode做到在不同Windows版本间的可移植性,有两个函数是必须的:1、查找kernel32.dll的函数;2、实现GetProcAddress()函数或者查找GetProcAddress()地址的函数。我所提供的实现是基于hash的而非字符串的比较,下面我将提供用于shellcode的hash实现,并做个简短的说明。

 

Hash函数

在shellcode中,使用hash进行函数的查询是比较普遍的。较流行的ROR13 hash方法是最常用的,它的实现也用在了《The Shellcoder’s Handbook》中。它的基本思想是当我们要查询一个名为“MyFunction”的函数时,不是将字符串存放在内存中,对每个函数名进行字符串的比对,而是生成一个32位的hash值,将每个函数名进行hash比对。这并不能减小运行时间,但是可以节省shellcode的空间,也具有一定的反逆向功效。下面我提供了ASCII和Unicode版本的ROR13 hash实现:

DWORD __stdcall unicode_ror13_hash(const WCHAR *unicode_string)

{

    DWORD hash = 0;

 

    while (*unicode_string != 0)

    {

        DWORD val = (DWORD)*unicode_string++;

        hash = (hash >> 13) | (hash << 19); // ROR 13

        hash += val;

    }

    return hash;

}

 

DWORD __stdcall ror13_hash(const char *string)

{

    DWORD hash = 0;

 

    while (*string) {

        DWORD val = (DWORD) *string++;

        hash = (hash >> 13)|(hash << 19);  // ROR 13

        hash += val;

    }

    return hash;

}

 

查找DLL

有3个链表可以用来描述内存中加载的DLL:

InMemoryOrderModuleList、InInitializationOrderModuleList和InLoadOrderModuleList。它们都在PEB(进程环境块)中。在你的shellcode中,用哪个都可以,我所用的是InMemoryOrderModuleList。需要如下的两条内联汇编来访问PEB:

PPEB __declspec(naked) get_peb(void)

{

    __asm {

        mov eax, fs:[0x30]

        ret

    }

}

现在我们已经获取了PEB,可以查询内存中的DLL了。唯一的一直存在于Windows进程内存中的DLL是ntdll.dll,但kernel32.dll会更方便一点,并且在99.99%的Windows进程中(Win32子系统)都可用。下面我提供的代码实现会查询module列表,利用unicode的ROR13 hash值查到kernel32.dll。

HMODULE __stdcall find_kernel32(void)

{

    return find_module_by_hash(0x8FECD63F);

}

 

HMODULE __stdcall find_module_by_hash(DWORD hash)

{

    PPEB peb;

    LDR_DATA_TABLE_ENTRY *module_ptr, *first_mod;

 

    peb = get_peb();

 

    module_ptr = (PLDR_DATA_TABLE_ENTRY)peb->Ldr->InMemoryOrderModuleList.Flink;

    first_mod = module_ptr;

 

    do {

        if (unicode_ror13_hash((WCHAR *)module_ptr->FullDllName.Buffer) == hash)

            return (HMODULE)module_ptr->Reserved2[0];

        else

            module_ptr = (PLDR_DATA_TABLE_ENTRY)module_ptr->Reserved1[0];

    } while (module_ptr && module_ptr != first_mod);   // because the list wraps,

 

    return INVALID_HANDLE_VALUE;

}

这里所提供的find_module_by_hash函数可以利用dll名称的hash值找到任意的加载在内存中的DLL。如果要加载一个新的原本不再内存中的DLL,就需要使用kernel32.dll中的LoadLibrary函数。要找到LoadLibrary函数,我们就需要实现GetProcAddress函数。下面的代码实现利用函数名的hash值在加载的dll中查找函数:

FARPROC __stdcall find_function(HMODULE module, DWORD hash)

{

    IMAGE_DOS_HEADER *dos_header;

    IMAGE_NT_HEADERS *nt_headers;

    IMAGE_EXPORT_DIRECTORY *export_dir;

    DWORD *names, *funcs;

    WORD *nameords;

    int i;

 

    dos_header = (IMAGE_DOS_HEADER *)module;

    nt_headers = (IMAGE_NT_HEADERS *)((char *)module + dos_header->e_lfanew);

    export_dir = (IMAGE_EXPORT_DIRECTORY *)((char *)module + nt_headers->OptionalHeade  
		
C语言编程笔记丨使用C编译器编写shellcode(二) https://www.cppentry.com/bencandy.php?fid=45&id=216423

首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C语言编程笔记丨失落的C语言结构.. 下一篇Cmake 学习笔记