Nytro Posted March 15, 2013 Report Posted March 15, 2013 [h=1]Extracting Objects from a Running Process[/h]February 11, 2013 By PnUicFew days ago two new 0-days have been spotted in the wild: CVE-2013-0633 and CVE-2013-0634, both of them involving a .swf file, possibly embedded inside a Word Document. It might be interesting to understand how to dump a similar resource while the attacked process is running, after all the obfuscation layers are cleared. Clearly this same technique can be expanded to extract any type of object from any process, as an example whenever we need to simply dump a memory area, or when we need to extract (or find) an entire object. While memory dumpers are usually common tools, it might be interesting to understand how the dumping process works. So let’s dig a bit deeper. [h=2]Step 1: Understanding Windows Address Space[/h] The virtual address space of a process is the set of virtual memory addresses that the process is allowed to use. In the default Virtual Address Space for 32-bit Windows processes, the lower 2GB: from 0×0 through 0x7FFFFFFF, are assigned to the running process while the other 2GB are normally used by the system. More information: Virtual Address Space -Virtual Address Space in 64-bit Windows. [h=2]Step 2: APIs to get system information and to access a process memory[/h] [h=3]2.1 Processes list[/h] In order to read a given process memory, we need to acquire its handle and in turn, to do that we need to iterate the list of processes until we find the one we are looking for. Process enumeration is performed through the use of EnunProcesses() API, the code is quite simple:if(!EnumProcesses(nProcess, //processes list sizeof(nProcess), &nByteOfProc)) {return false;}nOfProcesses = nByteOfProc / sizeof(DWORD);//for each processfor (i = 0; i < nOfProcesses; i++ ){ // Get a handle to the process. hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, nProcess[i] ); // Get the process name. if ( hProcess != NULL) { if (EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) ) { //get application filename GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR)); //Has it found the right process? if(!_tcscmp(szProcessName, procName)) { // Do whatever we need with the newly found process ... } } CloseHandle(hProcess); }}[h=3]2.2 Memory sections[/h] Once we have access to memory process throungh the handle, we need to get information on its sections in order to find in a signature (that is: a sequence of bytes). That’s how we’ll proceed:Get the system minimum and maximum address of a process using GetSystemInfoCall VirtualQueryEx to retrieve information about sections within the virtual address space of a specified process, by section’s base address.System minimum address is the the first section base address.In the MEMORY_BASIC_INFORMATION structure there are info about memory section: size, base address and more;nextSectionBaseAddr = currentBaseAddress + currentSectionSizeCopy in a locally allocated process memory the target process’ section (ReadProcessMemory) to find the desired signature with a simple memcmp(). Here it is the code to find a sequence of bytes in memory: the SWF signature (the entire project can be downloaded at the end of the article).TCHAR buffer[] = _T("FWS"); //the signature can also be: CWS and ZWS, see SWF file format specificationGetSystemInfo(&sysInfo);memBase = sysInfo.lpMinimumApplicationAddress;memMax = sysInfo.lpMaximumApplicationAddress;//until max memory address or until buffer foundwhile(memBase < memMax) { //get section info VirtualQueryEx(hProcess, memBase, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); //if section is not reserved if(mbi.State != MEM_RESERVE ) { //I copy it: I alloc a memory buffer in local process .. allocatedMem = (BYTE *) VirtualAlloc(NULL, mbi.RegionSize, MEM_COMMIT, PAGE_READWRITE); if(allocatedMem != NULL) { //.. and copy bytes for more scan velocity if(ReadProcessMemory(hProcess, memBase, allocatedMem, mbi.RegionSize, &jnk)) { storedBaseAddr = baseAddr = allocatedMem; maxAddr = (BYTE*) ( ((SIZE_T)baseAddr + mbi.RegionSize) - lenBuffer); //and find the buffer into section while(baseAddr < maxAddr) { if(memcmp((LPVOID)baseAddr, buffer, lenBuffer) == 0) { //I found it!! _tprintf(_T("\tBuffer found at found at %p\n"), ( (SIZE_T)memBase + (baseAddr-storedBaseAddr)) ); //try to dump! DWORD objSize = dumpObj(baseAddr); //go ahead the object baseAddr = (BYTE*) ((SIZE_T)baseAddr + objSize); } else baseAddr++; //next byte } } //free memory VirtualFree(allocatedMem, 0, MEM_RELEASE); } } //next section base address memBase = (LPVOID) ((SIZE_T)memBase + mbi.RegionSize);}//the signature to find[h=3]2.3 Dump the object[/h] Once we have found a signature in memory, we can dump the object, provided we know its size and where to find this information: according to SWF specification the length field is an UInt32 (DWORD) at start+4:stringBaseAddr += 4;//get file sizeDWORD size = *((DWORD*)stringBaseAddr);_tprintf(_T("\tFile size: %u bytes\n"), size);//go to object start addrstringBaseAddr -= 4;//create a new fileHANDLE hFile = CreateFile(outputFileName,GENERIC_WRITE, FILE_SHARE_WRITE, 0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);if (hFile == INVALID_HANDLE_VALUE) { _tprintf(_T("\tImpossible to create dump file\n")); return; } //and write in the object if(WriteFile(hFile, stringBaseAddr, size, &jnk, NULL) == false) { CloseHandle(hFile); DeleteFile(outputFileName); _tprintf(_T("\tImpossible to dump the file\n\n")); } else { CloseHandle(hFile); _tprintf(_T("\tFile dumped!!\n\n")); }//addr of "FileLength" field:That’s all!Download project’s code.PnSursa: Extracting Objects from a Running Process Quote