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

<86d00000){da @$t0;}}758ee86e"_initterm_e"758ee862"_initterm"75830002"."758eeb80"memset"758ee84e"wcsncmp"758ee858"strcspn"
我们将问题回归到枚举导出表上,函数的RVA地址和名字按照顺序存放在上述两个列表中,我们可以在列表定位任意函数的RVA地址,通过与动态链接库的基地址相加得到其真实的VA,而计算的地址就是我们最终在中调用时需要的地址,其汇编核心枚举代码如下所示;
#include #include int main(int argc, char * argv[]){int a;__asm{mov ebx, dword ptr fs : [0x30]; 获取当前线程信息的地址mov ecx, dword ptr[ebx + 0xc]; 获取PEB结构体的地址mov ecx, dword ptr[ecx + 0x1c]; 获取PEB结构体中的LDR结构体的地址mov ecx, [ecx]; 获取LDR结构体中的InMemoryOrderModuleList的头节点地址mov edx, [ecx + 0x8]; 获取第一个模块的基址,即ntdll.dll的基址mov eax, [edx+0x3c]; 获取PE头偏移地址mov ecx, [edx + eax + 0x78]; 获取导出表VA地址偏移add ecx,edx; 将导出表的VA地址转换成绝对地址mov ebx, [ecx+0x20]; 获取导出表中的导出函数名偏移数组的地址add ebx,edx; 将函数名偏移数组的VA地址转换成绝对地址xor edi,edi; 将edi清零,用于循环计数s1:inc edi; 计数器自增1mov esi, [ebx+edi*4]; 通过偏移获取导出函数名的地址add esi,edx; 将导出函数名的VA地址转换成绝对地址cmp esi,edx; 检查导出函数名的地址是否合法,如果等于基址则跳过je noloop s1; 继续查找导出函数名no:xor eax,eax; 清零eax寄存器,用于返回值}system("pause");return 0;}
1.5.5 整合自定位
完整的汇编代码如下,下方代码是一个定式,这里就只做了翻译,使用编译器编译如下代码 。
#include #include int main(int argc, char *argv){__asm{// 将索要调用的函数hash值入栈保存CLD// 清空标志位DFpush 0x1E380A6A// 压入MessageBoxA-->user32.dllpush 0x4FD18963// 压入ExitProcess-->kernel32.dllpush 0x0C917432// 压入LoadLibraryA-->kernel32.dllmov esi, esp// 指向堆栈中存放LoadLibraryA的地址lea edi, [esi - 0xc]// 后面会利用edi的值来调用不同的函数// 开辟内存空间,这里是堆栈空间xor ebx, ebxmov bh, 0x04// ebx为0x400sub esp, ebx// 开辟0x400大小的空间// 将user32.dll入栈mov bx, 0x3233push ebx// 压入字符'32'push 0x72657375// 压入字符 'user'push espxor edx, edx// edx=0// 查找kernel32.dll的基地址mov ebx, fs:[edx + 0x30]// [TEB+0x30] -> PEBmov ecx, [ebx + 0xC]// [PEB+0xC] -> PEB_LDR_DATAmov ecx, [ecx + 0x1C]// [PEB_LDR_DATA+0x1C] -> InInitializationOrderModuleListmov ecx, [ecx]// 进入链表第一个就是ntdll.dllmov ebp, [ecx + 0x8]//ebp = kernel32.dll 的基地址// hash 的查找相关find_lib_functions :lodsd// eax=[ds*10H+esi],读出来是LoadLibraryA的Hashcmp eax, 0x1E380A6A// 与MessageBoxA的Hash进行比较jne find_functions// 如果不相等则继续查找xchg eax, ebpcall[edi - 0x8]xchg eax, ebp// 在PE文件中查找相应的API函数find_functions :pushadmov eax, [ebp + 0x3C]// 指向PE头mov ecx, [ebp + eax + 0x78]// 导出表的指针add ecx, ebp// ecx=0x78C00000+0x262cmov ebx, [ecx + 0x20]// 导出函数的名字列表add ebx, ebp// ebx=0x78C00000+0x353Cxor edi, edi// 清空edi中的内容,用作索引// 循环读取导出表函数next_function_loop :inc edi// edi作为索引,自动递增mov esi, [ebx + edi * 4]// 从列表数组中读取add esi, ebp// esi保存的是函数名称所在的地址cdq// hash值的运算过程hash_loop :movsx eax, byte ptr[esi]// 每次读取一个字节放入eaxcmp al, ah// eax和0做比较,即结束符jz compare_hash// hash计算完毕跳转ror edx, 7add edx, eaxinc esijmp hash_loop// hash值的比较函数compare_hash :cmp edx, [esp + 0x1C]jnz next_function_loop// 比较不成功则查找下一个函数mov ebx, [ecx + 0x24]// ebx=序数表的相对偏移量add ebx, ebp// ebx=序数表的绝对地址mov di, [ebx + 2 * edi]// di=匹配函数的序数mov ebx, [ecx + 0x1C]// ebx=地址表的相对偏移量add ebx, ebp// ebx=地址表的绝对地址add ebp, [ebx + 4 * edi]// 添加到EBP(模块地址库)xchg eax, ebp// 将func addr移到eax中pop edi// edi是pushad中最后一个堆栈stosdpush edipopadcmp eax, 0x1e380a6a// 与MessageBox的hash值比较jne find_lib_functions// 下方的代码,就是我们的弹窗xor ebx, ebx// 清空eb寄存器push ebx// 截断字符串0push 0x2020206bpush 0x72616873push 0x796c206fpush 0x6c6c6568mov eax, esppush ebx// push 0push eax// push "hello lyshark"push eax// push "hello lyshark"push ebx// push 0call[edi - 0x04]// call MessageBoxApush ebx// push 0call[edi - 0x08]// call ExitProcess}return 0;}