1.5 编写自定位ShellCode弹窗( 三 )


根据如上分析细节,那么描述枚举模块列表的核心代码就可以写成如下案例;
#include #include int main(int argc, char* argv[]){DWORD *PEB = NULL, *Ldr = NULL, *Flink = NULL, *p = NULL;DWORD *BaseAddress = NULL, *FullDllName = NULL,*Ba = NULL;__asm{mov eax, fs:[0x30]mov PEB, eax}Ldr = *((DWORD **)((unsigned char *)PEB + 0x0c));Flink = *((DWORD **)((unsigned char *)Ldr + 0x14));p = Flink;p = *((DWORD **)p);while (Flink != p){BaseAddress = *((DWORD **)((unsigned char *)p + 0x10));FullDllName = *((DWORD **)((unsigned char *)p + 0x20));if (BaseAddress == 0)break;printf("镜像基址 = x \n --> 模块路径 = %S \n", BaseAddress, (unsigned char *)FullDllName);p = *((DWORD **)p);}system("pause");return 0;}
读者编译并运行该程序,则默认会枚举出当前模块所导入的所有模块信息,其输出效果如下图所示;
1.5.3 计算函数Hash摘要值
案例介绍了如何使用Win32汇编语言和C语言计算字符串的hash摘要值 。字符串的hash摘要值是通过一定的算法将字符串压缩为一个固定长度的十六进制数,用于在程序中进行快速的字符串比较 。具体而言,该案例使用了循环移位hash计算法,并最终得到了字符串的 hash 值,并以十六进制数的形式输出 。

1.5 编写自定位ShellCode弹窗

文章插图
读者一定有疑问为啥需要HASH压缩处理? 原因是,如果直接将函数名压栈的话,我们就需要提供更多的空间来存储代码,为了能够让我们编写的代码更加的短小精悍,所以我们将要对字符串进行hash处理,将字符串压缩为一个十六进制数,这样只需要比较二者hash值就能够判断目标函数,尽管这样会引入额外的hash算法,但是却可以节省出存储函数名字的空间 。
为了能让读者理解计算原理,此处我们先使用C语言做摘要计算描述,如下代码中的函数,该函数接受一个指向字符数组的指针,即一个字符串,然后对字符串进行哈希计算,并返回计算结果 。
哈希计算的过程是通过循环遍历字符串中的每个字符,对其进行位运算和加法运算,最终得到一个32位的哈希值 。对于字符串中的每个字符,程序首先将哈希值左移25位,然后将结果右移7位,相当于是对哈希值进行了循环右移25位 。然后程序将该字符的ASCII值加到哈希值上 。循环遍历完字符串中的所有字符后,哈希值即为最终的计算结果 。
#include #include DWORD GetHash(char *fun_name){DWORD digest = 0;while (*fun_name){digest = ((digest << 25) | (digest >> 7));digest += *fun_name;fun_name++;}return digest;}int main(int argc, char *argv[]){DWORD MessageBoxHash;DWORD ExitProcessHash;DWORD LoadLibraryAHash;MessageBoxHash = GetHash("MessageBoxA");printf("MessageBoxHash = 0x%.8x\n", MessageBoxHash);ExitProcessHash = GetHash("ExitProcess");printf("ExitProcessHash = 0x%.8x\n", ExitProcessHash);LoadLibraryAHash = GetHash("LoadLibraryA");printf("LoadLibraryAHash = 0x%.8x\n", LoadLibraryAHash);system("pause");return 0;}
运行上方C语言实现代码,则读者可以此获取到三个核心函数的Hash值,其输出效果如下图所示;
在理解了C语言版本的计算流程后,那么汇编语言版本的也应该很容易理解,如下是使用Win32汇编语言的实现过程,并在MASM上正常编译,汇编版字符串转换Hash值 。
.386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incinclude msvcrt.incincludelib kernel32.libincludelib msvcrt.lib.datadata db "MessageBoxA",0hFomat db "0x%x",0.codemain PROCxor eax,eax; 清空eax寄存器xor edx,edx; 清空edx寄存器lea esi,data; 取出字符串地址loops:movsx eax,byte ptr[esi]; 每次取出一个字符放入eax中cmp al,ah; 验证eax是否为0x0即结束符jz nops; 为0则说明计算完毕跳转到nopsror edx,7; 不为零,则进行循环右移7位add edx,eax; 将循环右移的值不断累加inc esi; esi自增,用于读取下一个字符jmp loops; 循环执行nops:mov eax,edx; 结果存在eax里面invoke crt_printf,addr Fomat,eaxretmain ENDPEND main