Thread: Segmentation fault!?!?!?

  1. #31
    Registered User
    Join Date
    Jun 2008
    Posts
    161
    That's the same example you already showed me. It only reads the main module. I want ALL the memory the process is using.

  2. #32
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Quote Originally Posted by matsp View Post
    Considering that the REST of the code is full of Windows API calls, I'd say that trying to write 5% of the code portably will make little difference.

    --
    Mats
    That was much appreciated. It reminds me of a question way back when where a person was asking how to read the contents of a file and dump it into an edit control. I pointed out that they may wish to consider using fread() instead of ReadFile() since it is more portable, and I believe it was Sabastiani who pointed out that it was pointless to try and remain portable considering the nature of the question to begin with. Plus ReadFile() is more native to the OS and is probably eventually called when using the fread() function. Sometimes its just better to just say touche, nod and move on.

    ---I digress. In responce to the previous post: EnumProcesses()? Have you looked at that at all. And EnumProcesseModules().

  3. #33
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Try looking up QueryWorkingSet().

    I'm about to go to be now, but I did a very quick hack to see what it gives, and it looks soemwhat sensible. Make sure you give a big enough table.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #34
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Nifty. QueryWorkingSetEx() looks like it can pick up a little more info than QueryWorkingSet().

  5. #35
    Registered User
    Join Date
    Jun 2008
    Posts
    161
    Well, the only thing I can figure to do at this point is use GetProcessMemoryInfo to get the size of the process, which gives me the exact amount shown by Task Manager. Then loop starting at 0 (or the entrypoint?) and skip over anything unreadable. Not exactly the most reliable or efficient thing to do, but I'm not seeing any other way that I can actually understand. All I want is ALL the memory allocated to the process--not the base module, not 1 page, ALL of it--dumped into an array in the fastest, most simplistic way possible.

  6. #36
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I'm pretty sure QueryWorkingSet (and perhaps QueryWorkingSetEx as well), assuming you give it a large enough table, is the right way to go.

    GetProcessMemoryInfo only shows HOW much memory the process uses, not where the memory is. QueryWorkingSet(Ex) gives you the actual memory used by the process.

    I'll see if I can hack up a little example in a bit.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #37
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Give the following a try. It dumps ALL the process memory to a log file that will be found in the same subdirectory from which the executable was started. Start the executable from the command line with the name of the target process as the first parm on the command line. Be forewarned, dumping something like iexplore.exe will create a HUGE file.

    Code:
    #include <afx.h>
    #include <windows.h>
    #include <TLHelp32.h>
    #include <stdio.h>
    #include <psapi.h>
    
    FILE *outfile;
    
    int VerifyProcessId(char *pProcessName)
    {
        HANDLE hSnap = INVALID_HANDLE_VALUE;
        HANDLE hProcess = INVALID_HANDLE_VALUE;    
        PROCESSENTRY32 ProcessStruct;
        ProcessStruct.dwSize = sizeof(PROCESSENTRY32);    
        hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);    
        if(hSnap == INVALID_HANDLE_VALUE)
            return -1;
        if(Process32First(hSnap, &ProcessStruct) == FALSE)
            return -1;
        do
        {
            if(stricmp(strupr(ProcessStruct.szExeFile), pProcessName)==0)
            {
                CloseHandle( hSnap ); 
                return  ProcessStruct.th32ProcessID;
                break;
            }
        } 
        while( Process32Next( hSnap, &ProcessStruct ) );
        CloseHandle( hSnap );  
        return -1;
    }
    
    static FILE *OpenLogFile(void)
    {
        int iIndex;
        for (iIndex = 0; iIndex < 0x10000; ++iIndex) {
            char fname[4096];
            sprintf(fname, "DUMP%04x.log", iIndex);
            FILE *f = fopen(fname, "r");
            if (f == NULL)
            {
                fprintf(stderr, "Log file being used: %s\n",fname);
                return fopen(fname, "wt");
            } 
            else {
                fclose(f);
            }
        }
        return NULL;
    }
    
    char * BuildErrorMessage( char* pMessage)
    {
        DWORD eNum;
        CHAR sysMsg[256] = {0};
        CHAR* p;
        static CHAR *szReturn[512];
        eNum = GetLastError( );
        FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, eNum,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            sysMsg, 256, NULL );
        // Trim the end of the line and terminate it with a null
        p = sysMsg;
        while( ( *p > 31 ) || ( *p == 9 ) )
            ++p;
        do { *p-- = 0; } while( ( p >= sysMsg ) &&
            ( ( *p == '.' ) || ( *p < 33 ) ) );
        memset(szReturn, 0, sizeof szReturn);
        sprintf((char *)szReturn,"WARNING: %s failed with error %d (%s)\n",pMessage, eNum, sysMsg );
        return (char *)szReturn;
    }
    
    BOOL EnableTokenPrivilege (LPTSTR privilege)
    {
        HANDLE hToken;                        
        TOKEN_PRIVILEGES token_privileges;                  
        DWORD dwSize;                        
        ZeroMemory (&token_privileges, sizeof (token_privileges));
        token_privileges.PrivilegeCount = 1;
        if ( !OpenProcessToken (GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
            return FALSE;
        if (!LookupPrivilegeValue ( NULL, privilege, &token_privileges.Privileges[0].Luid))
        { 
            CloseHandle (hToken);
            return FALSE;
        }
        token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        if (!AdjustTokenPrivileges ( hToken, FALSE, &token_privileges, 0, NULL, &dwSize))
        { 
            CloseHandle (hToken);
            return FALSE;
        }
        CloseHandle (hToken);
        return TRUE;
    }
    
    void ReadTheMemory(DWORD dwProcessId, HEAPENTRY32 heapentry)
    {
        CString     strLine, strArr, strTemp;
        BYTE        byte;
        DWORD dwBlock = 0, dwOffset, dwBytesRead;
        BYTE * pBuffer = new BYTE[heapentry.dwBlockSize];
        HANDLE hProcess = NULL;
        if (NULL != pBuffer)
        {    
            hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessId);
            if(hProcess == NULL)
            {
                fprintf(outfile, "%s", BuildErrorMessage("OpenProcess"));
                return;
            }
            if (ReadProcessMemory( hProcess, (LPCVOID) heapentry.dwAddress, pBuffer, heapentry.dwBlockSize, &dwBytesRead) == TRUE)
            {
                for (dwBlock = 0; dwBlock < heapentry.dwBlockSize; dwBlock += 16)
                {
                    strLine.Format("[%08x]:  ", heapentry.dwAddress + dwBlock);
                    strArr.Empty();
                    // we'll use 16 bytes per line
                    for (dwOffset = 0; dwOffset < 16; dwOffset++)
                    {
                        byte = *(pBuffer + dwBlock + dwOffset);
                        strLine.Format("%02x ", byte);
                        // account for non-printable characters
                        if (32 <= byte && byte < 127)
                            strArr += byte;
                        else
                            strArr += '·';
                    }
                    if(LF32_FIXED == heapentry.dwFlags)
                        strTemp.Format("%s", "Fixed  ");
                    else if(LF32_FREE == heapentry.dwFlags)
                        strTemp.Format("%s", "Free   ");
                    else if(LF32_MOVEABLE == heapentry.dwFlags)
                        strTemp.Format("%s", "Movable");
                    else    strTemp.Format("%s", "Unknown");    
    
                    strLine.Format ("%#x %#x %s %#x (%lu) %s ", heapentry.th32HeapID, heapentry.dwAddress, strTemp,heapentry.dwBlockSize, heapentry.dwBlockSize, strArr);
                     fprintf(outfile, "%s\n", strLine);
                }    
            }
            else
            {
                strLine.Format ("%#x %#x %s %#x (%lu) %s ", heapentry.th32HeapID, heapentry.dwAddress, strTemp,heapentry.dwBlockSize, heapentry.dwBlockSize, strArr);if(LF32_FIXED == heapentry.dwFlags)
                    strTemp.Format("%s", "Fixed  ");
                else if(LF32_FREE == heapentry.dwFlags)
                    strTemp.Format("%s", "Free   ");
                else if(LF32_MOVEABLE == heapentry.dwFlags)
                    strTemp.Format("%s", "Movable");
                else    strTemp.Format("%s", "Unknown");
                strLine.Format ("%#x %#x %s %#x (%lu)", heapentry.th32HeapID, heapentry.dwAddress,strTemp ,heapentry.dwBlockSize, heapentry.dwBlockSize);
                fprintf(outfile, " %s ", strLine);
                fprintf(outfile, "%s", BuildErrorMessage("ReadProcessMemory"));
            }
            delete [] pBuffer;
            CloseHandle( hProcess );
        }
    }
    
    int main(int argc, char **argv)
    {
        PROCESSENTRY32  ProcessEntry = {0};
        HANDLE          hProcessSnapshot;
        HANDLE hProcess = NULL;
        int             nIndex = 0,
                        nItem;
        CString         strText, strTemp;
        DWORD dwProcessId ;
        HEAPENTRY32 HeapEntry;
        HEAPLIST32 HeapList;
    
        if ( !EnableTokenPrivilege (SE_DEBUG_NAME) )
        {
            fprintf(outfile, "%s", BuildErrorMessage("EnabletokenPrivilege issue"));
            return 0;
        }                                                 
        dwProcessId = VerifyProcessId(argv[1]);
        if(dwProcessId == -1)
        {
            printf("Cannot determine Process id for %s, ABORTING!!\n",argv[1]);
            return -1;
        }
        outfile = OpenLogFile();
        if(outfile == NULL)
        {
            printf("Log file open failed\n");
            return -1;
        }
        HANDLE hHeapSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, dwProcessId);
        if (INVALID_HANDLE_VALUE != hHeapSnapshot)
        {
            HeapList.dwSize = sizeof(HEAPLIST32);
            if (Heap32ListFirst(hHeapSnapshot, &HeapList) != FALSE)
            {    
                do
                {
                    HeapEntry.dwSize = sizeof(HEAPENTRY32);
                    if (Heap32First(&HeapEntry, HeapList.th32ProcessID, HeapList.th32HeapID) != FALSE)
                    {
                        do
                        {
                            ReadTheMemory( dwProcessId, HeapEntry);
                        } while (Heap32Next(&HeapEntry) != FALSE);
                    }
                    else
                    {
                        fprintf(outfile, "%s", BuildErrorMessage("Iterating heap block error"));
                        break;
                    }
                } while (Heap32ListNext(hHeapSnapshot, &HeapList) != FALSE);
            }
            else  fprintf(outfile, "%s", BuildErrorMessage("Iterating heap list error"));
            CloseHandle(hHeapSnapshot);
        }   
        else  fprintf(outfile, "%s", BuildErrorMessage("Can't acquire snapshot"));
        return 0;
    }

  8. #38
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I've hacked up something that uses QueryWorkingSet here. It appears to work OK on Win2K - you may need to use some of that "set privilige" code that Bob has shown.

    I'm afraid I'm not a very good with GUI programming, so I have been using MFC for this, hence a large zipfile rather than a few hundred lines of code. The main parts is in
    Code:
    LeftView.cpp void CLeftView::OnInitialUpdate()
    which gathers and stores the memory information in a TreeView. Currently it's pretty stupid - I probably should use a more dynamic model of expanding the application when it's selected, rather than storing ALL page info for ALL processes (at the moment nobbled to stop at the 10th process to avoid it taking too long to start up - in the min(..., 10), either change 10 to a much larger number or remove the min(..., 10) except for cProcesses).
    Code:
    void CLeftView::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
    Connects the click on the memory block with the rigthPane drawing.

    Code:
    showmemView.cpp: void CshowmemView::OnPaint()
    Draws the content of the memory block selected.
    The thing that is needed here is a scrollbar to scroll to the second half of memory (and perhaps the next block of memory as well).

    The attachment is a .zip file with modified extension to get past the "you can only put these types of files up" filter.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #39
    Registered User
    Join Date
    Jun 2008
    Posts
    161
    Uh, sorry Bob. That seems to fail too. I did a quick test just outputting the HeapEntry.dwAddress and HeapEntry.dwBlockSize from the loop exactly as you had it. The highest it goes is 0x5F30008, despite the fact the process in question is reported (by task manager) to be using 70 megs--and I've personally dumped from 0x3B0A0000-3B0F0000 before. It also completely ignores the 0x400000 (entrypoint/main module) region. I don't get it.
    Last edited by Viper187; 09-26-2008 at 09:14 AM.

  10. #40
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Whilst I don't think looking for "heap" is the correct solution (I believe my suggestion of QueryWorkingSet is the correct solution), I would say that it's likely that an applicatin that uses addresses up to 95MB uses has approximately 70MB of space used. 5f30008 is 95.18 MB according to Calculator.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #41
    Registered User
    Join Date
    Jun 2008
    Posts
    161
    Quote Originally Posted by matsp View Post
    Whilst I don't think looking for "heap" is the correct solution (I believe my suggestion of QueryWorkingSet is the correct solution), I would say that it's likely that an applicatin that uses addresses up to 95MB uses has approximately 70MB of space used. 5f30008 is 95.18 MB according to Calculator.

    --
    Mats
    If 0x5F30008 is 95 megs, why does this process have data at 0x3B0A0000 but only uses 70 meg?

  12. #42
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Viper187 View Post
    If 0x5F30008 is 95 megs, why does this process have data at 0x3B0A0000 but only uses 70 meg?
    Becuase there are such things as "randomization" in the memory allocation...

    There is no guarantee that all memory comes in one big lump, ok?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #43
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by Viper187 View Post
    Uh, sorry Bob. That seems to fail too. I did a quick test just outputting the HeapEntry.dwAddress and HeapEntry.dwBlockSize from the loop exactly as you had it. The highest it goes is 0x5F30008, despite the fact the process in question is reported (by task manager) to be using 70 megs--and I've personally dumped from 0x3B0A0000-3B0F0000 before. It also completely ignores the 0x400000 (entrypoint/main module) region. I don't get it.
    I'm not sure what you're going to do with all that memory stored in an array. The task manager working set consists of thread stacks, environment memory, system data structures, shared memory and much more. If you plan on searching all this memory, you may end up in pages of shared memory loaded from NTDLL.DLL. IMHO, trying to sort out all of this in the working set would probably require a lot of "rocket science" coding in addition to just dumping all this memory in a array. So, my question is, can you make any practical use of this memory once you acquire it?

  14. #44
    Registered User
    Join Date
    Jun 2008
    Posts
    161
    Quote Originally Posted by matsp View Post
    Becuase there are such things as "randomization" in the memory allocation...

    There is no guarantee that all memory comes in one big lump, ok?

    --
    Mats
    Ok, so back to the original problem. I looked at the source you provided (I absolutely despise C++ project sand source, btw). in any case, I haven't figured out everything I need form it, assuming it even gets the right data. I get that looping wsInfo->WorkingSetInfo[j].VirtualPage gives me memory locations; however, I don't get how to determine the size of these "pages." They also don't output in order. I don't suppose there's an easy way to find the max address to malloc() my array so I can have everything padded the way I want. Sort the WorkingSetInfo array before looping, maybe? I dunno.

    p.s. Why the hell aren't PSAPI_WORKING_SET_INFORMATION and PSAPI_WORKING_SET_BLOCK declared in psapi.h like they should've been?


    Quote Originally Posted by BobS0327 View Post
    I'm not sure what you're going to do with all that memory stored in an array. The task manager working set consists of thread stacks, environment memory, system data structures, shared memory and much more. If you plan on searching all this memory, you may end up in pages of shared memory loaded from NTDLL.DLL. IMHO, trying to sort out all of this in the working set would probably require a lot of "rocket science" coding in addition to just dumping all this memory in a array. So, my question is, can you make any practical use of this memory once you acquire it?
    I don't know the right way to do it. That's why I'm asking you guys. I need to dump the entire process for comparison (i.e. game hacking). As I said... this 70 meg process stores data (actually, vital game data) at that higher address range (0x3B0A0000+), which your method didn't touch. you have no idea how useful it can be to run an N64 game on the PC to find gameshark codes for it. I've even done some PS2 codes, despite my system being slow. I want my program to branch out and do PC games as well though. Think Tsearch/Art Money on steroids. My previous program was called Renegade64, though I doubt anyone here would've heard of it. It was mainly written in VB6 with a C DLL to speed dumping/searching (only dumping the console RAM part of the process memory after finding it with tsearch). Now that I actually got off my ass and learned enough win32 to write C programs with a GUI, I'm trying to write a better version of my old program. Naturally, I'm running into issues I don't know how to handle. I never expected to be hung up for a week trying to figure out how to dump a process though.
    Last edited by Viper187; 09-26-2008 at 08:54 PM.

  15. #45
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I have no idea why psapi.h doesn't declare the types for QueryWorkingSet... I copied and pasted from the MSDN pages, and it appears to work.

    As to finding the total size of the project, I would actually just count the number of pages that came back and multiply by 4096 bytes. You will probably not sensibly be able to malloc a region big enough for the entire memory to fit in as one. Instead, store all of the memory as one big lump, and use an array with addresses to store the location of each block.

    It is possible that the system uses "large pages", in which case you would have to use QueryWorkingSetEx for each location to find the size of the page (the data returned by this function has a flag to say "LargePage", which means that it is 2 or 4MB depending on the mode of the processor: PAE -> 2MB, non-PAE->4MB). But I doubt it is likely that you will have any large pages. You could pre-check by this method:
    Code:
    if (!(proc->va & ((1 << 21)-1)))
    {
       // Need to check if it's a large page.
    }
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Segmentation fault problem
    By odedbobi in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2008, 03:36 AM
  2. Segmentation fault
    By bennyandthejets in forum C++ Programming
    Replies: 7
    Last Post: 09-07-2005, 05:04 PM
  3. Segmentation fault
    By NoUse in forum C Programming
    Replies: 4
    Last Post: 03-26-2005, 03:29 PM
  4. Locating A Segmentation Fault
    By Stack Overflow in forum C Programming
    Replies: 12
    Last Post: 12-14-2004, 01:33 PM
  5. Segmentation fault...
    By alvifarooq in forum C++ Programming
    Replies: 14
    Last Post: 09-26-2004, 12:53 PM