diff options
| author | Petr Mrázek | 2011-06-14 16:13:28 +0200 |
|---|---|---|
| committer | Petr Mrázek | 2011-06-14 16:13:28 +0200 |
| commit | 22b79bb46e80e552412ef60c1850b5955b6c940d (patch) | |
| tree | a84cbe989e46804b9080820776ff08683d36cf81 /library/Process-windows.cpp | |
| parent | 0a428b509e565d97f0bb2fe238053d09212cc18e (diff) | |
| download | dfhack-22b79bb46e80e552412ef60c1850b5955b6c940d.tar.gz dfhack-22b79bb46e80e552412ef60c1850b5955b6c940d.tar.bz2 dfhack-22b79bb46e80e552412ef60c1850b5955b6c940d.tar.xz | |
Now works on Windows again, some more cleanups, added a singleton Core object for holding all the globals.
Diffstat (limited to 'library/Process-windows.cpp')
| -rw-r--r-- | library/Process-windows.cpp | 436 |
1 files changed, 58 insertions, 378 deletions
diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index 8a8cd45f..543f7c70 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -31,309 +31,101 @@ distribution. #include <map> using namespace std; -#include "ProcessFactory.h" -#include "MicrosoftSTL.h" #include "dfhack/VersionInfo.h" -#include "dfhack/DFError.h" +#include "dfhack/VersionInfoFactory.h" +#include "dfhack/Error.h" +#include "dfhack/Process.h" using namespace DFHack; - -namespace +namespace DFHack { - class NormalProcess : public Process + class PlatformSpecific { - private: - VersionInfo * my_descriptor; - HANDLE my_handle; - vector <HANDLE> threads; - vector <HANDLE> stoppedthreads; - uint32_t my_pid; - string memFile; - bool attached; - bool suspended; - bool identified; - uint8_t vector_start; - IMAGE_NT_HEADERS pe_header; - IMAGE_SECTION_HEADER * sections; - uint32_t base; - MicrosoftSTL stl; - public: - NormalProcess(uint32_t pid, VersionInfoFactory * factory); - ~NormalProcess(); - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - void readQuad(const uint32_t address, uint64_t & value); - void writeQuad(const uint32_t address, const uint64_t value); - - void readDWord(const uint32_t address, uint32_t & value); - void writeDWord(const uint32_t address, const uint32_t value); - - void readFloat(const uint32_t address, float & value); - - void readWord(const uint32_t address, uint16_t & value); - void writeWord(const uint32_t address, const uint16_t value); - - void readByte(const uint32_t address, uint8_t & value); - void writeByte(const uint32_t address, const uint8_t value); - - void read( uint32_t address, uint32_t length, uint8_t* buffer); - void write(uint32_t address, uint32_t length, uint8_t* buffer); - - void readSTLVector(const uint32_t address, t_vecTriplet & triplet); - void writeSTLVector(const uint32_t address, t_vecTriplet & triplet); - const std::string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - size_t writeSTLString(const uint32_t address, const std::string writeString); - // get class name of an object with rtti/type info - std::string doReadClassName(uint32_t vptr); - - const std::string readCString (uint32_t offset); - - bool isSuspended(); - bool isAttached(); - bool isIdentified(); - - bool getThreadIDs(std::vector<uint32_t> & threads ); - void getMemRanges(std::vector<t_memrange> & ranges ); - VersionInfo *getDescriptor(); - int getPID(); - std::string getPath(); - // get module index by name and version. bool 1 = error - bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;}; - // get the SHM start if available - char * getSHMStart (void){return 0;}; - // set a SHM command and wait for a response - bool SetAndWait (uint32_t state){return false;}; + public: + PlatformSpecific() + { + base = 0; + sections = 0; + }; + HANDLE my_handle; + vector <HANDLE> threads; + vector <HANDLE> stoppedthreads; + uint32_t my_pid; + IMAGE_NT_HEADERS pe_header; + IMAGE_SECTION_HEADER * sections; + uint32_t base; }; - } - -Process* DFHack::createNormalProcess(uint32_t pid, VersionInfoFactory * factory) -{ - return new NormalProcess(pid, factory); -} - -NormalProcess::NormalProcess(uint32_t pid, VersionInfoFactory * factory) -: my_pid(pid) +Process::Process(VersionInfoFactory * factory) { - my_descriptor = NULL; - attached = false; - suspended = false; - base = 0; - sections = 0; - HMODULE hmod = NULL; DWORD needed; bool found = false; - identified = false; - // open process - my_handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, my_pid ); - if (NULL == my_handle) - return; + my_descriptor = NULL; + d = new PlatformSpecific(); + // open process + d->my_pid = GetCurrentProcessId(); + d->my_handle = GetCurrentProcess(); // try getting the first module of the process - if(EnumProcessModules(my_handle, &hmod, sizeof(hmod), &needed) == 0) + if(EnumProcessModules(d->my_handle, &hmod, sizeof(hmod), &needed) == 0) { - CloseHandle(my_handle); - my_handle=0; - // cout << "EnumProcessModules fail'd" << endl; return; //if enumprocessModules fails, give up } // got base ;) - base = (uint32_t)hmod; + d->base = (uint32_t)hmod; // read from this process try { - uint32_t pe_offset = Process::readDWord(base+0x3C); - read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); - const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * pe_header.FileHeader.NumberOfSections; - sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize); - read(base + pe_offset + sizeof(pe_header), sectionsSize, (uint8_t *)sections); + uint32_t pe_offset = Process::readDWord(d->base+0x3C); + read(d->base + pe_offset, sizeof(d->pe_header), (uint8_t *)&(d->pe_header)); + const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * d->pe_header.FileHeader.NumberOfSections; + d->sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize); + read(d->base + pe_offset + sizeof(d->pe_header), sectionsSize, (uint8_t *)(d->sections)); } catch (exception &) { - CloseHandle(my_handle); - my_handle = 0; return; } - //cout << "PE Timestamp: " << hex << pe_header.FileHeader.TimeDateStamp << dec << endl; - VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(pe_header.FileHeader.TimeDateStamp); + VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(d->pe_header.FileHeader.TimeDateStamp); if(vinfo) { - /* - cout << "Using version " << vinfo->getName() << ". Offsets follow:" << endl; - cout << "--------------------------------------------------------------" << endl; - cout << vinfo->PrintOffsets(); - cout << "--------------------------------------------------------------" << endl; - */ - // only enumerate threads if this is a valid DF process. the enumeration is costly. vector<uint32_t> threads_ids; if(!getThreadIDs( threads_ids )) { // thread enumeration failed. - CloseHandle(my_handle); - my_handle = 0; return; } identified = true; // give the process a data model and memory layout fixed for the base of first module my_descriptor = new VersionInfo(*vinfo); - my_descriptor->RebaseAll(base); + my_descriptor->RebaseAll(d->base); // keep track of created memory_info object so we can destroy it later my_descriptor->setParentProcess(this); - try - { - vector_start = my_descriptor->getGroup("vector")->getOffset("start"); - stl.init(this); - } - catch (DFHack::Error::UnsetMemoryDefinition &) - { - CloseHandle(my_handle); - my_handle = 0; - identified = false; - return; - } for(size_t i = 0; i < threads_ids.size();i++) { HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads_ids[i]); if(hThread) - threads.push_back(hThread); + d->threads.push_back(hThread); else cerr << "Unable to open thread :" << hex << (DWORD) threads_ids[i] << endl; } } - else - { - // close handles of processes that aren't DF - //cout << "ABOUT TO FREE HANDLE" << endl; - CloseHandle(my_handle); - //cout << "FREE'D HANDLE" << endl; - my_handle = 0; - } } -NormalProcess::~NormalProcess() +Process::~Process() { - if(attached) - { - detach(); - } // destroy our rebased copy of the memory descriptor delete my_descriptor; - if(my_handle != NULL) - { - CloseHandle(my_handle); - } - for(size_t i = 0; i < threads.size(); i++) - CloseHandle(threads[i]); - if(sections != NULL) - free(sections); + for(size_t i = 0; i < d->threads.size(); i++) + CloseHandle(d->threads[i]); + if(d->sections != NULL) + free(d->sections); } -VersionInfo * NormalProcess::getDescriptor() -{ - return my_descriptor; -} - -int NormalProcess::getPID() -{ - return my_pid; -} - -bool NormalProcess::isSuspended() -{ - return suspended; -} -bool NormalProcess::isAttached() -{ - return attached; -} - -bool NormalProcess::isIdentified() -{ - return identified; -} - -bool NormalProcess::asyncSuspend() -{ - return suspend(); -} - -bool NormalProcess::suspend() -{ - if(!attached) - return false; - if(suspended) - { - return true; - } - for(size_t i = 0; i < threads.size(); i++) - { - stoppedthreads.push_back(threads[i]); - SuspendThread(threads[i]); - } - suspended = true; - return true; -} - -bool NormalProcess::forceresume() -{ - if(!attached) - return false; - for(size_t i = 0; i < threads.size(); i++) - while (ResumeThread(threads[i]) > 1); - suspended = false; - return true; -} - - -bool NormalProcess::resume() -{ - if(!attached) - return false; - if(!suspended) - { - return true; - } - for(size_t i = 0; i < stoppedthreads.size(); i++) - ResumeThread(stoppedthreads[i]); - stoppedthreads.clear(); - suspended = false; - return true; -} - -bool NormalProcess::attach() -{ - if(attached) - { - if(!suspended) - return suspend(); - return true; - } - attached = true; - suspend(); - - return true; -} - - -bool NormalProcess::detach() -{ - if(!attached) return true; - resume(); - attached = false; - return true; -} - -bool NormalProcess::getThreadIDs(vector<uint32_t> & threads ) +bool Process::getThreadIDs(vector<uint32_t> & threads ) { HANDLE AllThreads = INVALID_HANDLE_VALUE; THREADENTRY32 te32; @@ -353,7 +145,7 @@ bool NormalProcess::getThreadIDs(vector<uint32_t> & threads ) do { - if( te32.th32OwnerProcessID == my_pid ) + if( te32.th32OwnerProcessID == d->my_pid ) { threads.push_back(te32.th32ThreadID); } @@ -402,7 +194,7 @@ void HeapNodes(DWORD pid, map<uint64_t, unsigned int> & heaps) } // FIXME: NEEDS TESTING! -void NormalProcess::getMemRanges( vector<t_memrange> & ranges ) +void Process::getMemRanges( vector<t_memrange> & ranges ) { MEMORY_BASIC_INFORMATION MBI; map<uint64_t, unsigned int> heaps; @@ -414,9 +206,9 @@ void NormalProcess::getMemRanges( vector<t_memrange> & ranges ) GetSystemInfo(&si); uint64_t PageSize = si.dwPageSize; // enumerate heaps - HeapNodes(my_pid, heaps); + HeapNodes(d->my_pid, heaps); // go through all the VM regions, convert them to our internal format - while (VirtualQueryEx(this->my_handle, (const void*) (movingStart), &MBI, sizeof(MBI)) == sizeof(MBI)) + while (VirtualQueryEx(d->my_handle, (const void*) (movingStart), &MBI, sizeof(MBI)) == sizeof(MBI)) { movingStart = ((uint64_t)MBI.BaseAddress + MBI.RegionSize); if(movingStart % PageSize != 0) @@ -431,7 +223,7 @@ void NormalProcess::getMemRanges( vector<t_memrange> & ranges ) temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE; temp.execute = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_EXECUTE; temp.valid = true; - if(!GetModuleBaseName(this->my_handle, (HMODULE) temp.start, temp.name, 1024)) + if(!GetModuleBaseName(d->my_handle, (HMODULE) temp.start, temp.name, 1024)) { if(nameMap.count(temp.start)) { @@ -452,26 +244,23 @@ void NormalProcess::getMemRanges( vector<t_memrange> & ranges ) } else temp.name[0]=0; } - - - } } else { // this is our executable! (could be generalized to pull segments from libs, but whatever) - if(base == temp.start) + if(d->base == temp.start) { - for(int i = 0; i < pe_header.FileHeader.NumberOfSections; i++) + for(int i = 0; i < d->pe_header.FileHeader.NumberOfSections; i++) { char sectionName[9]; - memcpy(sectionName,sections[i].Name,8); + memcpy(sectionName,d->sections[i].Name,8); sectionName[8] = 0; string nm; nm.append(temp.name); nm.append(" : "); nm.append(sectionName); - nameMap[temp.start + sections[i].VirtualAddress] = nm; + nameMap[temp.start + d->sections[i].VirtualAddress] = nm; } } else @@ -481,131 +270,22 @@ void NormalProcess::getMemRanges( vector<t_memrange> & ranges ) } } -void NormalProcess::readByte (const uint32_t offset,uint8_t &result) -{ - if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint8_t), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -void NormalProcess::readWord (const uint32_t offset, uint16_t &result) -{ - if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint16_t), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -void NormalProcess::readDWord (const uint32_t offset, uint32_t &result) -{ - if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint32_t), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -void NormalProcess::readQuad (const uint32_t offset, uint64_t &result) -{ - if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint64_t), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -void NormalProcess::readFloat (const uint32_t offset, float &result) -{ - if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(float), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -void NormalProcess::read (const uint32_t offset, uint32_t size, uint8_t *target) -{ - if(!ReadProcessMemory(my_handle, (int*) offset, target, size, NULL)) - throw Error::MemoryAccessDenied(offset); -} - -// WRITING -void NormalProcess::writeQuad (const uint32_t offset, uint64_t data) -{ - if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -void NormalProcess::writeDWord (const uint32_t offset, uint32_t data) -{ - if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -// using these is expensive. -void NormalProcess::writeWord (uint32_t offset, uint16_t data) -{ - if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -void NormalProcess::writeByte (uint32_t offset, uint8_t data) -{ - if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL)) - throw Error::MemoryAccessDenied(offset); -} - -void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) -{ - if(!WriteProcessMemory(my_handle, (int*) offset, source, size, NULL)) - throw Error::MemoryAccessDenied(offset); -} - -// FIXME: could exploit the fact we can read more than one byte... but still, this is almost unused. -const std::string NormalProcess::readCString (const uint32_t offset) -{ - std::string temp; - int counter = 0; - char r; - while (1) - { - if(!ReadProcessMemory(my_handle, (int*) (offset + counter), &r, sizeof(uint8_t), NULL)) break; - r = Process::readByte(offset+counter); - // order is important. even if the first character is \0, we cound that as a success. It's an empty string. - counter++; - if(!r) break; - temp.append(1,r); - } - if(!counter) - throw Error::MemoryAccessDenied(offset); - return temp; -} - -void NormalProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet) -{ - read(address + vector_start, sizeof(triplet), (uint8_t *) &triplet); -} - -void NormalProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet) -{ - write(address + vector_start, sizeof(triplet), (uint8_t *) &triplet); -} - -size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) -{ - return stl.readSTLString(offset, buffer, bufcapacity); -} - -const string NormalProcess::readSTLString (uint32_t offset) -{ - return stl.readSTLString(offset); -} - -size_t NormalProcess::writeSTLString (uint32_t address, string str) -{ - return stl.writeSTLString(address, str); -} - -string NormalProcess::doReadClassName (uint32_t vptr) +string Process::doReadClassName (uint32_t vptr) { - return stl.readClassName(vptr); + int rtti = readDWord(vptr - 0x4); + int typeinfo = readDWord(rtti + 0xC); + string raw = readCString(typeinfo + 0xC); // skips the .?AV + raw.resize(raw.length() - 2);// trim @@ from end + return raw; } -string NormalProcess::getPath() +string Process::getPath() { HMODULE hmod; DWORD junk; char String[255]; - EnumProcessModules(my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle - GetModuleFileNameEx(my_handle,hmod,String,sizeof(String)); //get the filename from the module + EnumProcessModules(d->my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle + GetModuleFileNameEx(d->my_handle,hmod,String,sizeof(String)); //get the filename from the module string out(String); return(out.substr(0,out.find_last_of("\\"))); } |
