2009-10-04 07:08:20 -06:00
|
|
|
/*
|
2011-06-12 15:17:40 -06:00
|
|
|
https://github.com/peterix/dfhack
|
2012-09-29 20:03:37 -06:00
|
|
|
Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com)
|
2009-10-04 07:08:20 -06:00
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any
|
|
|
|
damages arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any
|
|
|
|
purpose, including commercial applications, and to alter it and
|
|
|
|
redistribute it freely, subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must
|
|
|
|
not claim that you wrote the original software. If you use this
|
|
|
|
software in a product, an acknowledgment in the product documentation
|
|
|
|
would be appreciated but is not required.
|
|
|
|
|
|
|
|
2. Altered source versions must be plainly marked as such, and
|
|
|
|
must not be misrepresented as being the original software.
|
|
|
|
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
|
|
distribution.
|
|
|
|
*/
|
|
|
|
|
2011-06-16 15:53:39 -06:00
|
|
|
|
2011-04-10 05:12:28 -06:00
|
|
|
#pragma once
|
|
|
|
|
2009-11-16 20:19:13 -07:00
|
|
|
#ifndef PROCESS_H_INCLUDED
|
|
|
|
#define PROCESS_H_INCLUDED
|
2009-10-04 07:08:20 -06:00
|
|
|
|
2011-12-31 04:48:42 -07:00
|
|
|
#include "Pragma.h"
|
|
|
|
#include "Export.h"
|
2010-03-14 18:26:32 -06:00
|
|
|
#include <iostream>
|
2011-06-12 15:17:40 -06:00
|
|
|
#include <cstring>
|
2011-05-09 03:48:54 -06:00
|
|
|
#include <map>
|
2018-07-08 12:19:19 -06:00
|
|
|
#include <memory>
|
2009-11-14 21:25:00 -07:00
|
|
|
|
2018-07-08 16:50:14 -06:00
|
|
|
#include "VersionInfo.h"
|
|
|
|
|
2009-11-13 20:46:56 -07:00
|
|
|
namespace DFHack
|
2009-10-04 07:08:20 -06:00
|
|
|
{
|
2009-11-13 20:46:56 -07:00
|
|
|
class Process;
|
2011-11-25 10:54:50 -07:00
|
|
|
//class Window;
|
2011-03-24 23:40:33 -06:00
|
|
|
class DFVector;
|
2011-06-12 15:17:40 -06:00
|
|
|
class VersionInfoFactory;
|
2011-06-14 08:13:28 -06:00
|
|
|
class PlatformSpecific;
|
2011-06-17 07:02:43 -06:00
|
|
|
|
2011-03-18 01:53:59 -06:00
|
|
|
/**
|
|
|
|
* Structure describing a section of virtual memory inside a process
|
|
|
|
* \ingroup grp_context
|
|
|
|
*/
|
2009-11-14 21:25:00 -07:00
|
|
|
struct DFHACK_EXPORT t_memrange
|
|
|
|
{
|
2012-01-03 17:45:11 -07:00
|
|
|
void * start;
|
|
|
|
void * end;
|
2009-11-14 21:25:00 -07:00
|
|
|
// memory range name (if any)
|
|
|
|
char name[1024];
|
|
|
|
// permission to read
|
2011-02-27 01:48:08 -07:00
|
|
|
bool read : 1;
|
2009-11-14 21:25:00 -07:00
|
|
|
// permission to write
|
2011-02-27 01:48:08 -07:00
|
|
|
bool write : 1;
|
2009-11-14 21:25:00 -07:00
|
|
|
// permission to execute
|
2011-02-27 01:48:08 -07:00
|
|
|
bool execute : 1;
|
2011-03-19 23:20:23 -06:00
|
|
|
// is a shared region
|
|
|
|
bool shared : 1;
|
2012-01-03 17:45:11 -07:00
|
|
|
inline bool isInRange( void * address)
|
2009-11-14 21:25:00 -07:00
|
|
|
{
|
2011-02-27 01:48:08 -07:00
|
|
|
if (address >= start && address < end) return true;
|
2009-11-14 21:25:00 -07:00
|
|
|
return false;
|
|
|
|
}
|
2011-02-13 19:58:32 -07:00
|
|
|
bool valid;
|
2010-05-29 21:13:59 -06:00
|
|
|
uint8_t * buffer;
|
2009-11-14 21:25:00 -07:00
|
|
|
};
|
2011-05-09 03:48:54 -06:00
|
|
|
|
2011-03-18 01:53:59 -06:00
|
|
|
/**
|
2011-06-19 17:12:07 -06:00
|
|
|
* Allows low-level access to the memory of an OS process.
|
2011-03-18 01:53:59 -06:00
|
|
|
* \ingroup grp_context
|
|
|
|
*/
|
2009-11-14 21:25:00 -07:00
|
|
|
class DFHACK_EXPORT Process
|
2009-12-22 14:19:39 -07:00
|
|
|
{
|
2010-02-12 17:47:08 -07:00
|
|
|
public:
|
2010-05-29 21:13:59 -06:00
|
|
|
/// this is the single most important destructor ever. ~px
|
2018-07-08 16:50:14 -06:00
|
|
|
Process(const VersionInfoFactory& known_versions);
|
2011-06-12 15:17:40 -06:00
|
|
|
~Process();
|
2010-05-29 21:13:59 -06:00
|
|
|
/// read a 8-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
uint64_t readQuad(const void * address)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
return *(uint64_t *)address;
|
|
|
|
}
|
2010-05-29 21:13:59 -06:00
|
|
|
/// read a 8-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
void readQuad(const void * address, uint64_t & value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
value = *(uint64_t *)address;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
/// write a 8-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
void writeQuad(const void * address, const uint64_t value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
(*(uint64_t *)address) = value;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
|
|
|
|
/// read a 4-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
uint32_t readDWord(const void * address)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
return *(uint32_t *)address;
|
|
|
|
}
|
2010-05-29 21:13:59 -06:00
|
|
|
/// read a 4-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
void readDWord(const void * address, uint32_t & value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
value = *(uint32_t *)address;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
/// write a 4-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
void writeDWord(const void * address, const uint32_t value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
(*(uint32_t *)address) = value;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
|
2012-01-03 17:45:11 -07:00
|
|
|
/// read a pointer
|
2012-01-05 15:39:14 -07:00
|
|
|
char * readPtr(const void * address)
|
2012-01-03 17:45:11 -07:00
|
|
|
{
|
2012-01-05 15:39:14 -07:00
|
|
|
return *(char **)address;
|
2012-01-03 17:45:11 -07:00
|
|
|
}
|
|
|
|
/// read a pointer
|
2012-01-05 15:39:14 -07:00
|
|
|
void readPtr(const void * address, char * & value)
|
2012-01-03 17:45:11 -07:00
|
|
|
{
|
2012-01-05 15:39:14 -07:00
|
|
|
value = *(char **)address;
|
2012-01-03 17:45:11 -07:00
|
|
|
};
|
|
|
|
|
2010-05-29 21:13:59 -06:00
|
|
|
/// read a float
|
2012-01-03 17:45:11 -07:00
|
|
|
float readFloat(const void * address)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
return *(float*)address;
|
|
|
|
}
|
2010-05-29 21:13:59 -06:00
|
|
|
/// write a float
|
2012-01-03 17:45:11 -07:00
|
|
|
void readFloat(const void * address, float & value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
value = *(float*)address;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
|
|
|
|
/// read a 2-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
uint16_t readWord(const void * address)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
return *(uint16_t *)address;
|
|
|
|
}
|
2010-05-29 21:13:59 -06:00
|
|
|
/// read a 2-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
void readWord(const void * address, uint16_t & value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
value = *(uint16_t *)address;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
/// write a 2-byte integer
|
2012-01-03 17:45:11 -07:00
|
|
|
void writeWord(const void * address, const uint16_t value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
(*(uint16_t *)address) = value;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
|
|
|
|
/// read a byte
|
2012-01-03 17:45:11 -07:00
|
|
|
uint8_t readByte(const void * address)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
return *(uint8_t *)address;
|
|
|
|
}
|
2010-05-29 21:13:59 -06:00
|
|
|
/// read a byte
|
2012-01-03 17:45:11 -07:00
|
|
|
void readByte(const void * address, uint8_t & value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
value = *(uint8_t *)address;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
/// write a byte
|
2012-01-03 17:45:11 -07:00
|
|
|
void writeByte(const void * address, const uint8_t value)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
(*(uint8_t *)address) = value;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
|
|
|
|
/// read an arbitrary amount of bytes
|
2012-01-03 17:45:11 -07:00
|
|
|
void read(void * address, uint32_t length, uint8_t* buffer)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
memcpy(buffer, (void *) address, length);
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
/// write an arbitrary amount of bytes
|
2012-01-03 17:45:11 -07:00
|
|
|
void write(void * address, uint32_t length, uint8_t* buffer)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
memcpy((void *) address, buffer, length);
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
|
|
|
|
/// read an STL string
|
2012-01-03 17:45:11 -07:00
|
|
|
const std::string readSTLString (void * offset)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
std::string * str = (std::string *) offset;
|
|
|
|
return *str;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
/// read an STL string
|
2012-01-03 17:45:11 -07:00
|
|
|
size_t readSTLString (void * offset, char * buffer, size_t bufcapacity)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
if(!bufcapacity || bufcapacity == 1)
|
|
|
|
return 0;
|
|
|
|
std::string * str = (std::string *) offset;
|
2011-06-14 08:13:28 -06:00
|
|
|
size_t copied = str->copy(buffer,bufcapacity-1);
|
|
|
|
buffer[copied] = 0;
|
|
|
|
return copied;
|
2011-06-12 15:17:40 -06:00
|
|
|
};
|
2011-04-19 17:28:47 -06:00
|
|
|
/**
|
|
|
|
* write an STL string
|
|
|
|
* @return length written
|
|
|
|
*/
|
2012-01-03 17:45:11 -07:00
|
|
|
size_t writeSTLString(const void * address, const std::string writeString)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
std::string * str = (std::string *) address;
|
|
|
|
str->assign(writeString);
|
|
|
|
return writeString.size();
|
|
|
|
};
|
2011-04-19 17:28:47 -06:00
|
|
|
/**
|
|
|
|
* attempt to copy a string from source address to target address. may truncate or leak, depending on platform
|
|
|
|
* @return length copied
|
|
|
|
*/
|
2016-07-28 09:00:52 -06:00
|
|
|
size_t copySTLString(const void * address, const uintptr_t target)
|
2011-04-19 17:28:47 -06:00
|
|
|
{
|
2011-06-12 15:17:40 -06:00
|
|
|
std::string * strsrc = (std::string *) address;
|
|
|
|
std::string * str = (std::string *) target;
|
|
|
|
str->assign(*strsrc);
|
|
|
|
return str->size();
|
2011-04-13 10:36:10 -06:00
|
|
|
}
|
2011-04-19 17:28:47 -06:00
|
|
|
|
2010-05-29 21:13:59 -06:00
|
|
|
/// get class name of an object with rtti/type info
|
2011-07-06 23:00:36 -06:00
|
|
|
std::string doReadClassName(void * vptr);
|
2011-05-09 03:48:54 -06:00
|
|
|
|
2011-07-06 23:00:36 -06:00
|
|
|
std::string readClassName(void * vptr)
|
2011-05-15 14:24:40 -06:00
|
|
|
{
|
2011-07-06 23:00:36 -06:00
|
|
|
std::map<void *, std::string>::iterator it = classNameCache.find(vptr);
|
2011-05-09 03:48:54 -06:00
|
|
|
if (it != classNameCache.end())
|
|
|
|
return it->second;
|
|
|
|
return classNameCache[vptr] = doReadClassName(vptr);
|
|
|
|
}
|
2010-05-29 21:13:59 -06:00
|
|
|
|
|
|
|
/// read a null-terminated C string
|
2012-01-03 17:45:11 -07:00
|
|
|
const std::string readCString (void * offset)
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
|
|
|
return std::string((char *) offset);
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
|
|
|
|
/// @return true if the process is suspended
|
2011-06-12 15:17:40 -06:00
|
|
|
bool isSuspended()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
};
|
2012-02-11 11:24:44 -07:00
|
|
|
/// @return true if the process is identified -- has a symbol table extension
|
2011-06-12 15:17:40 -06:00
|
|
|
bool isIdentified()
|
|
|
|
{
|
|
|
|
return identified;
|
|
|
|
};
|
2010-05-29 21:13:59 -06:00
|
|
|
/// get virtual memory ranges of the process (what is mapped where)
|
2011-06-12 15:17:40 -06:00
|
|
|
void getMemRanges(std::vector<t_memrange> & ranges );
|
2010-05-29 21:13:59 -06:00
|
|
|
|
2012-02-11 11:24:44 -07:00
|
|
|
/// get the symbol table extension of this process
|
2018-07-08 16:50:14 -06:00
|
|
|
std::shared_ptr<DFHack::VersionInfo> getDescriptor()
|
2011-06-12 15:17:40 -06:00
|
|
|
{
|
2018-07-08 16:50:14 -06:00
|
|
|
return my_descriptor;
|
|
|
|
};
|
|
|
|
|
|
|
|
void ValidateDescriptionOS() {
|
2020-02-03 19:21:10 -07:00
|
|
|
if (my_descriptor)
|
|
|
|
my_descriptor->ValidateOS();
|
2011-06-12 15:17:40 -06:00
|
|
|
};
|
2018-07-08 16:50:14 -06:00
|
|
|
|
2012-11-11 04:49:01 -07:00
|
|
|
uintptr_t getBase();
|
2010-05-29 21:13:59 -06:00
|
|
|
/// get the DF Process ID
|
2011-06-12 15:17:40 -06:00
|
|
|
int getPID();
|
2010-09-12 19:36:31 -06:00
|
|
|
/// get the DF Process FilePath
|
2011-06-12 15:17:40 -06:00
|
|
|
std::string getPath();
|
2012-11-11 04:49:01 -07:00
|
|
|
/// Adjust between in-memory and in-file image offset
|
|
|
|
int adjustOffset(int offset, bool to_file = false);
|
2011-07-27 16:00:12 -06:00
|
|
|
|
2012-09-05 09:45:45 -06:00
|
|
|
/// millisecond tick count, exactly as DF uses
|
|
|
|
uint32_t getTickCount();
|
|
|
|
|
2012-02-11 11:24:44 -07:00
|
|
|
/// modify permisions of memory range
|
|
|
|
bool setPermisions(const t_memrange & range,const t_memrange &trgrange);
|
2012-08-17 04:32:04 -06:00
|
|
|
|
|
|
|
/// write a possibly read-only memory area
|
|
|
|
bool patchMemory(void *target, const void* src, size_t count);
|
2012-11-12 11:18:03 -07:00
|
|
|
|
|
|
|
/// allocate new memory pages for code or stuff
|
|
|
|
/// returns -1 on error (0 is a valid address)
|
|
|
|
void* memAlloc(const int length);
|
|
|
|
|
|
|
|
/// free memory pages from memAlloc
|
|
|
|
/// should have length = alloced length for portability
|
|
|
|
/// returns 0 on success
|
|
|
|
int memDealloc(void *ptr, const int length);
|
|
|
|
|
|
|
|
/// change memory page permissions
|
|
|
|
/// prot is a bitwise OR of the MemProt enum
|
|
|
|
/// returns 0 on success
|
|
|
|
int memProtect(void *ptr, const int length, const int prot);
|
|
|
|
|
|
|
|
enum MemProt {
|
|
|
|
READ = 1,
|
|
|
|
WRITE = 2,
|
|
|
|
EXEC = 4
|
|
|
|
};
|
|
|
|
|
2015-12-27 12:59:18 -07:00
|
|
|
uint32_t getPE() { return my_pe; }
|
|
|
|
std::string getMD5() { return my_md5; }
|
|
|
|
|
2011-06-12 15:17:40 -06:00
|
|
|
private:
|
2018-07-08 16:50:14 -06:00
|
|
|
std::shared_ptr<VersionInfo> my_descriptor;
|
2011-06-14 08:13:28 -06:00
|
|
|
PlatformSpecific *d;
|
2011-06-12 15:17:40 -06:00
|
|
|
bool identified;
|
2011-06-14 08:13:28 -06:00
|
|
|
uint32_t my_pid;
|
|
|
|
uint32_t base;
|
2011-07-06 23:00:36 -06:00
|
|
|
std::map<void *, std::string> classNameCache;
|
2015-12-27 12:59:18 -07:00
|
|
|
uint32_t my_pe;
|
|
|
|
std::string my_md5;
|
2010-03-09 07:15:15 -07:00
|
|
|
};
|
|
|
|
|
2011-05-14 21:19:51 -06:00
|
|
|
class DFHACK_EXPORT ClassNameCheck
|
2011-05-15 13:50:20 -06:00
|
|
|
{
|
2011-05-09 03:48:54 -06:00
|
|
|
std::string name;
|
2011-07-06 23:00:36 -06:00
|
|
|
mutable void * vptr;
|
2011-07-24 22:24:34 -06:00
|
|
|
|
2011-05-09 03:48:54 -06:00
|
|
|
public:
|
2011-07-24 22:24:34 -06:00
|
|
|
ClassNameCheck() : vptr(0) {}
|
|
|
|
ClassNameCheck(std::string _name);
|
|
|
|
ClassNameCheck &operator= (const ClassNameCheck &b);
|
|
|
|
|
|
|
|
// Is the class name of the given virtual table pointer the same as the
|
|
|
|
// name for thei ClassNameCheck object?
|
|
|
|
bool operator() (Process *p, void * ptr) const;
|
|
|
|
|
|
|
|
// Get list of names given to ClassNameCheck constructors.
|
|
|
|
static void getKnownClassNames(std::vector<std::string> &names);
|
2011-05-09 03:48:54 -06:00
|
|
|
};
|
2012-10-27 11:58:40 -06:00
|
|
|
|
|
|
|
class DFHACK_EXPORT MemoryPatcher
|
|
|
|
{
|
|
|
|
Process *p;
|
|
|
|
std::vector<t_memrange> ranges, save;
|
|
|
|
public:
|
|
|
|
MemoryPatcher(Process *p = NULL);
|
|
|
|
~MemoryPatcher();
|
|
|
|
|
|
|
|
bool verifyAccess(void *target, size_t size, bool write = false);
|
|
|
|
bool makeWritable(void *target, size_t size) {
|
|
|
|
return verifyAccess(target, size, true);
|
|
|
|
}
|
|
|
|
bool write(void *target, const void *src, size_t size);
|
|
|
|
|
|
|
|
void close();
|
|
|
|
};
|
2009-11-13 20:46:56 -07:00
|
|
|
}
|
2009-12-13 14:03:19 -07:00
|
|
|
#endif
|