1
0
Fork 0

PROJECT: fixed line endings (hopefully for good now)

This commit is contained in:
mrexodia 2015-11-24 01:50:17 +01:00
parent 6508104c81
commit 1731e1dee5
363 changed files with 80868 additions and 80868 deletions

Binary file not shown.

View File

@ -1,326 +1,326 @@
#ifndef _UTF8INI_H
#define _UTF8INI_H
#include <string>
#include <map>
#include <vector>
class Utf8Ini
{
public:
/**
\brief Serialize to the INI file format.
*/
inline std::string Serialize() const
{
std::string output;
for(const auto & section : _sections)
{
if(output.length())
appendLine(output, "");
appendLine(output, makeSectionText(section.first));
for(const auto & keyvalue : section.second)
if(keyvalue.first.length())
appendLine(output, makeKeyValueText(keyvalue.first, keyvalue.second));
}
return output;
}
/**
\brief Deserialize from the INI file format.
\param data The INI data.
\param [out] errorLine The error line (only has a meaning when this function failed).
\return true if it succeeds, false if it fails.
*/
inline bool Deserialize(const std::string & data, int & errorLine)
{
//initialize
errorLine = 0;
Clear();
//read lines
std::vector<std::string> lines;
std::string curLine;
for(auto ch : data)
{
switch(ch)
{
case '\r':
break;
case '\n':
lines.push_back(trim(curLine));
curLine.clear();
break;
default:
curLine += ch;
}
}
if(curLine.length())
lines.push_back(trim(curLine));
//parse lines
std::string section = "";
for(const auto & line : lines)
{
errorLine++;
switch(getLineType(line))
{
case LineType::Invalid:
MessageBoxA(0, line.c_str(), "line", 0);
return false;
case LineType::Comment:
case LineType::Empty:
continue;
case LineType::KeyValue:
{
std::string key;
std::string value;
if(!section.length() ||
!parseKeyValueLine(line, key, value) ||
!SetValue(section, key, value))
return false;
}
break;
case LineType::Section:
if(!parseSectionLine(line, section))
return false;
}
}
return true;
}
/**
\brief Sets a value. This will overwrite older values.
\param section The section. Must have a length greater than one.
\param key The key. Must have a length greater than one.
\param value The value. Can be empty (effectively removing the value).
\return true if the value was set successfully, false otherwise.
*/
inline bool SetValue(const std::string & section, const std::string & key, const std::string & value)
{
auto trimmedSection = trim(section);
auto trimmedKey = trim(key);
if(!trimmedSection.length() || !trimmedKey.length())
return false;
auto found = _sections.find(trimmedSection);
if(found != _sections.end())
found->second[trimmedKey] = value;
else
{
KeyValueMap keyValueMap;
keyValueMap[trimmedKey] = value;
_sections[trimmedSection] = keyValueMap;
}
return true;
}
/**
\brief Removes all key/value pairs from a section.
\param section The section to clear.
\return true if it succeeds, false otherwise.
*/
inline bool ClearSection(const std::string & section)
{
auto trimmedSection = trim(section);
if(!trimmedSection.length())
return false;
auto found = _sections.find(trimmedSection);
if(found == _sections.end())
return false;
_sections.erase(found);
return true;
}
/**
\brief Removes all sections.
*/
inline void Clear()
{
_sections.clear();
}
/**
\brief Gets a value.
\param section The section.
\param key The key.
\param [in,out] value The value.
\return The value. Empty string when the value was not found or empty.
*/
inline std::string GetValue(const std::string & section, const std::string & key) const
{
auto trimmedSection = trim(section);
auto trimmedKey = trim(key);
if(!trimmedSection.length() || !trimmedKey.length())
return "";
auto sectionFound = _sections.find(trimmedSection);
if(sectionFound == _sections.end())
return "";
const auto & keyValueMap = sectionFound->second;
auto keyFound = keyValueMap.find(trimmedKey);
if(keyFound == keyValueMap.end())
return "";
return keyFound->second;
}
private:
typedef std::map<std::string, std::string> KeyValueMap;
std::map<std::string, KeyValueMap> _sections;
enum class LineType
{
Invalid,
Empty,
Section,
KeyValue,
Comment
};
static inline LineType getLineType(const std::string & line)
{
auto len = line.length();
if(!len)
return LineType::Empty;
if(line[0] == '[' && line[len - 1] == ']')
return LineType::Section;
if(line[0] == ';')
return LineType::Comment;
if(line.find('=') != std::string::npos)
return LineType::KeyValue;
return LineType::Invalid;
}
static inline std::string trim(const std::string & str)
{
auto len = str.length();
if(!len)
return "";
size_t pre = 0;
while(str[pre] == ' ')
pre++;
size_t post = 0;
while(str[len - post - 1] == ' ' && post < len)
post++;
auto sublen = len - post - pre;
return sublen > 0 ? str.substr(pre, len - post - pre) : "";
}
static inline bool parseKeyValueLine(const std::string & line, std::string & key, std::string & value)
{
auto pos = line.find('=');
key = trim(line.substr(0, pos));
value = trim(line.substr(pos + 1));
auto len = value.length();
if(len && value[0] == '\"' && value[len - 1] == '\"')
value = unescapeValue(value);
return true;
}
static inline bool parseSectionLine(const std::string & line, std::string & section)
{
section = trim(line.substr(1, line.length() - 2));
return section.length() > 0;
}
static inline void appendLine(std::string & output, const std::string & line)
{
if(output.length())
output += "\r\n";
output += line;
}
static inline std::string makeSectionText(const std::string & section)
{
return "[" + section + "]";
}
static inline std::string makeKeyValueText(const std::string & key, const std::string & value)
{
return key + "=" + escapeValue(value);
}
static inline bool needsEscaping(const std::string & value)
{
auto len = value.length();
return len && (value[0] == ' ' || value[len - 1] == ' ' ||
value.find('\n') != std::string::npos ||
value.find('\"') != std::string::npos);
}
static inline std::string escapeValue(const std::string & value)
{
if(!needsEscaping(value))
return value;
std::string escaped = "\"";
for(auto ch : value)
{
switch(ch)
{
case '\"':
escaped += "\\\"";
break;
case '\\':
escaped += "\\\\";
break;
case '\r':
escaped += "\\r";
break;
case '\n':
escaped += "\\n";
break;
case '\t':
escaped += "\\t";
default:
escaped += ch;
}
}
return escaped + "\"";
}
static inline std::string unescapeValue(const std::string & str)
{
std::string result;
bool bEscaped = false;
for(auto ch : str)
{
if(!bEscaped)
{
switch(ch)
{
case '\"':
break;
case '\\':
bEscaped = true;
break;
default:
result += ch;
}
}
else
{
switch(ch)
{
case 'r':
result += '\r';
break;
case 'n':
result += '\n';
break;
case 't':
result += '\t';
break;
default:
result += ch;
}
bEscaped = false;
}
}
if(bEscaped)
result += '\\';
return result;
}
};
#ifndef _UTF8INI_H
#define _UTF8INI_H
#include <string>
#include <map>
#include <vector>
class Utf8Ini
{
public:
/**
\brief Serialize to the INI file format.
*/
inline std::string Serialize() const
{
std::string output;
for(const auto & section : _sections)
{
if(output.length())
appendLine(output, "");
appendLine(output, makeSectionText(section.first));
for(const auto & keyvalue : section.second)
if(keyvalue.first.length())
appendLine(output, makeKeyValueText(keyvalue.first, keyvalue.second));
}
return output;
}
/**
\brief Deserialize from the INI file format.
\param data The INI data.
\param [out] errorLine The error line (only has a meaning when this function failed).
\return true if it succeeds, false if it fails.
*/
inline bool Deserialize(const std::string & data, int & errorLine)
{
//initialize
errorLine = 0;
Clear();
//read lines
std::vector<std::string> lines;
std::string curLine;
for(auto ch : data)
{
switch(ch)
{
case '\r':
break;
case '\n':
lines.push_back(trim(curLine));
curLine.clear();
break;
default:
curLine += ch;
}
}
if(curLine.length())
lines.push_back(trim(curLine));
//parse lines
std::string section = "";
for(const auto & line : lines)
{
errorLine++;
switch(getLineType(line))
{
case LineType::Invalid:
MessageBoxA(0, line.c_str(), "line", 0);
return false;
case LineType::Comment:
case LineType::Empty:
continue;
case LineType::KeyValue:
{
std::string key;
std::string value;
if(!section.length() ||
!parseKeyValueLine(line, key, value) ||
!SetValue(section, key, value))
return false;
}
break;
case LineType::Section:
if(!parseSectionLine(line, section))
return false;
}
}
return true;
}
/**
\brief Sets a value. This will overwrite older values.
\param section The section. Must have a length greater than one.
\param key The key. Must have a length greater than one.
\param value The value. Can be empty (effectively removing the value).
\return true if the value was set successfully, false otherwise.
*/
inline bool SetValue(const std::string & section, const std::string & key, const std::string & value)
{
auto trimmedSection = trim(section);
auto trimmedKey = trim(key);
if(!trimmedSection.length() || !trimmedKey.length())
return false;
auto found = _sections.find(trimmedSection);
if(found != _sections.end())
found->second[trimmedKey] = value;
else
{
KeyValueMap keyValueMap;
keyValueMap[trimmedKey] = value;
_sections[trimmedSection] = keyValueMap;
}
return true;
}
/**
\brief Removes all key/value pairs from a section.
\param section The section to clear.
\return true if it succeeds, false otherwise.
*/
inline bool ClearSection(const std::string & section)
{
auto trimmedSection = trim(section);
if(!trimmedSection.length())
return false;
auto found = _sections.find(trimmedSection);
if(found == _sections.end())
return false;
_sections.erase(found);
return true;
}
/**
\brief Removes all sections.
*/
inline void Clear()
{
_sections.clear();
}
/**
\brief Gets a value.
\param section The section.
\param key The key.
\param [in,out] value The value.
\return The value. Empty string when the value was not found or empty.
*/
inline std::string GetValue(const std::string & section, const std::string & key) const
{
auto trimmedSection = trim(section);
auto trimmedKey = trim(key);
if(!trimmedSection.length() || !trimmedKey.length())
return "";
auto sectionFound = _sections.find(trimmedSection);
if(sectionFound == _sections.end())
return "";
const auto & keyValueMap = sectionFound->second;
auto keyFound = keyValueMap.find(trimmedKey);
if(keyFound == keyValueMap.end())
return "";
return keyFound->second;
}
private:
typedef std::map<std::string, std::string> KeyValueMap;
std::map<std::string, KeyValueMap> _sections;
enum class LineType
{
Invalid,
Empty,
Section,
KeyValue,
Comment
};
static inline LineType getLineType(const std::string & line)
{
auto len = line.length();
if(!len)
return LineType::Empty;
if(line[0] == '[' && line[len - 1] == ']')
return LineType::Section;
if(line[0] == ';')
return LineType::Comment;
if(line.find('=') != std::string::npos)
return LineType::KeyValue;
return LineType::Invalid;
}
static inline std::string trim(const std::string & str)
{
auto len = str.length();
if(!len)
return "";
size_t pre = 0;
while(str[pre] == ' ')
pre++;
size_t post = 0;
while(str[len - post - 1] == ' ' && post < len)
post++;
auto sublen = len - post - pre;
return sublen > 0 ? str.substr(pre, len - post - pre) : "";
}
static inline bool parseKeyValueLine(const std::string & line, std::string & key, std::string & value)
{
auto pos = line.find('=');
key = trim(line.substr(0, pos));
value = trim(line.substr(pos + 1));
auto len = value.length();
if(len && value[0] == '\"' && value[len - 1] == '\"')
value = unescapeValue(value);
return true;
}
static inline bool parseSectionLine(const std::string & line, std::string & section)
{
section = trim(line.substr(1, line.length() - 2));
return section.length() > 0;
}
static inline void appendLine(std::string & output, const std::string & line)
{
if(output.length())
output += "\r\n";
output += line;
}
static inline std::string makeSectionText(const std::string & section)
{
return "[" + section + "]";
}
static inline std::string makeKeyValueText(const std::string & key, const std::string & value)
{
return key + "=" + escapeValue(value);
}
static inline bool needsEscaping(const std::string & value)
{
auto len = value.length();
return len && (value[0] == ' ' || value[len - 1] == ' ' ||
value.find('\n') != std::string::npos ||
value.find('\"') != std::string::npos);
}
static inline std::string escapeValue(const std::string & value)
{
if(!needsEscaping(value))
return value;
std::string escaped = "\"";
for(auto ch : value)
{
switch(ch)
{
case '\"':
escaped += "\\\"";
break;
case '\\':
escaped += "\\\\";
break;
case '\r':
escaped += "\\r";
break;
case '\n':
escaped += "\\n";
break;
case '\t':
escaped += "\\t";
default:
escaped += ch;
}
}
return escaped + "\"";
}
static inline std::string unescapeValue(const std::string & str)
{
std::string result;
bool bEscaped = false;
for(auto ch : str)
{
if(!bEscaped)
{
switch(ch)
{
case '\"':
break;
case '\\':
bEscaped = true;
break;
default:
result += ch;
}
}
else
{
switch(ch)
{
case 'r':
result += '\r';
break;
case 'n':
result += '\n';
break;
case 't':
result += '\t';
break;
default:
result += ch;
}
bEscaped = false;
}
}
if(bEscaped)
result += '\\';
return result;
}
};
#endif //_UTF8INI_H

View File

@ -1,26 +1,26 @@
#include "_global.h"
GUIGUIINIT _gui_guiinit;
GUISENDMESSAGE _gui_sendmessage;
GUISENDMESSAGEASYNC _gui_sendmessageasync;
DBGDBGINIT _dbg_dbginit;
DBGMEMFINDBASEADDR _dbg_memfindbaseaddr;
DBGMEMREAD _dbg_memread;
DBGMEMWRITE _dbg_memwrite;
DBGDBGCMDEXEC _dbg_dbgcmdexec;
DBGMEMMAP _dbg_memmap;
DBGDBGEXITSIGNAL _dbg_dbgexitsignal;
DBGVALFROMSTRING _dbg_valfromstring;
DBGISDEBUGGING _dbg_isdebugging;
DBGISJUMPGOINGTOEXECUTE _dbg_isjumpgoingtoexecute;
DBGADDRINFOGET _dbg_addrinfoget;
DBGADDRINFOSET _dbg_addrinfoset;
DBGBPGETTYPEAT _dbg_bpgettypeat;
DBGGETREGDUMP _dbg_getregdump;
DBGVALTOSTRING _dbg_valtostring;
DBGMEMISVALIDREADPTR _dbg_memisvalidreadptr;
DBGGETBPLIST _dbg_getbplist;
DBGDBGCMDEXECDIRECT _dbg_dbgcmddirectexec;
DBGGETBRANCHDESTINATION _dbg_getbranchdestination;
DBGSENDMESSAGE _dbg_sendmessage;
#include "_global.h"
GUIGUIINIT _gui_guiinit;
GUISENDMESSAGE _gui_sendmessage;
GUISENDMESSAGEASYNC _gui_sendmessageasync;
DBGDBGINIT _dbg_dbginit;
DBGMEMFINDBASEADDR _dbg_memfindbaseaddr;
DBGMEMREAD _dbg_memread;
DBGMEMWRITE _dbg_memwrite;
DBGDBGCMDEXEC _dbg_dbgcmdexec;
DBGMEMMAP _dbg_memmap;
DBGDBGEXITSIGNAL _dbg_dbgexitsignal;
DBGVALFROMSTRING _dbg_valfromstring;
DBGISDEBUGGING _dbg_isdebugging;
DBGISJUMPGOINGTOEXECUTE _dbg_isjumpgoingtoexecute;
DBGADDRINFOGET _dbg_addrinfoget;
DBGADDRINFOSET _dbg_addrinfoset;
DBGBPGETTYPEAT _dbg_bpgettypeat;
DBGGETREGDUMP _dbg_getregdump;
DBGVALTOSTRING _dbg_valtostring;
DBGMEMISVALIDREADPTR _dbg_memisvalidreadptr;
DBGGETBPLIST _dbg_getbplist;
DBGDBGCMDEXECDIRECT _dbg_dbgcmddirectexec;
DBGGETBRANCHDESTINATION _dbg_getbranchdestination;
DBGSENDMESSAGE _dbg_sendmessage;

View File

@ -1,61 +1,61 @@
#ifndef _GLOBAL_H
#define _GLOBAL_H
#include <windows.h>
#include "bridgemain.h"
//GUI typedefs
typedef int (*GUIGUIINIT)(int, char**);
typedef void* (*GUISENDMESSAGE)(GUIMSG type, void* param1, void* param2);
typedef void (*GUISENDMESSAGEASYNC)(GUIMSG type, void* param1, void* param2);
//GUI functions
extern GUIGUIINIT _gui_guiinit;
extern GUISENDMESSAGE _gui_sendmessage;
extern GUISENDMESSAGEASYNC _gui_sendmessageasync;
//DBG typedefs
typedef const char* (*DBGDBGINIT)();
typedef duint (*DBGMEMFINDBASEADDR)(duint addr, duint* size);
typedef bool (*DBGMEMREAD)(duint addr, unsigned char* dest, duint size, duint* read);
typedef bool (*DBGMEMWRITE)(duint addr, const unsigned char* src, duint size, duint* written);
typedef bool (*DBGDBGCMDEXEC)(const char* cmd);
typedef bool (*DBGMEMMAP)(MEMMAP* memmap);
typedef void (*DBGDBGEXITSIGNAL)();
typedef bool (*DBGVALFROMSTRING)(const char* string, duint* value);
typedef bool (*DBGISDEBUGGING)();
typedef bool (*DBGISJUMPGOINGTOEXECUTE)(duint addr);
typedef bool (*DBGADDRINFOGET)(duint addr, SEGMENTREG segment, ADDRINFO* addrinfo);
typedef bool (*DBGADDRINFOSET)(duint addr, ADDRINFO* addrinfo);
typedef BPXTYPE (*DBGBPGETTYPEAT)(duint addr);
typedef bool (*DBGGETREGDUMP)(REGDUMP* regdump);
typedef bool (*DBGVALTOSTRING)(const char* string, duint value);
typedef bool (*DBGMEMISVALIDREADPTR)(duint addr);
typedef int (*DBGGETBPLIST)(BPXTYPE type, BPMAP* bplist);
typedef bool (*DBGDBGCMDEXECDIRECT)(const char* cmd);
typedef duint (*DBGGETBRANCHDESTINATION)(duint addr);
typedef duint (*DBGSENDMESSAGE)(DBGMSG type, void* param1, void* param2);
//DBG functions
extern DBGDBGINIT _dbg_dbginit;
extern DBGMEMFINDBASEADDR _dbg_memfindbaseaddr;
extern DBGMEMREAD _dbg_memread;
extern DBGMEMWRITE _dbg_memwrite;
extern DBGDBGCMDEXEC _dbg_dbgcmdexec;
extern DBGMEMMAP _dbg_memmap;
extern DBGDBGEXITSIGNAL _dbg_dbgexitsignal;
extern DBGVALFROMSTRING _dbg_valfromstring;
extern DBGISDEBUGGING _dbg_isdebugging;
extern DBGISJUMPGOINGTOEXECUTE _dbg_isjumpgoingtoexecute;
extern DBGADDRINFOGET _dbg_addrinfoget;
extern DBGADDRINFOSET _dbg_addrinfoset;
extern DBGBPGETTYPEAT _dbg_bpgettypeat;
extern DBGGETREGDUMP _dbg_getregdump;
extern DBGVALTOSTRING _dbg_valtostring;
extern DBGMEMISVALIDREADPTR _dbg_memisvalidreadptr;
extern DBGGETBPLIST _dbg_getbplist;
extern DBGDBGCMDEXECDIRECT _dbg_dbgcmddirectexec;
extern DBGGETBRANCHDESTINATION _dbg_getbranchdestination;
extern DBGSENDMESSAGE _dbg_sendmessage;
#endif // _GLOBAL_H
#ifndef _GLOBAL_H
#define _GLOBAL_H
#include <windows.h>
#include "bridgemain.h"
//GUI typedefs
typedef int (*GUIGUIINIT)(int, char**);
typedef void* (*GUISENDMESSAGE)(GUIMSG type, void* param1, void* param2);
typedef void (*GUISENDMESSAGEASYNC)(GUIMSG type, void* param1, void* param2);
//GUI functions
extern GUIGUIINIT _gui_guiinit;
extern GUISENDMESSAGE _gui_sendmessage;
extern GUISENDMESSAGEASYNC _gui_sendmessageasync;
//DBG typedefs
typedef const char* (*DBGDBGINIT)();
typedef duint (*DBGMEMFINDBASEADDR)(duint addr, duint* size);
typedef bool (*DBGMEMREAD)(duint addr, unsigned char* dest, duint size, duint* read);
typedef bool (*DBGMEMWRITE)(duint addr, const unsigned char* src, duint size, duint* written);
typedef bool (*DBGDBGCMDEXEC)(const char* cmd);
typedef bool (*DBGMEMMAP)(MEMMAP* memmap);
typedef void (*DBGDBGEXITSIGNAL)();
typedef bool (*DBGVALFROMSTRING)(const char* string, duint* value);
typedef bool (*DBGISDEBUGGING)();
typedef bool (*DBGISJUMPGOINGTOEXECUTE)(duint addr);
typedef bool (*DBGADDRINFOGET)(duint addr, SEGMENTREG segment, ADDRINFO* addrinfo);
typedef bool (*DBGADDRINFOSET)(duint addr, ADDRINFO* addrinfo);
typedef BPXTYPE (*DBGBPGETTYPEAT)(duint addr);
typedef bool (*DBGGETREGDUMP)(REGDUMP* regdump);
typedef bool (*DBGVALTOSTRING)(const char* string, duint value);
typedef bool (*DBGMEMISVALIDREADPTR)(duint addr);
typedef int (*DBGGETBPLIST)(BPXTYPE type, BPMAP* bplist);
typedef bool (*DBGDBGCMDEXECDIRECT)(const char* cmd);
typedef duint (*DBGGETBRANCHDESTINATION)(duint addr);
typedef duint (*DBGSENDMESSAGE)(DBGMSG type, void* param1, void* param2);
//DBG functions
extern DBGDBGINIT _dbg_dbginit;
extern DBGMEMFINDBASEADDR _dbg_memfindbaseaddr;
extern DBGMEMREAD _dbg_memread;
extern DBGMEMWRITE _dbg_memwrite;
extern DBGDBGCMDEXEC _dbg_dbgcmdexec;
extern DBGMEMMAP _dbg_memmap;
extern DBGDBGEXITSIGNAL _dbg_dbgexitsignal;
extern DBGVALFROMSTRING _dbg_valfromstring;
extern DBGISDEBUGGING _dbg_isdebugging;
extern DBGISJUMPGOINGTOEXECUTE _dbg_isjumpgoingtoexecute;
extern DBGADDRINFOGET _dbg_addrinfoget;
extern DBGADDRINFOSET _dbg_addrinfoset;
extern DBGBPGETTYPEAT _dbg_bpgettypeat;
extern DBGGETREGDUMP _dbg_getregdump;
extern DBGVALTOSTRING _dbg_valtostring;
extern DBGMEMISVALIDREADPTR _dbg_memisvalidreadptr;
extern DBGGETBPLIST _dbg_getbplist;
extern DBGDBGCMDEXECDIRECT _dbg_dbgcmddirectexec;
extern DBGGETBRANCHDESTINATION _dbg_getbranchdestination;
extern DBGSENDMESSAGE _dbg_sendmessage;
#endif // _GLOBAL_H

View File

@ -1,129 +1,129 @@
#ifndef _LIST_H
#define _LIST_H
typedef struct
{
int count; //Number of element in the list.
size_t size; //Size of list in bytes (used for type checking).
void* data; //Pointer to the list contents. Must be deleted by the caller using BridgeFree (or List::Free).
} ListInfo;
#define ListOf(Type) ListInfo*
#ifdef __cplusplus
#include <vector>
/**
\brief A list object. This object is NOT thread safe.
\tparam Type List contents type.
*/
template<typename Type>
class List
{
public:
/**
\brief List constructor.
\param _freeData (Optional) the free function.
*/
explicit inline List()
{
memset(&_listInfo, 0, sizeof(_listInfo));
}
/**
\brief List destructor.
*/
inline ~List()
{
cleanup();
}
/**
\brief Gets the list data.
\return Returns ListInfo->data. Can be null if the list was never initialized. Will be destroyed once this object goes out of scope!
*/
inline Type* data() const
{
return reinterpret_cast<Type*>(_listInfo.data);
}
/**
\brief Gets the number of elements in the list. This will crash the program if the data is not consistent with the specified template argument.
\return The number of elements in the list.
*/
inline int count() const
{
if(_listInfo.size != _listInfo.count * sizeof(Type)) //make sure the user is using the correct type.
__debugbreak();
return _listInfo.count;
}
/**
\brief Cleans up the list, freeing the list data when it is not null.
*/
inline void cleanup()
{
if(_listInfo.data)
{
BridgeFree(_listInfo.data);
_listInfo.data = nullptr;
}
}
/**
\brief Reference operator (cleans up the previous list)
\return Pointer to the ListInfo.
*/
inline ListInfo* operator&()
{
cleanup();
return &_listInfo;
}
/**
\brief Array indexer operator. This will crash if you try to access out-of-bounds.
\param index Zero-based index of the item you want to get.
\return Reference to a value at that index.
*/
inline Type & operator[](size_t index) const
{
if(index >= size_t(count())) //make sure the out-of-bounds access is caught as soon as possible.
__debugbreak();
return data()[index];
}
/**
\brief Copies data to a ListInfo structure..
\param [out] listInfo If non-null, information describing the list.
\param listData Data to copy in the ListInfo structure.
\return true if it succeeds, false if it fails.
*/
static inline bool CopyData(ListInfo* listInfo, const std::vector<Type> & listData)
{
if(!listInfo)
return false;
listInfo->count = int(listData.size());
listInfo->size = listInfo->count * sizeof(Type);
if(listInfo->count)
{
listInfo->data = BridgeAlloc(listInfo->size);
Type* curItem = reinterpret_cast<Type*>(listInfo->data);
for(const auto & item : listData)
{
*curItem = item;
++curItem;
}
}
else
listInfo->data = nullptr;
return true;
}
private:
ListInfo _listInfo;
};
#endif //__cplusplus
#ifndef _LIST_H
#define _LIST_H
typedef struct
{
int count; //Number of element in the list.
size_t size; //Size of list in bytes (used for type checking).
void* data; //Pointer to the list contents. Must be deleted by the caller using BridgeFree (or List::Free).
} ListInfo;
#define ListOf(Type) ListInfo*
#ifdef __cplusplus
#include <vector>
/**
\brief A list object. This object is NOT thread safe.
\tparam Type List contents type.
*/
template<typename Type>
class List
{
public:
/**
\brief List constructor.
\param _freeData (Optional) the free function.
*/
explicit inline List()
{
memset(&_listInfo, 0, sizeof(_listInfo));
}
/**
\brief List destructor.
*/
inline ~List()
{
cleanup();
}
/**
\brief Gets the list data.
\return Returns ListInfo->data. Can be null if the list was never initialized. Will be destroyed once this object goes out of scope!
*/
inline Type* data() const
{
return reinterpret_cast<Type*>(_listInfo.data);
}
/**
\brief Gets the number of elements in the list. This will crash the program if the data is not consistent with the specified template argument.
\return The number of elements in the list.
*/
inline int count() const
{
if(_listInfo.size != _listInfo.count * sizeof(Type)) //make sure the user is using the correct type.
__debugbreak();
return _listInfo.count;
}
/**
\brief Cleans up the list, freeing the list data when it is not null.
*/
inline void cleanup()
{
if(_listInfo.data)
{
BridgeFree(_listInfo.data);
_listInfo.data = nullptr;
}
}
/**
\brief Reference operator (cleans up the previous list)
\return Pointer to the ListInfo.
*/
inline ListInfo* operator&()
{
cleanup();
return &_listInfo;
}
/**
\brief Array indexer operator. This will crash if you try to access out-of-bounds.
\param index Zero-based index of the item you want to get.
\return Reference to a value at that index.
*/
inline Type & operator[](size_t index) const
{
if(index >= size_t(count())) //make sure the out-of-bounds access is caught as soon as possible.
__debugbreak();
return data()[index];
}
/**
\brief Copies data to a ListInfo structure..
\param [out] listInfo If non-null, information describing the list.
\param listData Data to copy in the ListInfo structure.
\return true if it succeeds, false if it fails.
*/
static inline bool CopyData(ListInfo* listInfo, const std::vector<Type> & listData)
{
if(!listInfo)
return false;
listInfo->count = int(listData.size());
listInfo->size = listInfo->count * sizeof(Type);
if(listInfo->count)
{
listInfo->data = BridgeAlloc(listInfo->size);
Type* curItem = reinterpret_cast<Type*>(listInfo->data);
for(const auto & item : listData)
{
*curItem = item;
++curItem;
}
}
else
listInfo->data = nullptr;
return true;
}
private:
ListInfo _listInfo;
};
#endif //__cplusplus
#endif //_LIST_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,157 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="bridgemain.cpp" />
<ClCompile Include="_global.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="bridgemain.h" />
<ClInclude Include="bridgelist.h" />
<ClInclude Include="Utf8Ini.h" />
<ClInclude Include="_global.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x32\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>x32bridge</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x32\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>x32bridge</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x64\</OutDir>
<TargetName>x64bridge</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x64\</OutDir>
<TargetName>x64bridge</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>MaxSpeed</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>MaxSpeed</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="bridgemain.cpp" />
<ClCompile Include="_global.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="bridgemain.h" />
<ClInclude Include="bridgelist.h" />
<ClInclude Include="Utf8Ini.h" />
<ClInclude Include="_global.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x32\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>x32bridge</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x32\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>x32bridge</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x64\</OutDir>
<TargetName>x64bridge</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x64\</OutDir>
<TargetName>x64bridge</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>MaxSpeed</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>MaxSpeed</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,301 +1,301 @@
#include "capstone_wrapper.h"
#include <windows.h>
csh Capstone::mHandle = 0;
void Capstone::GlobalInitialize()
{
#ifdef _WIN64
cs_open(CS_ARCH_X86, CS_MODE_64, &mHandle);
#else //x86
cs_open(CS_ARCH_X86, CS_MODE_32, &mHandle);
#endif //_WIN64
cs_option(mHandle, CS_OPT_DETAIL, CS_OPT_ON);
}
void Capstone::GlobalFinalize()
{
if(mHandle) //close handle
cs_close(&mHandle);
}
Capstone::Capstone()
{
mInstr = nullptr;
mSuccess = false;
}
Capstone::~Capstone()
{
if(mInstr) //free last disassembled instruction
cs_free(mInstr, 1);
}
bool Capstone::Disassemble(size_t addr, const unsigned char data[MAX_DISASM_BUFFER])
{
return Disassemble(addr, data, MAX_DISASM_BUFFER);
}
bool Capstone::Disassemble(size_t addr, const unsigned char* data, int size)
{
if(!data)
return false;
if(mInstr) //free last disassembled instruction
{
cs_free(mInstr, 1);
mInstr = nullptr;
}
return mSuccess = !!cs_disasm(mHandle, data, size, addr, 1, &mInstr);
}
const cs_insn* Capstone::GetInstr() const
{
if(!Success())
return nullptr;
return mInstr;
}
bool Capstone::Success() const
{
return mSuccess;
}
const char* Capstone::RegName(x86_reg reg) const
{
return cs_reg_name(mHandle, reg);
}
bool Capstone::InGroup(cs_group_type group) const
{
if(!Success())
return false;
return cs_insn_group(mHandle, mInstr, group);
}
std::string Capstone::OperandText(int opindex) const
{
if(!Success() || opindex >= mInstr->detail->x86.op_count)
return "";
const auto & op = mInstr->detail->x86.operands[opindex];
std::string result;
char temp[32] = "";
switch(op.type)
{
case X86_OP_REG:
{
result = RegName(x86_reg(op.reg));
}
break;
case X86_OP_IMM:
{
sprintf_s(temp, "%llX", op.imm);
result = temp;
}
break;
case X86_OP_MEM:
{
const auto & mem = op.mem;
if(op.mem.base == X86_REG_RIP) //rip-relative
{
sprintf_s(temp, "%llX", Address() + op.mem.disp + Size());
result += temp;
}
else //normal
{
bool prependPlus = false;
if(mem.base)
{
result += RegName(x86_reg(mem.base));
prependPlus = true;
}
if(mem.index)
{
if(prependPlus)
result += "+";
result += RegName(x86_reg(mem.index));
sprintf_s(temp, "*%X", mem.scale);
result += temp;
prependPlus = true;
}
if(mem.disp)
{
char operatorText = '+';
if(mem.disp < 0)
{
operatorText = '-';
sprintf_s(temp, "%llX", mem.disp * -1);
}
else
sprintf_s(temp, "%llX", mem.disp);
if(prependPlus)
result += operatorText;
result += temp;
}
}
}
break;
case X86_OP_FP:
case X86_OP_INVALID:
{
}
break;
}
return result;
}
int Capstone::Size() const
{
if(!Success())
return 1;
return GetInstr()->size;
}
size_t Capstone::Address() const
{
if(!Success())
return 0;
return size_t(GetInstr()->address);
}
const cs_x86 & Capstone::x86() const
{
if(!Success())
DebugBreak();
return GetInstr()->detail->x86;
}
bool Capstone::IsFilling() const
{
if(!Success())
return false;
switch(GetId())
{
case X86_INS_NOP:
case X86_INS_INT3:
return true;
default:
return false;
}
}
bool Capstone::IsLoop() const
{
if(!Success())
return false;
switch(GetId())
{
case X86_INS_LOOP:
case X86_INS_LOOPE:
case X86_INS_LOOPNE:
return true;
default:
return false;
}
}
x86_insn Capstone::GetId() const
{
if(!Success())
DebugBreak();
return x86_insn(mInstr->id);
}
std::string Capstone::InstructionText() const
{
if(!Success())
return "???";
std::string result = Mnemonic();
if(OpCount())
{
result += " ";
result += mInstr->op_str;
}
return result;
}
int Capstone::OpCount() const
{
if(!Success())
return 0;
return x86().op_count;
}
cs_x86_op Capstone::operator[](int index) const
{
if(!Success() || index >= OpCount())
DebugBreak();
return x86().operands[index];
}
bool Capstone::IsNop() const
{
return GetId() == X86_INS_NOP;
}
bool Capstone::IsInt3() const
{
if(!Success())
return false;
switch(GetId())
{
case X86_INS_INT3:
return true;
case X86_INS_INT:
{
cs_x86_op op = x86().operands[0];
return op.type == X86_OP_IMM && op.imm == 3;
}
default:
return false;
}
}
std::string Capstone::Mnemonic() const
{
if(!Success())
return "???";
return mInstr->mnemonic;
}
const char* Capstone::MemSizeName(int size) const
{
switch(size)
{
case 1:
return "byte";
case 2:
return "word";
case 4:
return "dword";
case 6:
return "fword";
case 8:
return "qword";
case 10:
return "tword";
case 16:
return "dqword";
case 32:
return "yword";
case 64:
return "zword";
default:
return nullptr;
}
}
size_t Capstone::BranchDestination() const
{
if(!Success())
return 0;
if(InGroup(CS_GRP_JUMP) || InGroup(CS_GRP_CALL) || IsLoop())
{
const auto & op = x86().operands[0];
if(op.type == CS_OP_IMM)
return size_t(op.imm);
}
return 0;
#include "capstone_wrapper.h"
#include <windows.h>
csh Capstone::mHandle = 0;
void Capstone::GlobalInitialize()
{
#ifdef _WIN64
cs_open(CS_ARCH_X86, CS_MODE_64, &mHandle);
#else //x86
cs_open(CS_ARCH_X86, CS_MODE_32, &mHandle);
#endif //_WIN64
cs_option(mHandle, CS_OPT_DETAIL, CS_OPT_ON);
}
void Capstone::GlobalFinalize()
{
if(mHandle) //close handle
cs_close(&mHandle);
}
Capstone::Capstone()
{
mInstr = nullptr;
mSuccess = false;
}
Capstone::~Capstone()
{
if(mInstr) //free last disassembled instruction
cs_free(mInstr, 1);
}
bool Capstone::Disassemble(size_t addr, const unsigned char data[MAX_DISASM_BUFFER])
{
return Disassemble(addr, data, MAX_DISASM_BUFFER);
}
bool Capstone::Disassemble(size_t addr, const unsigned char* data, int size)
{
if(!data)
return false;
if(mInstr) //free last disassembled instruction
{
cs_free(mInstr, 1);
mInstr = nullptr;
}
return mSuccess = !!cs_disasm(mHandle, data, size, addr, 1, &mInstr);
}
const cs_insn* Capstone::GetInstr() const
{
if(!Success())
return nullptr;
return mInstr;
}
bool Capstone::Success() const
{
return mSuccess;
}
const char* Capstone::RegName(x86_reg reg) const
{
return cs_reg_name(mHandle, reg);
}
bool Capstone::InGroup(cs_group_type group) const
{
if(!Success())
return false;
return cs_insn_group(mHandle, mInstr, group);
}
std::string Capstone::OperandText(int opindex) const
{
if(!Success() || opindex >= mInstr->detail->x86.op_count)
return "";
const auto & op = mInstr->detail->x86.operands[opindex];
std::string result;
char temp[32] = "";
switch(op.type)
{
case X86_OP_REG:
{
result = RegName(x86_reg(op.reg));
}
break;
case X86_OP_IMM:
{
sprintf_s(temp, "%llX", op.imm);
result = temp;
}
break;
case X86_OP_MEM:
{
const auto & mem = op.mem;
if(op.mem.base == X86_REG_RIP) //rip-relative
{
sprintf_s(temp, "%llX", Address() + op.mem.disp + Size());
result += temp;
}
else //normal
{
bool prependPlus = false;
if(mem.base)
{
result += RegName(x86_reg(mem.base));
prependPlus = true;
}
if(mem.index)
{
if(prependPlus)
result += "+";
result += RegName(x86_reg(mem.index));
sprintf_s(temp, "*%X", mem.scale);
result += temp;
prependPlus = true;
}
if(mem.disp)
{
char operatorText = '+';
if(mem.disp < 0)
{
operatorText = '-';
sprintf_s(temp, "%llX", mem.disp * -1);
}
else
sprintf_s(temp, "%llX", mem.disp);
if(prependPlus)
result += operatorText;
result += temp;
}
}
}
break;
case X86_OP_FP:
case X86_OP_INVALID:
{
}
break;
}
return result;
}
int Capstone::Size() const
{
if(!Success())
return 1;
return GetInstr()->size;
}
size_t Capstone::Address() const
{
if(!Success())
return 0;
return size_t(GetInstr()->address);
}
const cs_x86 & Capstone::x86() const
{
if(!Success())
DebugBreak();
return GetInstr()->detail->x86;
}
bool Capstone::IsFilling() const
{
if(!Success())
return false;
switch(GetId())
{
case X86_INS_NOP:
case X86_INS_INT3:
return true;
default:
return false;
}
}
bool Capstone::IsLoop() const
{
if(!Success())
return false;
switch(GetId())
{
case X86_INS_LOOP:
case X86_INS_LOOPE:
case X86_INS_LOOPNE:
return true;
default:
return false;
}
}
x86_insn Capstone::GetId() const
{
if(!Success())
DebugBreak();
return x86_insn(mInstr->id);
}
std::string Capstone::InstructionText() const
{
if(!Success())
return "???";
std::string result = Mnemonic();
if(OpCount())
{
result += " ";
result += mInstr->op_str;
}
return result;
}
int Capstone::OpCount() const
{
if(!Success())
return 0;
return x86().op_count;
}
cs_x86_op Capstone::operator[](int index) const
{
if(!Success() || index >= OpCount())
DebugBreak();
return x86().operands[index];
}
bool Capstone::IsNop() const
{
return GetId() == X86_INS_NOP;
}
bool Capstone::IsInt3() const
{
if(!Success())
return false;
switch(GetId())
{
case X86_INS_INT3:
return true;
case X86_INS_INT:
{
cs_x86_op op = x86().operands[0];
return op.type == X86_OP_IMM && op.imm == 3;
}
default:
return false;
}
}
std::string Capstone::Mnemonic() const
{
if(!Success())
return "???";
return mInstr->mnemonic;
}
const char* Capstone::MemSizeName(int size) const
{
switch(size)
{
case 1:
return "byte";
case 2:
return "word";
case 4:
return "dword";
case 6:
return "fword";
case 8:
return "qword";
case 10:
return "tword";
case 16:
return "dqword";
case 32:
return "yword";
case 64:
return "zword";
default:
return nullptr;
}
}
size_t Capstone::BranchDestination() const
{
if(!Success())
return 0;
if(InGroup(CS_GRP_JUMP) || InGroup(CS_GRP_CALL) || IsLoop())
{
const auto & op = x86().operands[0];
if(op.type == CS_OP_IMM)
return size_t(op.imm);
}
return 0;
}

View File

@ -1,44 +1,44 @@
#ifndef _CAPSTONE_WRAPPER_H
#define _CAPSTONE_WRAPPER_H
#include "../dbg/capstone/capstone.h"
#include <string>
#define MAX_DISASM_BUFFER 16
class Capstone
{
public:
static void GlobalInitialize();
static void GlobalFinalize();
Capstone();
~Capstone();
bool Disassemble(size_t addr, const unsigned char data[MAX_DISASM_BUFFER]);
bool Disassemble(size_t addr, const unsigned char* data, int size);
const cs_insn* GetInstr() const;
bool Success() const;
const char* RegName(x86_reg reg) const;
bool InGroup(cs_group_type group) const;
std::string OperandText(int opindex) const;
int Size() const;
size_t Address() const;
const cs_x86 & x86() const;
bool IsFilling() const;
bool IsLoop() const;
x86_insn GetId() const;
std::string InstructionText() const;
int OpCount() const;
cs_x86_op operator[](int index) const;
bool IsNop() const;
bool IsInt3() const;
std::string Mnemonic() const;
const char* MemSizeName(int size) const;
size_t BranchDestination() const;
private:
static csh mHandle;
cs_insn* mInstr;
bool mSuccess;
};
#ifndef _CAPSTONE_WRAPPER_H
#define _CAPSTONE_WRAPPER_H
#include "../dbg/capstone/capstone.h"
#include <string>
#define MAX_DISASM_BUFFER 16
class Capstone
{
public:
static void GlobalInitialize();
static void GlobalFinalize();
Capstone();
~Capstone();
bool Disassemble(size_t addr, const unsigned char data[MAX_DISASM_BUFFER]);
bool Disassemble(size_t addr, const unsigned char* data, int size);
const cs_insn* GetInstr() const;
bool Success() const;
const char* RegName(x86_reg reg) const;
bool InGroup(cs_group_type group) const;
std::string OperandText(int opindex) const;
int Size() const;
size_t Address() const;
const cs_x86 & x86() const;
bool IsFilling() const;
bool IsLoop() const;
x86_insn GetId() const;
std::string InstructionText() const;
int OpCount() const;
cs_x86_op operator[](int index) const;
bool IsNop() const;
bool IsInt3() const;
std::string Mnemonic() const;
const char* MemSizeName(int size) const;
size_t BranchDestination() const;
private:
static csh mHandle;
cs_insn* mInstr;
bool mSuccess;
};
#endif //_CAPSTONE_WRAPPER_H

View File

@ -1,95 +1,95 @@
#include <assert.h>
#include <thread>
#include "AnalysisPass.h"
#include "memory.h"
AnalysisPass::AnalysisPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks) : m_MainBlocks(MainBlocks)
{
assert(VirtualEnd > VirtualStart);
// Internal class data
m_VirtualStart = VirtualStart;
m_VirtualEnd = VirtualEnd;
m_InternalMaxThreads = 0;
// Read remote instruction data to local memory
m_DataSize = VirtualEnd - VirtualStart;
m_Data = (unsigned char*)emalloc(m_DataSize, "AnalysisPass:m_Data");
if(!MemRead(VirtualStart, m_Data, m_DataSize))
{
BridgeFree(m_Data);
assert(false);
}
}
AnalysisPass::~AnalysisPass()
{
if(m_Data)
efree(m_Data);
}
BasicBlock* AnalysisPass::FindBBlockInRange(duint Address)
{
// NOTE: __MUST__ BE A SORTED VECTOR
//
// Use a binary search
duint indexLo = 0;
duint indexHi = m_MainBlocks.size();
// Get a pointer to pure data
const auto blocks = m_MainBlocks.data();
while(indexHi > indexLo)
{
duint indexMid = (indexLo + indexHi) / 2;
auto entry = &blocks[indexMid];
if(Address < entry->VirtualStart)
{
// Continue search in lower half
indexHi = indexMid;
}
else if(Address >= entry->VirtualEnd)
{
// Continue search in upper half
indexLo = indexMid + 1;
}
else
{
// Address is within limits, return entry
return entry;
}
}
// Not found
return nullptr;
}
duint AnalysisPass::FindBBlockIndex(BasicBlock* Block)
{
// Fast pointer arithmetic to find index
return ((duint)Block - (duint)m_MainBlocks.data()) / sizeof(BasicBlock);
}
duint AnalysisPass::IdealThreadCount()
{
if(m_InternalMaxThreads == 0)
{
// Determine the maximum hardware thread count at once
duint maximumThreads = max(std::thread::hardware_concurrency(), 1);
// Don't consume 100% of the CPU, adjust accordingly
if(maximumThreads > 1)
maximumThreads -= 1;
SetIdealThreadCount(maximumThreads);
}
return m_InternalMaxThreads;
}
void AnalysisPass::SetIdealThreadCount(duint Count)
{
m_InternalMaxThreads = (BYTE)min(Count, 255);
#include <assert.h>
#include <thread>
#include "AnalysisPass.h"
#include "memory.h"
AnalysisPass::AnalysisPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks) : m_MainBlocks(MainBlocks)
{
assert(VirtualEnd > VirtualStart);
// Internal class data
m_VirtualStart = VirtualStart;
m_VirtualEnd = VirtualEnd;
m_InternalMaxThreads = 0;
// Read remote instruction data to local memory
m_DataSize = VirtualEnd - VirtualStart;
m_Data = (unsigned char*)emalloc(m_DataSize, "AnalysisPass:m_Data");
if(!MemRead(VirtualStart, m_Data, m_DataSize))
{
BridgeFree(m_Data);
assert(false);
}
}
AnalysisPass::~AnalysisPass()
{
if(m_Data)
efree(m_Data);
}
BasicBlock* AnalysisPass::FindBBlockInRange(duint Address)
{
// NOTE: __MUST__ BE A SORTED VECTOR
//
// Use a binary search
duint indexLo = 0;
duint indexHi = m_MainBlocks.size();
// Get a pointer to pure data
const auto blocks = m_MainBlocks.data();
while(indexHi > indexLo)
{
duint indexMid = (indexLo + indexHi) / 2;
auto entry = &blocks[indexMid];
if(Address < entry->VirtualStart)
{
// Continue search in lower half
indexHi = indexMid;
}
else if(Address >= entry->VirtualEnd)
{
// Continue search in upper half
indexLo = indexMid + 1;
}
else
{
// Address is within limits, return entry
return entry;
}
}
// Not found
return nullptr;
}
duint AnalysisPass::FindBBlockIndex(BasicBlock* Block)
{
// Fast pointer arithmetic to find index
return ((duint)Block - (duint)m_MainBlocks.data()) / sizeof(BasicBlock);
}
duint AnalysisPass::IdealThreadCount()
{
if(m_InternalMaxThreads == 0)
{
// Determine the maximum hardware thread count at once
duint maximumThreads = max(std::thread::hardware_concurrency(), 1);
// Don't consume 100% of the CPU, adjust accordingly
if(maximumThreads > 1)
maximumThreads -= 1;
SetIdealThreadCount(maximumThreads);
}
return m_InternalMaxThreads;
}
void AnalysisPass::SetIdealThreadCount(duint Count)
{
m_InternalMaxThreads = (BYTE)min(Count, 255);
}

View File

@ -1,41 +1,41 @@
#pragma once
#include "_global.h"
#include "BasicBlock.h"
class AnalysisPass
{
public:
AnalysisPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks);
virtual ~AnalysisPass();
virtual const char* GetName() = 0;
virtual bool Analyse() = 0;
protected:
duint m_VirtualStart;
duint m_VirtualEnd;
duint m_DataSize;
unsigned char* m_Data;
BBlockArray & m_MainBlocks;
inline unsigned char* AnalysisPass::TranslateAddress(duint Address)
{
assert(ValidateAddress(Address));
return &m_Data[Address - m_VirtualStart];
}
inline bool AnalysisPass::ValidateAddress(duint Address)
{
return (Address >= m_VirtualStart && Address < m_VirtualEnd);
}
BasicBlock* FindBBlockInRange(duint Address);
duint FindBBlockIndex(BasicBlock* Block);
duint IdealThreadCount();
void SetIdealThreadCount(duint Count);
private:
BYTE m_InternalMaxThreads;
#pragma once
#include "_global.h"
#include "BasicBlock.h"
class AnalysisPass
{
public:
AnalysisPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks);
virtual ~AnalysisPass();
virtual const char* GetName() = 0;
virtual bool Analyse() = 0;
protected:
duint m_VirtualStart;
duint m_VirtualEnd;
duint m_DataSize;
unsigned char* m_Data;
BBlockArray & m_MainBlocks;
inline unsigned char* AnalysisPass::TranslateAddress(duint Address)
{
assert(ValidateAddress(Address));
return &m_Data[Address - m_VirtualStart];
}
inline bool AnalysisPass::ValidateAddress(duint Address)
{
return (Address >= m_VirtualStart && Address < m_VirtualEnd);
}
BasicBlock* FindBBlockInRange(duint Address);
duint FindBBlockIndex(BasicBlock* Block);
duint IdealThreadCount();
void SetIdealThreadCount(duint Count);
private:
BYTE m_InternalMaxThreads;
};

View File

@ -1,80 +1,80 @@
#pragma once
#include "_global.h"
enum BasicBlockFlags : duint
{
BASIC_BLOCK_FLAG_NONE = 0, // No flag
BASIC_BLOCK_FLAG_FUNCTION = (1 << 1), // Scanned; also part of a known function
BASIC_BLOCK_FLAG_ORPHANED = (1 << 2), // No targets ever reach this block
BASIC_BLOCK_FLAG_CUTOFF = (1 << 3), // Ends prematurely because of another JMP to location
BASIC_BLOCK_FLAG_DELETE = (1 << 4), // Delete element at the next possible time
BASIC_BLOCK_FLAG_CALL = (1 << 5), // The block ends with a call
BASIC_BLOCK_FLAG_RET = (1 << 6), // The block ends with a retn
BASIC_BLOCK_FLAG_ABSJMP = (1 << 7), // Branch is absolute
BASIC_BLOCK_FLAG_INDIRECT = (1 << 8), // This block ends with an indirect branch
BASIC_BLOCK_FLAG_INDIRPTR = (1 << 9), // This block ends with an indirect branch; pointer known
BASIC_BLOCK_FLAG_PREPAD = (1 << 10), // Block ends because there was padding afterwards
BASIC_BLOCK_FLAG_PAD = (1 << 11), // Block is only a series of padding instructions
};
struct BasicBlock
{
duint VirtualStart; // Inclusive
duint VirtualEnd; // Exclusive
duint Flags;
duint Target;
__forceinline bool GetFlag(duint Flag)
{
return (Flags & Flag) == Flag;
}
__forceinline void SetFlag(duint Flag)
{
Flags |= Flag;
}
__forceinline duint Size()
{
return VirtualEnd - VirtualStart;
}
bool operator< (const BasicBlock & b) const
{
return VirtualStart < b.VirtualStart;
}
bool operator== (const BasicBlock & b) const
{
return VirtualStart == b.VirtualStart;
}
};
struct FunctionDef
{
duint VirtualStart; // Inclusive
duint VirtualEnd; // Exclusive
duint BBlockStart; // Index of first basic block
duint BBlockEnd; // Index of last basic block
bool operator< (const FunctionDef & b) const
{
if(VirtualStart == b.VirtualStart)
return VirtualEnd > b.VirtualEnd;
return VirtualStart < b.VirtualStart;
}
bool operator== (const FunctionDef & b) const
{
return VirtualStart == b.VirtualStart;
}
};
typedef std::vector<BasicBlock> BBlockArray;
#pragma once
#include "_global.h"
enum BasicBlockFlags : duint
{
BASIC_BLOCK_FLAG_NONE = 0, // No flag
BASIC_BLOCK_FLAG_FUNCTION = (1 << 1), // Scanned; also part of a known function
BASIC_BLOCK_FLAG_ORPHANED = (1 << 2), // No targets ever reach this block
BASIC_BLOCK_FLAG_CUTOFF = (1 << 3), // Ends prematurely because of another JMP to location
BASIC_BLOCK_FLAG_DELETE = (1 << 4), // Delete element at the next possible time
BASIC_BLOCK_FLAG_CALL = (1 << 5), // The block ends with a call
BASIC_BLOCK_FLAG_RET = (1 << 6), // The block ends with a retn
BASIC_BLOCK_FLAG_ABSJMP = (1 << 7), // Branch is absolute
BASIC_BLOCK_FLAG_INDIRECT = (1 << 8), // This block ends with an indirect branch
BASIC_BLOCK_FLAG_INDIRPTR = (1 << 9), // This block ends with an indirect branch; pointer known
BASIC_BLOCK_FLAG_PREPAD = (1 << 10), // Block ends because there was padding afterwards
BASIC_BLOCK_FLAG_PAD = (1 << 11), // Block is only a series of padding instructions
};
struct BasicBlock
{
duint VirtualStart; // Inclusive
duint VirtualEnd; // Exclusive
duint Flags;
duint Target;
__forceinline bool GetFlag(duint Flag)
{
return (Flags & Flag) == Flag;
}
__forceinline void SetFlag(duint Flag)
{
Flags |= Flag;
}
__forceinline duint Size()
{
return VirtualEnd - VirtualStart;
}
bool operator< (const BasicBlock & b) const
{
return VirtualStart < b.VirtualStart;
}
bool operator== (const BasicBlock & b) const
{
return VirtualStart == b.VirtualStart;
}
};
struct FunctionDef
{
duint VirtualStart; // Inclusive
duint VirtualEnd; // Exclusive
duint BBlockStart; // Index of first basic block
duint BBlockEnd; // Index of last basic block
bool operator< (const FunctionDef & b) const
{
if(VirtualStart == b.VirtualStart)
return VirtualEnd > b.VirtualEnd;
return VirtualStart < b.VirtualStart;
}
bool operator== (const FunctionDef & b) const
{
return VirtualStart == b.VirtualStart;
}
};
typedef std::vector<BasicBlock> BBlockArray;
typedef std::vector<FunctionDef> FuncDefArray;

View File

@ -1,92 +1,92 @@
#include "AnalysisPass.h"
#include "CodeFollowPass.h"
CodeFollowPass::CodeFollowPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
{
}
CodeFollowPass::~CodeFollowPass()
{
}
const char* CodeFollowPass::GetName()
{
return "Code Follower";
}
bool CodeFollowPass::Analyse()
{
// First gather all possible function references with certain tables
//
// This includes:
// Main entry
// Module exports
// Module import references (?)
// Control flow guard
// RUNTIME_FUNCTION
// TLS callbacks
// FLS callbacks
return false;
}
duint CodeFollowPass::GetReferenceOperand(const cs_x86 & Context)
{
for(int i = 0; i < Context.op_count; i++)
{
auto operand = Context.operands[i];
// Looking for immediate references
if(operand.type == X86_OP_IMM)
{
duint dest = (duint)operand.imm;
if(ValidateAddress(dest))
return dest;
}
}
return 0;
}
duint CodeFollowPass::GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect)
{
if(Context.op_count <= 0)
return 0;
// Only the first operand matters
auto operand = Context.operands[0];
// Jumps and calls only
if(Disasm.InGroup(CS_GRP_CALL) || Disasm.InGroup(CS_GRP_JUMP))
{
// Looking for memory references
if(operand.type == X86_OP_MEM)
{
// Notify if the operand was indirect
if(Indirect)
{
if(operand.mem.base != X86_REG_INVALID ||
operand.mem.index != X86_REG_INVALID ||
operand.mem.scale != 0)
{
*Indirect = true;
return 0;
}
}
// TODO: Read pointer
// TODO: Find virtual tables (new pass?)
// TODO: Translate RIP-Relative
return 0;
duint dest = (duint)operand.mem.disp;
if(ValidateAddress(dest))
return dest;
}
}
return 0;
#include "AnalysisPass.h"
#include "CodeFollowPass.h"
CodeFollowPass::CodeFollowPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
{
}
CodeFollowPass::~CodeFollowPass()
{
}
const char* CodeFollowPass::GetName()
{
return "Code Follower";
}
bool CodeFollowPass::Analyse()
{
// First gather all possible function references with certain tables
//
// This includes:
// Main entry
// Module exports
// Module import references (?)
// Control flow guard
// RUNTIME_FUNCTION
// TLS callbacks
// FLS callbacks
return false;
}
duint CodeFollowPass::GetReferenceOperand(const cs_x86 & Context)
{
for(int i = 0; i < Context.op_count; i++)
{
auto operand = Context.operands[i];
// Looking for immediate references
if(operand.type == X86_OP_IMM)
{
duint dest = (duint)operand.imm;
if(ValidateAddress(dest))
return dest;
}
}
return 0;
}
duint CodeFollowPass::GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect)
{
if(Context.op_count <= 0)
return 0;
// Only the first operand matters
auto operand = Context.operands[0];
// Jumps and calls only
if(Disasm.InGroup(CS_GRP_CALL) || Disasm.InGroup(CS_GRP_JUMP))
{
// Looking for memory references
if(operand.type == X86_OP_MEM)
{
// Notify if the operand was indirect
if(Indirect)
{
if(operand.mem.base != X86_REG_INVALID ||
operand.mem.index != X86_REG_INVALID ||
operand.mem.scale != 0)
{
*Indirect = true;
return 0;
}
}
// TODO: Read pointer
// TODO: Find virtual tables (new pass?)
// TODO: Translate RIP-Relative
return 0;
duint dest = (duint)operand.mem.disp;
if(ValidateAddress(dest))
return dest;
}
}
return 0;
}

View File

@ -1,19 +1,19 @@
#pragma once
#include "AnalysisPass.h"
#include "BasicBlock.h"
#include <capstone_wrapper.h>
class CodeFollowPass : public AnalysisPass
{
public:
CodeFollowPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks);
virtual ~CodeFollowPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
private:
duint GetReferenceOperand(const cs_x86 & Context);
duint GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect);
#pragma once
#include "AnalysisPass.h"
#include "BasicBlock.h"
#include <capstone_wrapper.h>
class CodeFollowPass : public AnalysisPass
{
public:
CodeFollowPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks);
virtual ~CodeFollowPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
private:
duint GetReferenceOperand(const cs_x86 & Context);
duint GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect);
};

View File

@ -1,22 +1,22 @@
#ifndef _DEVICENAMERESOLVER_H
#define _DEVICENAMERESOLVER_H
#include <windows.h>
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) bool DevicePathToPathW(const wchar_t* szDevicePath, wchar_t* szPath, size_t nSize);
__declspec(dllexport) bool DevicePathToPathA(const char* szDevicePath, char* szPath, size_t nSize);
__declspec(dllexport) bool DevicePathFromFileHandleW(HANDLE hFile, wchar_t* szDevicePath, size_t nSize);
__declspec(dllexport) bool DevicePathFromFileHandleA(HANDLE hFile, char* szDevicePath, size_t nSize);
__declspec(dllexport) bool PathFromFileHandleW(HANDLE hFile, wchar_t* szPath, size_t nSize);
__declspec(dllexport) bool PathFromFileHandleA(HANDLE hFile, char* szPath, size_t nSize);
#ifdef __cplusplus
}
#endif
#endif // _DEVICENAMERESOLVER_H
#ifndef _DEVICENAMERESOLVER_H
#define _DEVICENAMERESOLVER_H
#include <windows.h>
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) bool DevicePathToPathW(const wchar_t* szDevicePath, wchar_t* szPath, size_t nSize);
__declspec(dllexport) bool DevicePathToPathA(const char* szDevicePath, char* szPath, size_t nSize);
__declspec(dllexport) bool DevicePathFromFileHandleW(HANDLE hFile, wchar_t* szDevicePath, size_t nSize);
__declspec(dllexport) bool DevicePathFromFileHandleA(HANDLE hFile, char* szDevicePath, size_t nSize);
__declspec(dllexport) bool PathFromFileHandleW(HANDLE hFile, wchar_t* szPath, size_t nSize);
__declspec(dllexport) bool PathFromFileHandleA(HANDLE hFile, char* szPath, size_t nSize);
#ifdef __cplusplus
}
#endif
#endif // _DEVICENAMERESOLVER_H

View File

@ -1,359 +1,359 @@
#include "FunctionPass.h"
#include <ppl.h>
#include "memory.h"
#include "console.h"
#include "debugger.h"
#include "module.h"
#include "function.h"
FunctionPass::FunctionPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
{
// Zero values
m_FunctionInfo = nullptr;
m_FunctionInfoSize = 0;
// This will only be valid if the address range is within a loaded module
m_ModuleStart = ModBaseFromAddr(VirtualStart);
if(m_ModuleStart != 0)
{
char modulePath[MAX_PATH];
memset(modulePath, 0, sizeof(modulePath));
ModPathFromAddr(m_ModuleStart, modulePath, ARRAYSIZE(modulePath));
HANDLE fileHandle;
DWORD fileSize;
HANDLE fileMapHandle;
ULONG_PTR fileMapVa;
if(StaticFileLoadW(
StringUtils::Utf8ToUtf16(modulePath).c_str(),
UE_ACCESS_READ,
false,
&fileHandle,
&fileSize,
&fileMapHandle,
&fileMapVa))
{
// Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use
ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET);
m_FunctionInfoSize = (ULONG)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE);
// Unload the file
StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa);
// Get a copy of the function table
if(virtualOffset)
{
// Read the table into a buffer
m_FunctionInfo = BridgeAlloc(m_FunctionInfoSize);
if(m_FunctionInfo)
MemRead(virtualOffset + m_ModuleStart, m_FunctionInfo, m_FunctionInfoSize);
}
}
}
}
FunctionPass::~FunctionPass()
{
if(m_FunctionInfo)
BridgeFree(m_FunctionInfo);
}
const char* FunctionPass::GetName()
{
return "Function Analysis";
}
bool FunctionPass::Analyse()
{
// THREAD_WORK = ceil(TOTAL / # THREADS)
duint workAmount = (m_MainBlocks.size() + (IdealThreadCount() - 1)) / IdealThreadCount();
// Initialize thread vector
auto threadFunctions = new std::vector<FunctionDef>[IdealThreadCount()];
concurrency::parallel_for(duint (0), IdealThreadCount(), [&](duint i)
{
duint threadWorkStart = (workAmount * i);
duint threadWorkStop = min((threadWorkStart + workAmount), m_MainBlocks.size());
// Memory allocation optimization
// TODO: Option to conserve memory
threadFunctions[i].reserve(30000);
// Execute
AnalysisWorker(threadWorkStart, threadWorkStop, &threadFunctions[i]);
});
std::vector<FunctionDef> funcs;
// Merge thread vectors into single local
for(duint i = 0; i < IdealThreadCount(); i++)
std::move(threadFunctions[i].begin(), threadFunctions[i].end(), std::back_inserter(funcs));
// Sort and remove duplicates
std::sort(funcs.begin(), funcs.end());
funcs.erase(std::unique(funcs.begin(), funcs.end()), funcs.end());
dprintf("%u functions\n", funcs.size());
FunctionClear();
for(auto & func : funcs)
{
FunctionAdd(func.VirtualStart, func.VirtualEnd - 1, true);
}
GuiUpdateAllViews();
delete[] threadFunctions;
return true;
}
void FunctionPass::AnalysisWorker(duint Start, duint End, std::vector<FunctionDef>* Blocks)
{
// Step 1: Use any defined functions in the PE function table
FindFunctionWorkerPrepass(Start, End, Blocks);
// Step 2: for each block that contains a CALL flag,
// add it to a local function start array
//
// NOTE: *Some* indirect calls are included
auto blockItr = std::next(m_MainBlocks.begin(), Start);
for(duint i = Start; i < End; i++, ++blockItr)
{
if(blockItr->GetFlag(BASIC_BLOCK_FLAG_CALL))
{
duint destination = blockItr->Target;
// Was it a pointer?
if(blockItr->GetFlag(BASIC_BLOCK_FLAG_INDIRPTR))
{
// Read it from memory
if(!MemRead(destination, &destination, sizeof(duint)))
continue;
// Validity check
if(!MemIsValidReadPtr(destination))
continue;
dprintf("Indirect pointer: 0x%p 0x%p\n", blockItr->Target, destination);
}
// Destination must be within analysis limits
if(!ValidateAddress(destination))
continue;
FunctionDef def;
def.VirtualStart = destination;
def.VirtualEnd = 0;
def.BBlockStart = 0;
def.BBlockEnd = 0;
Blocks->push_back(def);
}
}
// Step 3: Sort and remove duplicates
std::sort(Blocks->begin(), Blocks->end());
Blocks->erase(std::unique(Blocks->begin(), Blocks->end()), Blocks->end());
// Step 4: Find the end of functions
FindFunctionWorker(Blocks);
dprintf("Total detected functions: %d\n", Blocks->size());
// Step 5: Find all orphaned blocks and repeat analysis process
// TODO
}
void FunctionPass::FindFunctionWorkerPrepass(duint Start, duint End, std::vector<FunctionDef>* Blocks)
{
const duint minFunc = std::next(m_MainBlocks.begin(), Start)->VirtualStart;
const duint maxFunc = std::next(m_MainBlocks.begin(), End - 1)->VirtualEnd;
#ifdef _WIN64
// RUNTIME_FUNCTION exception information
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
{
const duint funcAddr = m_ModuleStart + Function->BeginAddress;
const duint funcEnd = m_ModuleStart + Function->EndAddress;
// If within limits...
if(funcAddr >= minFunc && funcAddr < maxFunc)
{
// Add the descriptor
FunctionDef def;
def.VirtualStart = funcAddr;
def.VirtualEnd = funcEnd;
def.BBlockStart = 0;
def.BBlockEnd = 0;
Blocks->push_back(def);
}
return true;
});
#endif // _WIN64
// Module exports (return value ignored)
apienumexports(m_ModuleStart, [&](duint Base, const char* Module, const char* Name, duint Address)
{
// If within limits...
if(Address >= minFunc && Address < maxFunc)
{
// Add the descriptor
FunctionDef def;
def.VirtualStart = Address;
def.VirtualEnd = 0;
def.BBlockStart = 0;
def.BBlockEnd = 0;
Blocks->push_back(def);
}
});
}
void FunctionPass::FindFunctionWorker(std::vector<FunctionDef>* Blocks)
{
// Cached final block
BasicBlock* finalBlock = &m_MainBlocks.back();
// Enumerate all function entries for this thread
for(auto & block : *Blocks)
{
// Sometimes the ending address is already supplied, so
// check first
if(block.VirtualEnd != 0)
{
if(ResolveKnownFunctionEnd(&block))
continue;
}
// Now the function end must be determined by heuristics (find manually)
ResolveFunctionEnd(&block, finalBlock);
}
}
bool FunctionPass::ResolveKnownFunctionEnd(FunctionDef* Function)
{
// Helper to link final blocks to function
auto startBlock = FindBBlockInRange(Function->VirtualStart);
auto endBlock = FindBBlockInRange(Function->VirtualEnd);
if(!startBlock || !endBlock)
return false;
// Find block start/end indices
Function->BBlockStart = FindBBlockIndex(startBlock);
Function->BBlockEnd = FindBBlockIndex(endBlock);
// Set the flag for blocks that have been scanned
for(BasicBlock* block = startBlock; (duint)block <= (duint)endBlock; block++)
block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION);
return true;
}
bool FunctionPass::ResolveFunctionEnd(FunctionDef* Function, BasicBlock* LastBlock)
{
ASSERT_TRUE(Function->VirtualStart != 0);
// Find the first basic block of the function
BasicBlock* block = FindBBlockInRange(Function->VirtualStart);
if(!block)
{
ASSERT_ALWAYS("Block should exist at this point");
return false;
}
// The maximum address is determined by any jump that extends past
// a RET or other terminating basic block. A function may have multiple
// return statements.
duint maximumAddr = 0;
// Loop forever until the end is found
for(; (duint)block <= (duint)LastBlock; block++)
{
// Block is now in use
block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION);
// Calculate max from just linear instructions
maximumAddr = max(maximumAddr, block->VirtualEnd - 1);
// Find maximum jump target
if(!block->GetFlag(BASIC_BLOCK_FLAG_CALL) && !block->GetFlag(BASIC_BLOCK_FLAG_INDIRECT))
{
if(block->Target != 0)
{
// Here's a problem: Compilers add tail-call elimination with a jump.
// Solve this by creating a maximum jump limit: +/- 512 bytes from the end.
//
// abs(block->VirtualEnd - block->Target) -- unsigned
if(min(block->VirtualEnd - block->Target, block->Target - block->VirtualEnd) <= 512)
maximumAddr = max(maximumAddr, block->Target);
}
}
// Sanity check
ASSERT_TRUE(maximumAddr >= block->VirtualStart);
// Does this node contain the maximum address?
if(maximumAddr >= block->VirtualStart && maximumAddr < block->VirtualEnd)
{
// It does! There's 4 possibilities next:
//
// 1. Return
// 2. Tail-call elimination
// 3. Optimized loop
// 4. Function continues to next block
//
// 1.
if(block->GetFlag(BASIC_BLOCK_FLAG_RET))
break;
if(block->Target != 0)
{
// NOTE: Both must be an absolute jump
if(block->GetFlag(BASIC_BLOCK_FLAG_ABSJMP))
{
// 2.
//
// abs(block->VirtualEnd - block->Target) -- unsigned
if(min(block->VirtualEnd - block->Target, block->Target - block->VirtualEnd) > 128)
break;
// 3.
if(block->Target >= Function->VirtualStart && block->Target < block->VirtualEnd)
break;
}
}
// 4. Continue
}
}
// Loop is done. Set the information in the function structure.
Function->VirtualEnd = block->VirtualEnd;
Function->BBlockEnd = FindBBlockIndex(block);
return true;
}
#ifdef _WIN64
void FunctionPass::EnumerateFunctionRuntimeEntries64(std::function<bool (PRUNTIME_FUNCTION)> Callback)
{
if(!m_FunctionInfo)
return;
// Get the table pointer and size
auto functionTable = (PRUNTIME_FUNCTION)m_FunctionInfo;
ULONG totalCount = (m_FunctionInfoSize / sizeof(RUNTIME_FUNCTION));
// Enumerate each entry
for(ULONG i = 0; i < totalCount; i++)
{
if(!Callback(&functionTable[i]))
break;
}
}
#include "FunctionPass.h"
#include <ppl.h>
#include "memory.h"
#include "console.h"
#include "debugger.h"
#include "module.h"
#include "function.h"
FunctionPass::FunctionPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
{
// Zero values
m_FunctionInfo = nullptr;
m_FunctionInfoSize = 0;
// This will only be valid if the address range is within a loaded module
m_ModuleStart = ModBaseFromAddr(VirtualStart);
if(m_ModuleStart != 0)
{
char modulePath[MAX_PATH];
memset(modulePath, 0, sizeof(modulePath));
ModPathFromAddr(m_ModuleStart, modulePath, ARRAYSIZE(modulePath));
HANDLE fileHandle;
DWORD fileSize;
HANDLE fileMapHandle;
ULONG_PTR fileMapVa;
if(StaticFileLoadW(
StringUtils::Utf8ToUtf16(modulePath).c_str(),
UE_ACCESS_READ,
false,
&fileHandle,
&fileSize,
&fileMapHandle,
&fileMapVa))
{
// Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use
ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET);
m_FunctionInfoSize = (ULONG)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE);
// Unload the file
StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa);
// Get a copy of the function table
if(virtualOffset)
{
// Read the table into a buffer
m_FunctionInfo = BridgeAlloc(m_FunctionInfoSize);
if(m_FunctionInfo)
MemRead(virtualOffset + m_ModuleStart, m_FunctionInfo, m_FunctionInfoSize);
}
}
}
}
FunctionPass::~FunctionPass()
{
if(m_FunctionInfo)
BridgeFree(m_FunctionInfo);
}
const char* FunctionPass::GetName()
{
return "Function Analysis";
}
bool FunctionPass::Analyse()
{
// THREAD_WORK = ceil(TOTAL / # THREADS)
duint workAmount = (m_MainBlocks.size() + (IdealThreadCount() - 1)) / IdealThreadCount();
// Initialize thread vector
auto threadFunctions = new std::vector<FunctionDef>[IdealThreadCount()];
concurrency::parallel_for(duint (0), IdealThreadCount(), [&](duint i)
{
duint threadWorkStart = (workAmount * i);
duint threadWorkStop = min((threadWorkStart + workAmount), m_MainBlocks.size());
// Memory allocation optimization
// TODO: Option to conserve memory
threadFunctions[i].reserve(30000);
// Execute
AnalysisWorker(threadWorkStart, threadWorkStop, &threadFunctions[i]);
});
std::vector<FunctionDef> funcs;
// Merge thread vectors into single local
for(duint i = 0; i < IdealThreadCount(); i++)
std::move(threadFunctions[i].begin(), threadFunctions[i].end(), std::back_inserter(funcs));
// Sort and remove duplicates
std::sort(funcs.begin(), funcs.end());
funcs.erase(std::unique(funcs.begin(), funcs.end()), funcs.end());
dprintf("%u functions\n", funcs.size());
FunctionClear();
for(auto & func : funcs)
{
FunctionAdd(func.VirtualStart, func.VirtualEnd - 1, true);
}
GuiUpdateAllViews();
delete[] threadFunctions;
return true;
}
void FunctionPass::AnalysisWorker(duint Start, duint End, std::vector<FunctionDef>* Blocks)
{
// Step 1: Use any defined functions in the PE function table
FindFunctionWorkerPrepass(Start, End, Blocks);
// Step 2: for each block that contains a CALL flag,
// add it to a local function start array
//
// NOTE: *Some* indirect calls are included
auto blockItr = std::next(m_MainBlocks.begin(), Start);
for(duint i = Start; i < End; i++, ++blockItr)
{
if(blockItr->GetFlag(BASIC_BLOCK_FLAG_CALL))
{
duint destination = blockItr->Target;
// Was it a pointer?
if(blockItr->GetFlag(BASIC_BLOCK_FLAG_INDIRPTR))
{
// Read it from memory
if(!MemRead(destination, &destination, sizeof(duint)))
continue;
// Validity check
if(!MemIsValidReadPtr(destination))
continue;
dprintf("Indirect pointer: 0x%p 0x%p\n", blockItr->Target, destination);
}
// Destination must be within analysis limits
if(!ValidateAddress(destination))
continue;
FunctionDef def;
def.VirtualStart = destination;
def.VirtualEnd = 0;
def.BBlockStart = 0;
def.BBlockEnd = 0;
Blocks->push_back(def);
}
}
// Step 3: Sort and remove duplicates
std::sort(Blocks->begin(), Blocks->end());
Blocks->erase(std::unique(Blocks->begin(), Blocks->end()), Blocks->end());
// Step 4: Find the end of functions
FindFunctionWorker(Blocks);
dprintf("Total detected functions: %d\n", Blocks->size());
// Step 5: Find all orphaned blocks and repeat analysis process
// TODO
}
void FunctionPass::FindFunctionWorkerPrepass(duint Start, duint End, std::vector<FunctionDef>* Blocks)
{
const duint minFunc = std::next(m_MainBlocks.begin(), Start)->VirtualStart;
const duint maxFunc = std::next(m_MainBlocks.begin(), End - 1)->VirtualEnd;
#ifdef _WIN64
// RUNTIME_FUNCTION exception information
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
{
const duint funcAddr = m_ModuleStart + Function->BeginAddress;
const duint funcEnd = m_ModuleStart + Function->EndAddress;
// If within limits...
if(funcAddr >= minFunc && funcAddr < maxFunc)
{
// Add the descriptor
FunctionDef def;
def.VirtualStart = funcAddr;
def.VirtualEnd = funcEnd;
def.BBlockStart = 0;
def.BBlockEnd = 0;
Blocks->push_back(def);
}
return true;
});
#endif // _WIN64
// Module exports (return value ignored)
apienumexports(m_ModuleStart, [&](duint Base, const char* Module, const char* Name, duint Address)
{
// If within limits...
if(Address >= minFunc && Address < maxFunc)
{
// Add the descriptor
FunctionDef def;
def.VirtualStart = Address;
def.VirtualEnd = 0;
def.BBlockStart = 0;
def.BBlockEnd = 0;
Blocks->push_back(def);
}
});
}
void FunctionPass::FindFunctionWorker(std::vector<FunctionDef>* Blocks)
{
// Cached final block
BasicBlock* finalBlock = &m_MainBlocks.back();
// Enumerate all function entries for this thread
for(auto & block : *Blocks)
{
// Sometimes the ending address is already supplied, so
// check first
if(block.VirtualEnd != 0)
{
if(ResolveKnownFunctionEnd(&block))
continue;
}
// Now the function end must be determined by heuristics (find manually)
ResolveFunctionEnd(&block, finalBlock);
}
}
bool FunctionPass::ResolveKnownFunctionEnd(FunctionDef* Function)
{
// Helper to link final blocks to function
auto startBlock = FindBBlockInRange(Function->VirtualStart);
auto endBlock = FindBBlockInRange(Function->VirtualEnd);
if(!startBlock || !endBlock)
return false;
// Find block start/end indices
Function->BBlockStart = FindBBlockIndex(startBlock);
Function->BBlockEnd = FindBBlockIndex(endBlock);
// Set the flag for blocks that have been scanned
for(BasicBlock* block = startBlock; (duint)block <= (duint)endBlock; block++)
block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION);
return true;
}
bool FunctionPass::ResolveFunctionEnd(FunctionDef* Function, BasicBlock* LastBlock)
{
ASSERT_TRUE(Function->VirtualStart != 0);
// Find the first basic block of the function
BasicBlock* block = FindBBlockInRange(Function->VirtualStart);
if(!block)
{
ASSERT_ALWAYS("Block should exist at this point");
return false;
}
// The maximum address is determined by any jump that extends past
// a RET or other terminating basic block. A function may have multiple
// return statements.
duint maximumAddr = 0;
// Loop forever until the end is found
for(; (duint)block <= (duint)LastBlock; block++)
{
// Block is now in use
block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION);
// Calculate max from just linear instructions
maximumAddr = max(maximumAddr, block->VirtualEnd - 1);
// Find maximum jump target
if(!block->GetFlag(BASIC_BLOCK_FLAG_CALL) && !block->GetFlag(BASIC_BLOCK_FLAG_INDIRECT))
{
if(block->Target != 0)
{
// Here's a problem: Compilers add tail-call elimination with a jump.
// Solve this by creating a maximum jump limit: +/- 512 bytes from the end.
//
// abs(block->VirtualEnd - block->Target) -- unsigned
if(min(block->VirtualEnd - block->Target, block->Target - block->VirtualEnd) <= 512)
maximumAddr = max(maximumAddr, block->Target);
}
}
// Sanity check
ASSERT_TRUE(maximumAddr >= block->VirtualStart);
// Does this node contain the maximum address?
if(maximumAddr >= block->VirtualStart && maximumAddr < block->VirtualEnd)
{
// It does! There's 4 possibilities next:
//
// 1. Return
// 2. Tail-call elimination
// 3. Optimized loop
// 4. Function continues to next block
//
// 1.
if(block->GetFlag(BASIC_BLOCK_FLAG_RET))
break;
if(block->Target != 0)
{
// NOTE: Both must be an absolute jump
if(block->GetFlag(BASIC_BLOCK_FLAG_ABSJMP))
{
// 2.
//
// abs(block->VirtualEnd - block->Target) -- unsigned
if(min(block->VirtualEnd - block->Target, block->Target - block->VirtualEnd) > 128)
break;
// 3.
if(block->Target >= Function->VirtualStart && block->Target < block->VirtualEnd)
break;
}
}
// 4. Continue
}
}
// Loop is done. Set the information in the function structure.
Function->VirtualEnd = block->VirtualEnd;
Function->BBlockEnd = FindBBlockIndex(block);
return true;
}
#ifdef _WIN64
void FunctionPass::EnumerateFunctionRuntimeEntries64(std::function<bool (PRUNTIME_FUNCTION)> Callback)
{
if(!m_FunctionInfo)
return;
// Get the table pointer and size
auto functionTable = (PRUNTIME_FUNCTION)m_FunctionInfo;
ULONG totalCount = (m_FunctionInfoSize / sizeof(RUNTIME_FUNCTION));
// Enumerate each entry
for(ULONG i = 0; i < totalCount; i++)
{
if(!Callback(&functionTable[i]))
break;
}
}
#endif // _WIN64

View File

@ -1,32 +1,32 @@
#pragma once
#include <functional>
#include "AnalysisPass.h"
#include "BasicBlock.h"
class FunctionPass : public AnalysisPass
{
public:
FunctionPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks);
virtual ~FunctionPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
private:
duint m_ModuleStart;
PVOID m_FunctionInfo;
ULONG m_FunctionInfoSize;
void AnalysisWorker(duint Start, duint End, std::vector<FunctionDef>* Blocks);
void FindFunctionWorkerPrepass(duint Start, duint End, std::vector<FunctionDef>* Blocks);
void FindFunctionWorker(std::vector<FunctionDef>* Blocks);
bool ResolveKnownFunctionEnd(FunctionDef* Function);
bool ResolveFunctionEnd(FunctionDef* Function, BasicBlock* LastBlock);
#ifdef _WIN64
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
#endif // _WIN64
#pragma once
#include <functional>
#include "AnalysisPass.h"
#include "BasicBlock.h"
class FunctionPass : public AnalysisPass
{
public:
FunctionPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks);
virtual ~FunctionPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
private:
duint m_ModuleStart;
PVOID m_FunctionInfo;
ULONG m_FunctionInfoSize;
void AnalysisWorker(duint Start, duint End, std::vector<FunctionDef>* Blocks);
void FindFunctionWorkerPrepass(duint Start, duint End, std::vector<FunctionDef>* Blocks);
void FindFunctionWorker(std::vector<FunctionDef>* Blocks);
bool ResolveKnownFunctionEnd(FunctionDef* Function);
bool ResolveFunctionEnd(FunctionDef* Function, BasicBlock* LastBlock);
#ifdef _WIN64
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
#endif // _WIN64
};

View File

@ -1,327 +1,327 @@
#include <thread>
#include <ppl.h>
#include "AnalysisPass.h"
#include "LinearPass.h"
#include <capstone_wrapper.h>
LinearPass::LinearPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
{
// This is a fix for when the total data analysis size is less
// than what parallelization can support. The minimum size requirement
// is ((# THREADS) * (512)) bytes. If the requirement isn't met,
// scale to use a single thread.
if((512 * IdealThreadCount()) >= m_DataSize)
SetIdealThreadCount(1);
}
LinearPass::~LinearPass()
{
}
const char* LinearPass::GetName()
{
return "Linear Scandown";
}
bool LinearPass::Analyse()
{
// Divide the work up between each thread
// THREAD_WORK = (TOTAL / # THREADS)
duint workAmount = m_DataSize / IdealThreadCount();
// Initialize thread vector
auto threadBlocks = new std::vector<BasicBlock>[IdealThreadCount()];
concurrency::parallel_for(duint (0), IdealThreadCount(), [&](duint i)
{
duint threadWorkStart = m_VirtualStart + (workAmount * i);
duint threadWorkStop = min((threadWorkStart + workAmount), m_VirtualEnd);
// Allow a 256-byte variance of scanning because of
// integer rounding errors and instruction overlap
if(threadWorkStart > m_VirtualStart)
{
threadWorkStart = max((threadWorkStart - 256), m_VirtualStart);
threadWorkStop = min((threadWorkStop + 256), m_VirtualEnd);
}
// Memory allocation optimization
// TODO: Option to conserve memory
threadBlocks[i].reserve(100000);
// Execute
AnalysisWorker(threadWorkStart, threadWorkStop, &threadBlocks[i]);
});
// Clear old data and combine vectors
m_MainBlocks.clear();
for(duint i = 0; i < IdealThreadCount(); i++)
{
std::move(threadBlocks[i].begin(), threadBlocks[i].end(), std::back_inserter(m_MainBlocks));
// Free old elements to conserve memory further
BBlockArray().swap(threadBlocks[i]);
}
// Free memory ASAP
delete[] threadBlocks;
// Sort and remove duplicates
std::sort(m_MainBlocks.begin(), m_MainBlocks.end());
m_MainBlocks.erase(std::unique(m_MainBlocks.begin(), m_MainBlocks.end()), m_MainBlocks.end());
// Run overlap analysis sub-pass
AnalyseOverlaps();
return true;
}
void LinearPass::AnalyseOverlaps()
{
// Goal of this function:
//
// Remove all overlapping
// basic blocks because of threads not ending or
// starting at absolutely defined points.
// (Example: one thread starts in the middle of
// an instruction)
//
// This also checks for basic block targets jumping into
// the middle of other basic blocks.
//
// THREAD_WORK = ceil(TOTAL / # THREADS)
duint workTotal = m_MainBlocks.size();
duint workAmount = (workTotal + (IdealThreadCount() - 1)) / IdealThreadCount();
// Initialize thread vectors
auto threadInserts = new std::vector<BasicBlock>[IdealThreadCount()];
concurrency::parallel_for(duint (0), IdealThreadCount(), [&](duint i)
{
duint threadWorkStart = (workAmount * i);
duint threadWorkStop = min((threadWorkStart + workAmount), workTotal);
// Again, allow an overlap of +/- 1 entry
if(threadWorkStart > 0)
{
threadWorkStart = max((threadWorkStart - 1), 0);
threadWorkStop = min((threadWorkStop + 1), workTotal);
}
// Execute
AnalysisOverlapWorker(threadWorkStart, threadWorkStop, &threadInserts[i]);
});
// THREAD VECTOR
std::vector<BasicBlock> overlapInserts;
{
for(duint i = 0; i < IdealThreadCount(); i++)
std::move(threadInserts[i].begin(), threadInserts[i].end(), std::back_inserter(overlapInserts));
// Sort and remove duplicates
std::sort(overlapInserts.begin(), overlapInserts.end());
overlapInserts.erase(std::unique(overlapInserts.begin(), overlapInserts.end()), overlapInserts.end());
delete[] threadInserts;
}
// GLOBAL VECTOR
{
// Erase blocks marked for deletion
m_MainBlocks.erase(std::remove_if(m_MainBlocks.begin(), m_MainBlocks.end(), [](BasicBlock & Elem)
{
return Elem.GetFlag(BASIC_BLOCK_FLAG_DELETE);
}));
// Insert
std::move(overlapInserts.begin(), overlapInserts.end(), std::back_inserter(m_MainBlocks));
// Final sort
std::sort(m_MainBlocks.begin(), m_MainBlocks.end());
}
}
void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
{
Capstone disasm;
duint blockBegin = Start; // BBlock starting virtual address
duint blockEnd; // BBlock ending virtual address
bool blockPrevPad = false; // Indicator if the last instruction was padding
BasicBlock* lastBlock = nullptr;// Avoid an expensive call to std::vector::back()
for(duint i = Start; i < End;)
{
if(!disasm.Disassemble(i, TranslateAddress(i)))
{
// Skip instructions that can't be determined
i++;
continue;
}
// Increment counter
i += disasm.Size();
blockEnd = i;
// The basic block ends here if it is a branch
bool call = disasm.InGroup(CS_GRP_CALL); // CALL
bool jmp = disasm.InGroup(CS_GRP_JUMP); // JUMP
bool ret = disasm.InGroup(CS_GRP_RET); // RETURN
bool padding = disasm.IsFilling(); // INSTRUCTION PADDING
if(padding)
{
// PADDING is treated differently. They are all created as their
// own separate block for more analysis later.
duint realBlockEnd = blockEnd - disasm.Size();
if((realBlockEnd - blockBegin) > 0)
{
// The next line terminates the BBlock before the INT instruction.
// Early termination, faked as an indirect JMP. Rare case.
lastBlock = CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false);
lastBlock->SetFlag(BASIC_BLOCK_FLAG_PREPAD);
blockBegin = realBlockEnd;
}
}
if(call || jmp || ret || padding)
{
// Was this a padding instruction?
if(padding && blockPrevPad)
{
// Append it to the previous block
lastBlock->VirtualEnd = blockEnd;
}
else
{
// Otherwise use the default route: create a new entry
auto block = lastBlock = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, padding);
// Figure out the operand type
auto operand = disasm.x86().operands[0];
if(operand.type == X86_OP_IMM)
{
// Branch target immediate
block->Target = (duint)operand.imm;
// Check if absolute jump
if(disasm.GetId() == X86_INS_JMP)
block->SetFlag(BASIC_BLOCK_FLAG_ABSJMP);
}
else
{
// Indirects
block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT);
if(operand.type == X86_OP_MEM &&
operand.mem.base == X86_REG_INVALID &&
operand.mem.index == X86_REG_INVALID &&
operand.mem.scale == 1)
{
block->SetFlag(BASIC_BLOCK_FLAG_INDIRPTR);
block->Target = (duint)operand.mem.disp;
}
}
}
// Reset the loop variables
blockBegin = i;
blockPrevPad = padding;
}
}
}
void LinearPass::AnalysisOverlapWorker(duint Start, duint End, BBlockArray* Insertions)
{
// Comparison function to see if two blocks overlap
auto BlockOverlapsRemove = [](BasicBlock * A, BasicBlock * B) -> BasicBlock*
{
// Do the blocks overlap?
if(max(A->VirtualStart, B->VirtualStart) <= min((A->VirtualEnd - 1), (B->VirtualEnd - 1)))
{
// Return the block that should be removed
if(A->Size() > B->Size())
return B;
return A;
}
return nullptr;
};
// Get a pointer to pure data
const auto blocks = m_MainBlocks.data();
for(duint i = Start; i < End; i++)
{
const auto curr = &blocks[i];
const auto next = &blocks[i + 1];
// Current versus next (overlap -> delete)
BasicBlock* removal = BlockOverlapsRemove(curr, next);
if(removal)
removal->SetFlag(BASIC_BLOCK_FLAG_DELETE);
// Find blocks that need to be split in two because
// of CALL/JMP targets
//
// Find targets in the virtual range
if(ValidateAddress(curr->Target))
{
removal = FindBBlockInRange(curr->Target);
// If the target does not equal the block start...
if(removal && curr->Target != removal->VirtualStart)
{
// Mark for deletion
removal->SetFlag(BASIC_BLOCK_FLAG_DELETE);
// Block part 1
BasicBlock block1;
block1.VirtualStart = removal->VirtualStart;
block1.VirtualEnd = curr->Target;
block1.Target = 0;
block1.Flags = BASIC_BLOCK_FLAG_CUTOFF;
// Block part 2
BasicBlock block2;
block2.VirtualStart = curr->Target;
block2.VirtualEnd = removal->VirtualEnd;
block2.Target = removal->Target;
block2.Flags = removal->Flags;
Insertions->push_back(block1);
Insertions->push_back(block2);
}
}
}
}
BasicBlock* LinearPass::CreateBlockWorker(std::vector<BasicBlock>* Blocks, duint Start, duint End, bool Call, bool Jmp, bool Ret, bool Pad)
{
BasicBlock block;
block.VirtualStart = Start;
block.VirtualEnd = End;
block.Flags = 0;
block.Target = 0;
// Check for calls
if(Call)
block.SetFlag(BASIC_BLOCK_FLAG_CALL);
// Check for returns
if(Ret)
block.SetFlag(BASIC_BLOCK_FLAG_RET);
// Check for interrupts
if(Pad)
block.SetFlag(BASIC_BLOCK_FLAG_PAD);
Blocks->push_back(block);
return &Blocks->back();
#include <thread>
#include <ppl.h>
#include "AnalysisPass.h"
#include "LinearPass.h"
#include <capstone_wrapper.h>
LinearPass::LinearPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
{
// This is a fix for when the total data analysis size is less
// than what parallelization can support. The minimum size requirement
// is ((# THREADS) * (512)) bytes. If the requirement isn't met,
// scale to use a single thread.
if((512 * IdealThreadCount()) >= m_DataSize)
SetIdealThreadCount(1);
}
LinearPass::~LinearPass()
{
}
const char* LinearPass::GetName()
{
return "Linear Scandown";
}
bool LinearPass::Analyse()
{
// Divide the work up between each thread
// THREAD_WORK = (TOTAL / # THREADS)
duint workAmount = m_DataSize / IdealThreadCount();
// Initialize thread vector
auto threadBlocks = new std::vector<BasicBlock>[IdealThreadCount()];
concurrency::parallel_for(duint (0), IdealThreadCount(), [&](duint i)
{
duint threadWorkStart = m_VirtualStart + (workAmount * i);
duint threadWorkStop = min((threadWorkStart + workAmount), m_VirtualEnd);
// Allow a 256-byte variance of scanning because of
// integer rounding errors and instruction overlap
if(threadWorkStart > m_VirtualStart)
{
threadWorkStart = max((threadWorkStart - 256), m_VirtualStart);
threadWorkStop = min((threadWorkStop + 256), m_VirtualEnd);
}
// Memory allocation optimization
// TODO: Option to conserve memory
threadBlocks[i].reserve(100000);
// Execute
AnalysisWorker(threadWorkStart, threadWorkStop, &threadBlocks[i]);
});
// Clear old data and combine vectors
m_MainBlocks.clear();
for(duint i = 0; i < IdealThreadCount(); i++)
{
std::move(threadBlocks[i].begin(), threadBlocks[i].end(), std::back_inserter(m_MainBlocks));
// Free old elements to conserve memory further
BBlockArray().swap(threadBlocks[i]);
}
// Free memory ASAP
delete[] threadBlocks;
// Sort and remove duplicates
std::sort(m_MainBlocks.begin(), m_MainBlocks.end());
m_MainBlocks.erase(std::unique(m_MainBlocks.begin(), m_MainBlocks.end()), m_MainBlocks.end());
// Run overlap analysis sub-pass
AnalyseOverlaps();
return true;
}
void LinearPass::AnalyseOverlaps()
{
// Goal of this function:
//
// Remove all overlapping
// basic blocks because of threads not ending or
// starting at absolutely defined points.
// (Example: one thread starts in the middle of
// an instruction)
//
// This also checks for basic block targets jumping into
// the middle of other basic blocks.
//
// THREAD_WORK = ceil(TOTAL / # THREADS)
duint workTotal = m_MainBlocks.size();
duint workAmount = (workTotal + (IdealThreadCount() - 1)) / IdealThreadCount();
// Initialize thread vectors
auto threadInserts = new std::vector<BasicBlock>[IdealThreadCount()];
concurrency::parallel_for(duint (0), IdealThreadCount(), [&](duint i)
{
duint threadWorkStart = (workAmount * i);
duint threadWorkStop = min((threadWorkStart + workAmount), workTotal);
// Again, allow an overlap of +/- 1 entry
if(threadWorkStart > 0)
{
threadWorkStart = max((threadWorkStart - 1), 0);
threadWorkStop = min((threadWorkStop + 1), workTotal);
}
// Execute
AnalysisOverlapWorker(threadWorkStart, threadWorkStop, &threadInserts[i]);
});
// THREAD VECTOR
std::vector<BasicBlock> overlapInserts;
{
for(duint i = 0; i < IdealThreadCount(); i++)
std::move(threadInserts[i].begin(), threadInserts[i].end(), std::back_inserter(overlapInserts));
// Sort and remove duplicates
std::sort(overlapInserts.begin(), overlapInserts.end());
overlapInserts.erase(std::unique(overlapInserts.begin(), overlapInserts.end()), overlapInserts.end());
delete[] threadInserts;
}
// GLOBAL VECTOR
{
// Erase blocks marked for deletion
m_MainBlocks.erase(std::remove_if(m_MainBlocks.begin(), m_MainBlocks.end(), [](BasicBlock & Elem)
{
return Elem.GetFlag(BASIC_BLOCK_FLAG_DELETE);
}));
// Insert
std::move(overlapInserts.begin(), overlapInserts.end(), std::back_inserter(m_MainBlocks));
// Final sort
std::sort(m_MainBlocks.begin(), m_MainBlocks.end());
}
}
void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
{
Capstone disasm;
duint blockBegin = Start; // BBlock starting virtual address
duint blockEnd; // BBlock ending virtual address
bool blockPrevPad = false; // Indicator if the last instruction was padding
BasicBlock* lastBlock = nullptr;// Avoid an expensive call to std::vector::back()
for(duint i = Start; i < End;)
{
if(!disasm.Disassemble(i, TranslateAddress(i)))
{
// Skip instructions that can't be determined
i++;
continue;
}
// Increment counter
i += disasm.Size();
blockEnd = i;
// The basic block ends here if it is a branch
bool call = disasm.InGroup(CS_GRP_CALL); // CALL
bool jmp = disasm.InGroup(CS_GRP_JUMP); // JUMP
bool ret = disasm.InGroup(CS_GRP_RET); // RETURN
bool padding = disasm.IsFilling(); // INSTRUCTION PADDING
if(padding)
{
// PADDING is treated differently. They are all created as their
// own separate block for more analysis later.
duint realBlockEnd = blockEnd - disasm.Size();
if((realBlockEnd - blockBegin) > 0)
{
// The next line terminates the BBlock before the INT instruction.
// Early termination, faked as an indirect JMP. Rare case.
lastBlock = CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false);
lastBlock->SetFlag(BASIC_BLOCK_FLAG_PREPAD);
blockBegin = realBlockEnd;
}
}
if(call || jmp || ret || padding)
{
// Was this a padding instruction?
if(padding && blockPrevPad)
{
// Append it to the previous block
lastBlock->VirtualEnd = blockEnd;
}
else
{
// Otherwise use the default route: create a new entry
auto block = lastBlock = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, padding);
// Figure out the operand type
auto operand = disasm.x86().operands[0];
if(operand.type == X86_OP_IMM)
{
// Branch target immediate
block->Target = (duint)operand.imm;
// Check if absolute jump
if(disasm.GetId() == X86_INS_JMP)
block->SetFlag(BASIC_BLOCK_FLAG_ABSJMP);
}
else
{
// Indirects
block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT);
if(operand.type == X86_OP_MEM &&
operand.mem.base == X86_REG_INVALID &&
operand.mem.index == X86_REG_INVALID &&
operand.mem.scale == 1)
{
block->SetFlag(BASIC_BLOCK_FLAG_INDIRPTR);
block->Target = (duint)operand.mem.disp;
}
}
}
// Reset the loop variables
blockBegin = i;
blockPrevPad = padding;
}
}
}
void LinearPass::AnalysisOverlapWorker(duint Start, duint End, BBlockArray* Insertions)
{
// Comparison function to see if two blocks overlap
auto BlockOverlapsRemove = [](BasicBlock * A, BasicBlock * B) -> BasicBlock*
{
// Do the blocks overlap?
if(max(A->VirtualStart, B->VirtualStart) <= min((A->VirtualEnd - 1), (B->VirtualEnd - 1)))
{
// Return the block that should be removed
if(A->Size() > B->Size())
return B;
return A;
}
return nullptr;
};
// Get a pointer to pure data
const auto blocks = m_MainBlocks.data();
for(duint i = Start; i < End; i++)
{
const auto curr = &blocks[i];
const auto next = &blocks[i + 1];
// Current versus next (overlap -> delete)
BasicBlock* removal = BlockOverlapsRemove(curr, next);
if(removal)
removal->SetFlag(BASIC_BLOCK_FLAG_DELETE);
// Find blocks that need to be split in two because
// of CALL/JMP targets
//
// Find targets in the virtual range
if(ValidateAddress(curr->Target))
{
removal = FindBBlockInRange(curr->Target);
// If the target does not equal the block start...
if(removal && curr->Target != removal->VirtualStart)
{
// Mark for deletion
removal->SetFlag(BASIC_BLOCK_FLAG_DELETE);
// Block part 1
BasicBlock block1;
block1.VirtualStart = removal->VirtualStart;
block1.VirtualEnd = curr->Target;
block1.Target = 0;
block1.Flags = BASIC_BLOCK_FLAG_CUTOFF;
// Block part 2
BasicBlock block2;
block2.VirtualStart = curr->Target;
block2.VirtualEnd = removal->VirtualEnd;
block2.Target = removal->Target;
block2.Flags = removal->Flags;
Insertions->push_back(block1);
Insertions->push_back(block2);
}
}
}
}
BasicBlock* LinearPass::CreateBlockWorker(std::vector<BasicBlock>* Blocks, duint Start, duint End, bool Call, bool Jmp, bool Ret, bool Pad)
{
BasicBlock block;
block.VirtualStart = Start;
block.VirtualEnd = End;
block.Flags = 0;
block.Target = 0;
// Check for calls
if(Call)
block.SetFlag(BASIC_BLOCK_FLAG_CALL);
// Check for returns
if(Ret)
block.SetFlag(BASIC_BLOCK_FLAG_RET);
// Check for interrupts
if(Pad)
block.SetFlag(BASIC_BLOCK_FLAG_PAD);
Blocks->push_back(block);
return &Blocks->back();
}

View File

@ -1,20 +1,20 @@
#pragma once
#include "AnalysisPass.h"
#include "BasicBlock.h"
class LinearPass : public AnalysisPass
{
public:
LinearPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks);
virtual ~LinearPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
void AnalyseOverlaps();
private:
void AnalysisWorker(duint Start, duint End, BBlockArray* Blocks);
void AnalysisOverlapWorker(duint Start, duint End, BBlockArray* Insertions);
BasicBlock* CreateBlockWorker(BBlockArray* Blocks, duint Start, duint End, bool Call, bool Jmp, bool Ret, bool Pad);
#pragma once
#include "AnalysisPass.h"
#include "BasicBlock.h"
class LinearPass : public AnalysisPass
{
public:
LinearPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks);
virtual ~LinearPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
void AnalyseOverlaps();
private:
void AnalysisWorker(duint Start, duint End, BBlockArray* Blocks);
void AnalysisOverlapWorker(duint Start, duint End, BBlockArray* Insertions);
BasicBlock* CreateBlockWorker(BBlockArray* Blocks, duint Start, duint End, bool Call, bool Jmp, bool Ret, bool Pad);
};

File diff suppressed because it is too large Load Diff

View File

@ -1,53 +1,53 @@
#ifndef _XEDPARSE_H
#define _XEDPARSE_H
#include <windows.h>
//XEDParse defines
#ifdef XEDPARSE_BUILD
#define XEDPARSE_EXPORT __declspec(dllexport)
#else
#define XEDPARSE_EXPORT __declspec(dllimport)
#endif //XEDPARSE_BUILD
#define XEDPARSE_CALL //calling convention
#define XEDPARSE_MAXBUFSIZE 256
#define XEDPARSE_MAXASMSIZE 16
//typedefs
typedef bool (XEDPARSE_CALL* CBXEDPARSE_UNKNOWN)(const char* text, ULONGLONG* value);
//XEDParse enums
enum XEDPARSE_STATUS
{
XEDPARSE_ERROR = 0,
XEDPARSE_OK = 1
};
//XEDParse structs
#pragma pack(push,8)
struct XEDPARSE
{
bool x64; // use 64-bit instructions
ULONGLONG cip; //instruction pointer (for relative addressing)
unsigned int dest_size; //destination size (returned by XEDParse)
CBXEDPARSE_UNKNOWN cbUnknown; //unknown operand callback
unsigned char dest[XEDPARSE_MAXASMSIZE]; //destination buffer
char instr[XEDPARSE_MAXBUFSIZE]; //instruction text
char error[XEDPARSE_MAXBUFSIZE]; //error text (in case of an error)
};
#pragma pack(pop)
#ifdef __cplusplus
extern "C"
{
#endif
XEDPARSE_EXPORT XEDPARSE_STATUS XEDPARSE_CALL XEDParseAssemble(XEDPARSE* XEDParse);
#ifdef __cplusplus
}
#endif
#endif // _XEDPARSE_H
#ifndef _XEDPARSE_H
#define _XEDPARSE_H
#include <windows.h>
//XEDParse defines
#ifdef XEDPARSE_BUILD
#define XEDPARSE_EXPORT __declspec(dllexport)
#else
#define XEDPARSE_EXPORT __declspec(dllimport)
#endif //XEDPARSE_BUILD
#define XEDPARSE_CALL //calling convention
#define XEDPARSE_MAXBUFSIZE 256
#define XEDPARSE_MAXASMSIZE 16
//typedefs
typedef bool (XEDPARSE_CALL* CBXEDPARSE_UNKNOWN)(const char* text, ULONGLONG* value);
//XEDParse enums
enum XEDPARSE_STATUS
{
XEDPARSE_ERROR = 0,
XEDPARSE_OK = 1
};
//XEDParse structs
#pragma pack(push,8)
struct XEDPARSE
{
bool x64; // use 64-bit instructions
ULONGLONG cip; //instruction pointer (for relative addressing)
unsigned int dest_size; //destination size (returned by XEDParse)
CBXEDPARSE_UNKNOWN cbUnknown; //unknown operand callback
unsigned char dest[XEDPARSE_MAXASMSIZE]; //destination buffer
char instr[XEDPARSE_MAXBUFSIZE]; //instruction text
char error[XEDPARSE_MAXBUFSIZE]; //error text (in case of an error)
};
#pragma pack(pop)
#ifdef __cplusplus
extern "C"
{
#endif
XEDPARSE_EXPORT XEDPARSE_STATUS XEDPARSE_CALL XEDParseAssemble(XEDPARSE* XEDParse);
#ifdef __cplusplus
}
#endif
#endif // _XEDPARSE_H

View File

@ -1,238 +1,238 @@
/**
@file _dbgfunctions.cpp
@brief Implements the dbgfunctions class.
*/
#include "_global.h"
#include "_dbgfunctions.h"
#include "assemble.h"
#include "debugger.h"
#include "jit.h"
#include "patches.h"
#include "memory.h"
#include "disasm_fast.h"
#include "stackinfo.h"
#include "symbolinfo.h"
#include "module.h"
static DBGFUNCTIONS _dbgfunctions;
const DBGFUNCTIONS* dbgfunctionsget()
{
return &_dbgfunctions;
}
static bool _assembleatex(duint addr, const char* instruction, char* error, bool fillnop)
{
return assembleat(addr, instruction, nullptr, error, fillnop);
}
static bool _sectionfromaddr(duint addr, char* section)
{
HMODULE hMod = (HMODULE)ModBaseFromAddr(addr);
if(!hMod)
return false;
wchar_t curModPath[MAX_PATH] = L"";
if(!GetModuleFileNameExW(fdProcessInfo->hProcess, hMod, curModPath, MAX_PATH))
return false;
HANDLE FileHandle;
DWORD LoadedSize;
HANDLE FileMap;
ULONG_PTR FileMapVA;
if(StaticFileLoadW(curModPath, UE_ACCESS_READ, false, &FileHandle, &LoadedSize, &FileMap, &FileMapVA))
{
duint rva = addr - (duint)hMod;
int sectionNumber = GetPE32SectionNumberFromVA(FileMapVA, GetPE32DataFromMappedFile(FileMapVA, 0, UE_IMAGEBASE) + rva);
if(sectionNumber >= 0)
{
const char* name = (const char*)GetPE32DataFromMappedFile(FileMapVA, sectionNumber, UE_SECTIONNAME);
if(section)
strcpy_s(section, MAX_SECTION_SIZE, name); //maxi
StaticFileUnloadW(curModPath, false, FileHandle, LoadedSize, FileMap, FileMapVA);
return true;
}
StaticFileUnloadW(curModPath, false, FileHandle, LoadedSize, FileMap, FileMapVA);
}
return false;
}
static bool _patchget(duint addr)
{
return PatchGet(addr, nullptr);
}
static bool _patchinrange(duint start, duint end)
{
if(start > end)
std::swap(start, end);
for(duint i = start; i <= end; i++)
{
if(_patchget(i))
return true;
}
return false;
}
static bool _mempatch(duint va, const unsigned char* src, duint size)
{
return MemPatch(va, src, size, nullptr);
}
static void _patchrestorerange(duint start, duint end)
{
if(start > end)
std::swap(start, end);
for(duint i = start; i <= end; i++)
PatchDelete(i, true);
GuiUpdatePatches();
}
static bool _patchrestore(duint addr)
{
return PatchDelete(addr, true);
}
static void _getcallstack(DBGCALLSTACK* callstack)
{
stackgetcallstack(GetContextDataEx(hActiveThread, UE_CSP), (CALLSTACK*)callstack);
}
static bool _getjitauto(bool* jit_auto)
{
return dbggetjitauto(jit_auto, notfound, NULL, NULL);
}
static bool _getcmdline(char* cmd_line, size_t* cbsize)
{
if(!cmd_line && !cbsize)
return false;
char* cmdline;
if(!dbggetcmdline(&cmdline, NULL))
return false;
if(!cmd_line && cbsize)
*cbsize = strlen(cmdline) + sizeof(char);
else if(cmd_line)
strcpy(cmd_line, cmdline);
efree(cmdline, "_getcmdline:cmdline");
return true;
}
static bool _setcmdline(const char* cmd_line)
{
return dbgsetcmdline(cmd_line, nullptr);
}
static bool _getjit(char* jit, bool jit64)
{
arch dummy;
char jit_tmp[JIT_ENTRY_MAX_SIZE] = "";
if(jit != NULL)
{
if(!dbggetjit(jit_tmp, jit64 ? x64 : x32, &dummy, NULL))
return false;
strcpy_s(jit, MAX_SETTING_SIZE, jit_tmp);
}
else // if jit input == NULL: it returns false if there are not an OLD JIT STORED.
{
char oldjit[MAX_SETTING_SIZE] = "";
if(!BridgeSettingGet("JIT", "Old", (char*) & oldjit))
return false;
}
return true;
}
bool _getprocesslist(DBGPROCESSINFO** entries, int* count)
{
std::vector<PROCESSENTRY32> list;
if(!dbglistprocesses(&list))
return false;
*count = (int)list.size();
if(!*count)
return false;
*entries = (DBGPROCESSINFO*)BridgeAlloc(*count * sizeof(DBGPROCESSINFO));
for(int i = 0; i < *count; i++)
{
(*entries)[*count - i - 1].dwProcessId = list.at(i).th32ProcessID;
strcpy_s((*entries)[*count - i - 1].szExeFile, list.at(i).szExeFile);
}
return true;
}
static void _memupdatemap()
{
MemUpdateMap();
GuiUpdateMemoryView();
}
static duint _getaddrfromline(const char* szSourceFile, int line)
{
LONG displacement = 0;
IMAGEHLP_LINE64 lineData;
memset(&lineData, 0, sizeof(lineData));
lineData.SizeOfStruct = sizeof(lineData);
if(!SymGetLineFromName64(fdProcessInfo->hProcess, NULL, szSourceFile, line, &displacement, &lineData))
return 0;
return (duint)lineData.Address;
}
static bool _getsourcefromaddr(duint addr, char* szSourceFile, int* line)
{
char sourceFile[MAX_STRING_SIZE] = "";
if(!SymGetSourceLine(addr, sourceFile, line))
return false;
if(!FileExists(sourceFile))
return false;
if(szSourceFile)
strcpy_s(szSourceFile, MAX_STRING_SIZE, sourceFile);
return true;
}
static bool _valfromstring(const char* string, duint* value)
{
return valfromstring(string, value);
}
void dbgfunctionsinit()
{
_dbgfunctions.AssembleAtEx = _assembleatex;
_dbgfunctions.SectionFromAddr = _sectionfromaddr;
_dbgfunctions.ModNameFromAddr = ModNameFromAddr;
_dbgfunctions.ModBaseFromAddr = ModBaseFromAddr;
_dbgfunctions.ModBaseFromName = ModBaseFromName;
_dbgfunctions.ModSizeFromAddr = ModSizeFromAddr;
_dbgfunctions.Assemble = assemble;
_dbgfunctions.PatchGet = _patchget;
_dbgfunctions.PatchInRange = _patchinrange;
_dbgfunctions.MemPatch = _mempatch;
_dbgfunctions.PatchRestoreRange = _patchrestorerange;
_dbgfunctions.PatchEnum = (PATCHENUM)PatchEnum;
_dbgfunctions.PatchRestore = _patchrestore;
_dbgfunctions.PatchFile = (PATCHFILE)PatchFile;
_dbgfunctions.ModPathFromAddr = ModPathFromAddr;
_dbgfunctions.ModPathFromName = ModPathFromName;
_dbgfunctions.DisasmFast = disasmfast;
_dbgfunctions.MemUpdateMap = _memupdatemap;
_dbgfunctions.GetCallStack = _getcallstack;
_dbgfunctions.SymbolDownloadAllSymbols = SymDownloadAllSymbols;
_dbgfunctions.GetJit = _getjit;
_dbgfunctions.GetJitAuto = _getjitauto;
_dbgfunctions.GetDefJit = dbggetdefjit;
_dbgfunctions.GetProcessList = _getprocesslist;
_dbgfunctions.GetPageRights = MemGetPageRights;
_dbgfunctions.SetPageRights = MemSetPageRights;
_dbgfunctions.PageRightsToString = MemPageRightsToString;
_dbgfunctions.IsProcessElevated = IsProcessElevated;
_dbgfunctions.GetCmdline = _getcmdline;
_dbgfunctions.SetCmdline = _setcmdline;
_dbgfunctions.FileOffsetToVa = valfileoffsettova;
_dbgfunctions.VaToFileOffset = valvatofileoffset;
_dbgfunctions.GetAddrFromLine = _getaddrfromline;
_dbgfunctions.GetSourceFromAddr = _getsourcefromaddr;
_dbgfunctions.ValFromString = _valfromstring;
}
/**
@file _dbgfunctions.cpp
@brief Implements the dbgfunctions class.
*/
#include "_global.h"
#include "_dbgfunctions.h"
#include "assemble.h"
#include "debugger.h"
#include "jit.h"
#include "patches.h"
#include "memory.h"
#include "disasm_fast.h"
#include "stackinfo.h"
#include "symbolinfo.h"
#include "module.h"
static DBGFUNCTIONS _dbgfunctions;
const DBGFUNCTIONS* dbgfunctionsget()
{
return &_dbgfunctions;
}
static bool _assembleatex(duint addr, const char* instruction, char* error, bool fillnop)
{
return assembleat(addr, instruction, nullptr, error, fillnop);
}
static bool _sectionfromaddr(duint addr, char* section)
{
HMODULE hMod = (HMODULE)ModBaseFromAddr(addr);
if(!hMod)
return false;
wchar_t curModPath[MAX_PATH] = L"";
if(!GetModuleFileNameExW(fdProcessInfo->hProcess, hMod, curModPath, MAX_PATH))
return false;
HANDLE FileHandle;
DWORD LoadedSize;
HANDLE FileMap;
ULONG_PTR FileMapVA;
if(StaticFileLoadW(curModPath, UE_ACCESS_READ, false, &FileHandle, &LoadedSize, &FileMap, &FileMapVA))
{
duint rva = addr - (duint)hMod;
int sectionNumber = GetPE32SectionNumberFromVA(FileMapVA, GetPE32DataFromMappedFile(FileMapVA, 0, UE_IMAGEBASE) + rva);
if(sectionNumber >= 0)
{
const char* name = (const char*)GetPE32DataFromMappedFile(FileMapVA, sectionNumber, UE_SECTIONNAME);
if(section)
strcpy_s(section, MAX_SECTION_SIZE, name); //maxi
StaticFileUnloadW(curModPath, false, FileHandle, LoadedSize, FileMap, FileMapVA);
return true;
}
StaticFileUnloadW(curModPath, false, FileHandle, LoadedSize, FileMap, FileMapVA);
}
return false;
}
static bool _patchget(duint addr)
{
return PatchGet(addr, nullptr);
}
static bool _patchinrange(duint start, duint end)
{
if(start > end)
std::swap(start, end);
for(duint i = start; i <= end; i++)
{
if(_patchget(i))
return true;
}
return false;
}
static bool _mempatch(duint va, const unsigned char* src, duint size)
{
return MemPatch(va, src, size, nullptr);
}
static void _patchrestorerange(duint start, duint end)
{
if(start > end)
std::swap(start, end);
for(duint i = start; i <= end; i++)
PatchDelete(i, true);
GuiUpdatePatches();
}
static bool _patchrestore(duint addr)
{
return PatchDelete(addr, true);
}
static void _getcallstack(DBGCALLSTACK* callstack)
{
stackgetcallstack(GetContextDataEx(hActiveThread, UE_CSP), (CALLSTACK*)callstack);
}
static bool _getjitauto(bool* jit_auto)
{
return dbggetjitauto(jit_auto, notfound, NULL, NULL);
}
static bool _getcmdline(char* cmd_line, size_t* cbsize)
{
if(!cmd_line && !cbsize)
return false;
char* cmdline;
if(!dbggetcmdline(&cmdline, NULL))
return false;
if(!cmd_line && cbsize)
*cbsize = strlen(cmdline) + sizeof(char);
else if(cmd_line)
strcpy(cmd_line, cmdline);
efree(cmdline, "_getcmdline:cmdline");
return true;
}
static bool _setcmdline(const char* cmd_line)
{
return dbgsetcmdline(cmd_line, nullptr);
}
static bool _getjit(char* jit, bool jit64)
{
arch dummy;
char jit_tmp[JIT_ENTRY_MAX_SIZE] = "";
if(jit != NULL)
{
if(!dbggetjit(jit_tmp, jit64 ? x64 : x32, &dummy, NULL))
return false;
strcpy_s(jit, MAX_SETTING_SIZE, jit_tmp);
}
else // if jit input == NULL: it returns false if there are not an OLD JIT STORED.
{
char oldjit[MAX_SETTING_SIZE] = "";
if(!BridgeSettingGet("JIT", "Old", (char*) & oldjit))
return false;
}
return true;
}
bool _getprocesslist(DBGPROCESSINFO** entries, int* count)
{
std::vector<PROCESSENTRY32> list;
if(!dbglistprocesses(&list))
return false;
*count = (int)list.size();
if(!*count)
return false;
*entries = (DBGPROCESSINFO*)BridgeAlloc(*count * sizeof(DBGPROCESSINFO));
for(int i = 0; i < *count; i++)
{
(*entries)[*count - i - 1].dwProcessId = list.at(i).th32ProcessID;
strcpy_s((*entries)[*count - i - 1].szExeFile, list.at(i).szExeFile);
}
return true;
}
static void _memupdatemap()
{
MemUpdateMap();
GuiUpdateMemoryView();
}
static duint _getaddrfromline(const char* szSourceFile, int line)
{
LONG displacement = 0;
IMAGEHLP_LINE64 lineData;
memset(&lineData, 0, sizeof(lineData));
lineData.SizeOfStruct = sizeof(lineData);
if(!SymGetLineFromName64(fdProcessInfo->hProcess, NULL, szSourceFile, line, &displacement, &lineData))
return 0;
return (duint)lineData.Address;
}
static bool _getsourcefromaddr(duint addr, char* szSourceFile, int* line)
{
char sourceFile[MAX_STRING_SIZE] = "";
if(!SymGetSourceLine(addr, sourceFile, line))
return false;
if(!FileExists(sourceFile))
return false;
if(szSourceFile)
strcpy_s(szSourceFile, MAX_STRING_SIZE, sourceFile);
return true;
}
static bool _valfromstring(const char* string, duint* value)
{
return valfromstring(string, value);
}
void dbgfunctionsinit()
{
_dbgfunctions.AssembleAtEx = _assembleatex;
_dbgfunctions.SectionFromAddr = _sectionfromaddr;
_dbgfunctions.ModNameFromAddr = ModNameFromAddr;
_dbgfunctions.ModBaseFromAddr = ModBaseFromAddr;
_dbgfunctions.ModBaseFromName = ModBaseFromName;
_dbgfunctions.ModSizeFromAddr = ModSizeFromAddr;
_dbgfunctions.Assemble = assemble;
_dbgfunctions.PatchGet = _patchget;
_dbgfunctions.PatchInRange = _patchinrange;
_dbgfunctions.MemPatch = _mempatch;
_dbgfunctions.PatchRestoreRange = _patchrestorerange;
_dbgfunctions.PatchEnum = (PATCHENUM)PatchEnum;
_dbgfunctions.PatchRestore = _patchrestore;
_dbgfunctions.PatchFile = (PATCHFILE)PatchFile;
_dbgfunctions.ModPathFromAddr = ModPathFromAddr;
_dbgfunctions.ModPathFromName = ModPathFromName;
_dbgfunctions.DisasmFast = disasmfast;
_dbgfunctions.MemUpdateMap = _memupdatemap;
_dbgfunctions.GetCallStack = _getcallstack;
_dbgfunctions.SymbolDownloadAllSymbols = SymDownloadAllSymbols;
_dbgfunctions.GetJit = _getjit;
_dbgfunctions.GetJitAuto = _getjitauto;
_dbgfunctions.GetDefJit = dbggetdefjit;
_dbgfunctions.GetProcessList = _getprocesslist;
_dbgfunctions.GetPageRights = MemGetPageRights;
_dbgfunctions.SetPageRights = MemSetPageRights;
_dbgfunctions.PageRightsToString = MemPageRightsToString;
_dbgfunctions.IsProcessElevated = IsProcessElevated;
_dbgfunctions.GetCmdline = _getcmdline;
_dbgfunctions.SetCmdline = _setcmdline;
_dbgfunctions.FileOffsetToVa = valfileoffsettova;
_dbgfunctions.VaToFileOffset = valvatofileoffset;
_dbgfunctions.GetAddrFromLine = _getaddrfromline;
_dbgfunctions.GetSourceFromAddr = _getsourcefromaddr;
_dbgfunctions.ValFromString = _valfromstring;
}

View File

@ -1,118 +1,118 @@
#ifndef _DBGFUNCTIONS_H
#define _DBGFUNCTIONS_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
typedef struct
{
char mod[MAX_MODULE_SIZE];
duint addr;
unsigned char oldbyte;
unsigned char newbyte;
} DBGPATCHINFO;
typedef struct
{
duint addr;
duint from;
duint to;
char comment[MAX_COMMENT_SIZE];
} DBGCALLSTACKENTRY;
typedef struct
{
int total;
DBGCALLSTACKENTRY* entries;
} DBGCALLSTACK;
typedef struct
{
DWORD dwProcessId;
char szExeFile[MAX_PATH];
} DBGPROCESSINFO;
typedef bool (*ASSEMBLEATEX)(duint addr, const char* instruction, char* error, bool fillnop);
typedef bool (*SECTIONFROMADDR)(duint addr, char* section);
typedef bool (*MODNAMEFROMADDR)(duint addr, char* modname, bool extension);
typedef duint (*MODBASEFROMADDR)(duint addr);
typedef duint (*MODBASEFROMNAME)(const char* modname);
typedef duint (*MODSIZEFROMADDR)(duint addr);
typedef bool (*ASSEMBLE)(duint addr, unsigned char* dest, int* size, const char* instruction, char* error);
typedef bool (*PATCHGET)(duint addr);
typedef bool (*PATCHINRANGE)(duint start, duint end);
typedef bool (*MEMPATCH)(duint va, const unsigned char* src, duint size);
typedef void (*PATCHRESTORERANGE)(duint start, duint end);
typedef bool (*PATCHENUM)(DBGPATCHINFO* patchlist, size_t* cbsize);
typedef bool (*PATCHRESTORE)(duint addr);
typedef int (*PATCHFILE)(DBGPATCHINFO* patchlist, int count, const char* szFileName, char* error);
typedef int (*MODPATHFROMADDR)(duint addr, char* path, int size);
typedef int (*MODPATHFROMNAME)(const char* modname, char* path, int size);
typedef bool (*DISASMFAST)(unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* basicinfo);
typedef void (*MEMUPDATEMAP)();
typedef void (*GETCALLSTACK)(DBGCALLSTACK* callstack);
typedef void (*SYMBOLDOWNLOADALLSYMBOLS)(const char* szSymbolStore);
typedef bool (*GETJIT)(char* jit, bool x64);
typedef bool (*GETJITAUTO)(bool* jitauto);
typedef bool (*GETDEFJIT)(char* defjit);
typedef bool (*GETPROCESSLIST)(DBGPROCESSINFO** entries, int* count);
typedef bool (*GETPAGERIGHTS)(duint addr, char* rights);
typedef bool (*SETPAGERIGHTS)(duint addr, const char* rights);
typedef bool (*PAGERIGHTSTOSTRING)(DWORD protect, char* rights);
typedef bool (*ISPROCESSELEVATED)();
typedef bool (*GETCMDLINE)(char* cmdline, size_t* cbsize);
typedef bool (*SETCMDLINE)(const char* cmdline);
typedef duint (*FILEOFFSETTOVA)(const char* modname, duint offset);
typedef duint (*VATOFILEOFFSET)(duint va);
typedef duint (*GETADDRFROMLINE)(const char* szSourceFile, int line);
typedef bool (*GETSOURCEFROMADDR)(duint addr, char* szSourceFile, int* line);
typedef bool (*VALFROMSTRING)(const char* string, duint* value);
typedef struct DBGFUNCTIONS_
{
ASSEMBLEATEX AssembleAtEx;
SECTIONFROMADDR SectionFromAddr;
MODNAMEFROMADDR ModNameFromAddr;
MODBASEFROMADDR ModBaseFromAddr;
MODBASEFROMNAME ModBaseFromName;
MODSIZEFROMADDR ModSizeFromAddr;
ASSEMBLE Assemble;
PATCHGET PatchGet;
PATCHINRANGE PatchInRange;
MEMPATCH MemPatch;
PATCHRESTORERANGE PatchRestoreRange;
PATCHENUM PatchEnum;
PATCHRESTORE PatchRestore;
PATCHFILE PatchFile;
MODPATHFROMADDR ModPathFromAddr;
MODPATHFROMNAME ModPathFromName;
DISASMFAST DisasmFast;
MEMUPDATEMAP MemUpdateMap;
GETCALLSTACK GetCallStack;
SYMBOLDOWNLOADALLSYMBOLS SymbolDownloadAllSymbols;
GETJITAUTO GetJitAuto;
GETJIT GetJit;
GETDEFJIT GetDefJit;
GETPROCESSLIST GetProcessList;
GETPAGERIGHTS GetPageRights;
SETPAGERIGHTS SetPageRights;
PAGERIGHTSTOSTRING PageRightsToString;
ISPROCESSELEVATED IsProcessElevated;
GETCMDLINE GetCmdline;
SETCMDLINE SetCmdline;
FILEOFFSETTOVA FileOffsetToVa;
VATOFILEOFFSET VaToFileOffset;
GETADDRFROMLINE GetAddrFromLine;
GETSOURCEFROMADDR GetSourceFromAddr;
VALFROMSTRING ValFromString;
} DBGFUNCTIONS;
#ifdef BUILD_DBG
const DBGFUNCTIONS* dbgfunctionsget();
void dbgfunctionsinit();
#endif //BUILD_DBG
#endif //_DBGFUNCTIONS_H
#ifndef _DBGFUNCTIONS_H
#define _DBGFUNCTIONS_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
typedef struct
{
char mod[MAX_MODULE_SIZE];
duint addr;
unsigned char oldbyte;
unsigned char newbyte;
} DBGPATCHINFO;
typedef struct
{
duint addr;
duint from;
duint to;
char comment[MAX_COMMENT_SIZE];
} DBGCALLSTACKENTRY;
typedef struct
{
int total;
DBGCALLSTACKENTRY* entries;
} DBGCALLSTACK;
typedef struct
{
DWORD dwProcessId;
char szExeFile[MAX_PATH];
} DBGPROCESSINFO;
typedef bool (*ASSEMBLEATEX)(duint addr, const char* instruction, char* error, bool fillnop);
typedef bool (*SECTIONFROMADDR)(duint addr, char* section);
typedef bool (*MODNAMEFROMADDR)(duint addr, char* modname, bool extension);
typedef duint (*MODBASEFROMADDR)(duint addr);
typedef duint (*MODBASEFROMNAME)(const char* modname);
typedef duint (*MODSIZEFROMADDR)(duint addr);
typedef bool (*ASSEMBLE)(duint addr, unsigned char* dest, int* size, const char* instruction, char* error);
typedef bool (*PATCHGET)(duint addr);
typedef bool (*PATCHINRANGE)(duint start, duint end);
typedef bool (*MEMPATCH)(duint va, const unsigned char* src, duint size);
typedef void (*PATCHRESTORERANGE)(duint start, duint end);
typedef bool (*PATCHENUM)(DBGPATCHINFO* patchlist, size_t* cbsize);
typedef bool (*PATCHRESTORE)(duint addr);
typedef int (*PATCHFILE)(DBGPATCHINFO* patchlist, int count, const char* szFileName, char* error);
typedef int (*MODPATHFROMADDR)(duint addr, char* path, int size);
typedef int (*MODPATHFROMNAME)(const char* modname, char* path, int size);
typedef bool (*DISASMFAST)(unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* basicinfo);
typedef void (*MEMUPDATEMAP)();
typedef void (*GETCALLSTACK)(DBGCALLSTACK* callstack);
typedef void (*SYMBOLDOWNLOADALLSYMBOLS)(const char* szSymbolStore);
typedef bool (*GETJIT)(char* jit, bool x64);
typedef bool (*GETJITAUTO)(bool* jitauto);
typedef bool (*GETDEFJIT)(char* defjit);
typedef bool (*GETPROCESSLIST)(DBGPROCESSINFO** entries, int* count);
typedef bool (*GETPAGERIGHTS)(duint addr, char* rights);
typedef bool (*SETPAGERIGHTS)(duint addr, const char* rights);
typedef bool (*PAGERIGHTSTOSTRING)(DWORD protect, char* rights);
typedef bool (*ISPROCESSELEVATED)();
typedef bool (*GETCMDLINE)(char* cmdline, size_t* cbsize);
typedef bool (*SETCMDLINE)(const char* cmdline);
typedef duint (*FILEOFFSETTOVA)(const char* modname, duint offset);
typedef duint (*VATOFILEOFFSET)(duint va);
typedef duint (*GETADDRFROMLINE)(const char* szSourceFile, int line);
typedef bool (*GETSOURCEFROMADDR)(duint addr, char* szSourceFile, int* line);
typedef bool (*VALFROMSTRING)(const char* string, duint* value);
typedef struct DBGFUNCTIONS_
{
ASSEMBLEATEX AssembleAtEx;
SECTIONFROMADDR SectionFromAddr;
MODNAMEFROMADDR ModNameFromAddr;
MODBASEFROMADDR ModBaseFromAddr;
MODBASEFROMNAME ModBaseFromName;
MODSIZEFROMADDR ModSizeFromAddr;
ASSEMBLE Assemble;
PATCHGET PatchGet;
PATCHINRANGE PatchInRange;
MEMPATCH MemPatch;
PATCHRESTORERANGE PatchRestoreRange;
PATCHENUM PatchEnum;
PATCHRESTORE PatchRestore;
PATCHFILE PatchFile;
MODPATHFROMADDR ModPathFromAddr;
MODPATHFROMNAME ModPathFromName;
DISASMFAST DisasmFast;
MEMUPDATEMAP MemUpdateMap;
GETCALLSTACK GetCallStack;
SYMBOLDOWNLOADALLSYMBOLS SymbolDownloadAllSymbols;
GETJITAUTO GetJitAuto;
GETJIT GetJit;
GETDEFJIT GetDefJit;
GETPROCESSLIST GetProcessList;
GETPAGERIGHTS GetPageRights;
SETPAGERIGHTS SetPageRights;
PAGERIGHTSTOSTRING PageRightsToString;
ISPROCESSELEVATED IsProcessElevated;
GETCMDLINE GetCmdline;
SETCMDLINE SetCmdline;
FILEOFFSETTOVA FileOffsetToVa;
VATOFILEOFFSET VaToFileOffset;
GETADDRFROMLINE GetAddrFromLine;
GETSOURCEFROMADDR GetSourceFromAddr;
VALFROMSTRING ValFromString;
} DBGFUNCTIONS;
#ifdef BUILD_DBG
const DBGFUNCTIONS* dbgfunctionsget();
void dbgfunctionsinit();
#endif //BUILD_DBG
#endif //_DBGFUNCTIONS_H

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,33 @@
#ifndef _EXPORTS_H
#define _EXPORTS_H
#include "_global.h"
#ifdef __cplusplus
extern "C"
{
#endif
DLL_EXPORT duint _dbg_memfindbaseaddr(duint addr, duint* size);
DLL_EXPORT bool _dbg_memread(duint addr, unsigned char* dest, duint size, duint* read);
DLL_EXPORT bool _dbg_memwrite(duint addr, const unsigned char* src, duint size, duint* written);
DLL_EXPORT bool _dbg_memmap(MEMMAP* memmap);
DLL_EXPORT bool _dbg_memisvalidreadptr(duint addr);
DLL_EXPORT bool _dbg_valfromstring(const char* string, duint* value);
DLL_EXPORT bool _dbg_isdebugging();
DLL_EXPORT bool _dbg_isjumpgoingtoexecute(duint addr);
DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDRINFO* addrinfo);
DLL_EXPORT bool _dbg_addrinfoset(duint addr, ADDRINFO* addrinfo);
DLL_EXPORT int _dbg_bpgettypeat(duint addr);
DLL_EXPORT bool _dbg_getregdump(REGDUMP* regdump);
DLL_EXPORT bool _dbg_valtostring(const char* string, duint value);
DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* list);
DLL_EXPORT duint _dbg_getbranchdestination(duint addr);
DLL_EXPORT bool _dbg_functionoverlaps(duint start, duint end);
DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* param2);
#ifdef __cplusplus
}
#endif
#endif // _EXPORTS_H
#ifndef _EXPORTS_H
#define _EXPORTS_H
#include "_global.h"
#ifdef __cplusplus
extern "C"
{
#endif
DLL_EXPORT duint _dbg_memfindbaseaddr(duint addr, duint* size);
DLL_EXPORT bool _dbg_memread(duint addr, unsigned char* dest, duint size, duint* read);
DLL_EXPORT bool _dbg_memwrite(duint addr, const unsigned char* src, duint size, duint* written);
DLL_EXPORT bool _dbg_memmap(MEMMAP* memmap);
DLL_EXPORT bool _dbg_memisvalidreadptr(duint addr);
DLL_EXPORT bool _dbg_valfromstring(const char* string, duint* value);
DLL_EXPORT bool _dbg_isdebugging();
DLL_EXPORT bool _dbg_isjumpgoingtoexecute(duint addr);
DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDRINFO* addrinfo);
DLL_EXPORT bool _dbg_addrinfoset(duint addr, ADDRINFO* addrinfo);
DLL_EXPORT int _dbg_bpgettypeat(duint addr);
DLL_EXPORT bool _dbg_getregdump(REGDUMP* regdump);
DLL_EXPORT bool _dbg_valtostring(const char* string, duint value);
DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* list);
DLL_EXPORT duint _dbg_getbranchdestination(duint addr);
DLL_EXPORT bool _dbg_functionoverlaps(duint start, duint end);
DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* param2);
#ifdef __cplusplus
}
#endif
#endif // _EXPORTS_H

View File

@ -1,348 +1,348 @@
/**
\file _global.cpp
\brief Implements the global class.
*/
#include "_global.h"
#include <objbase.h>
#include <shlobj.h>
/**
\brief x64dbg library instance.
*/
HINSTANCE hInst;
/**
\brief Number of allocated buffers by emalloc(). This should be 0 when x64dbg ends.
*/
static int emalloc_count = 0;
/**
\brief Path for debugging, used to create an allocation trace file on emalloc() or efree(). Not used.
*/
static char alloctrace[MAX_PATH] = "";
/**
\brief Allocates a new buffer.
\param size The size of the buffer to allocate (in bytes).
\param reason The reason for allocation (can be used for memory allocation tracking).
\return Always returns a valid pointer to the buffer you requested. Will quit the application on errors.
*/
void* emalloc(size_t size, const char* reason)
{
ASSERT_NONZERO(size);
unsigned char* a = (unsigned char*)GlobalAlloc(GMEM_FIXED, size);
if(!a)
{
MessageBoxA(0, "Could not allocate memory", "Error", MB_ICONERROR);
ExitProcess(1);
}
memset(a, 0, size);
emalloc_count++;
/*
FILE* file = fopen(alloctrace, "a+");
fprintf(file, "DBG%.5d: alloc:" fhex ":%s:" fhex "\n", emalloc_count, a, reason, size);
fclose(file);
*/
return a;
}
/**
\brief Reallocates a buffer allocated with emalloc().
\param [in] Pointer to memory previously allocated with emalloc(). When NULL a new buffer will be allocated by emalloc().
\param size The new memory size.
\param reason The reason for allocation (can be used for memory allocation tracking).
\return Always returns a valid pointer to the buffer you requested. Will quit the application on errors.
*/
void* erealloc(void* ptr, size_t size, const char* reason)
{
ASSERT_NONZERO(size);
// Free the memory if the pointer was set (as per documentation).
if (ptr)
efree(ptr);
return emalloc(size, reason);
}
/**
\brief Free memory previously allocated with emalloc().
\param [in] Pointer to the memory to free.
\param reason The reason for freeing, should be the same as the reason for allocating.
*/
void efree(void* ptr, const char* reason)
{
emalloc_count--;
/*
FILE* file = fopen(alloctrace, "a+");
fprintf(file, "DBG%.5d: free:" fhex ":%s\n", emalloc_count, ptr, reason);
fclose(file);
*/
GlobalFree(ptr);
}
void* json_malloc(size_t size)
{
return emalloc(size, "json:ptr");
}
void json_free(void* ptr)
{
efree(ptr, "json:ptr");
}
/**
\brief Gets the number of memory leaks. This number is only valid in _dbg_dbgexitsignal().
\return The number of memory leaks.
*/
int memleaks()
{
return emalloc_count;
}
/**
\brief Sets the path for the allocation trace file.
\param file UTF-8 filepath.
*/
void setalloctrace(const char* file)
{
strcpy_s(alloctrace, file);
}
/**
\brief A function to determine if a string is contained in a specifically formatted 'array string'.
\param cmd_list Array of strings separated by '\1'.
\param cmd The string to look for.
\return true if \p cmd is contained in \p cmd_list.
*/
bool arraycontains(const char* cmd_list, const char* cmd)
{
//TODO: fix this function a little
if(!cmd_list || !cmd)
return false;
char temp[deflen] = "";
strcpy_s(temp, cmd_list);
int len = (int)strlen(cmd_list);
if(len >= deflen)
return false;
for(int i = 0; i < len; i++)
if(temp[i] == 1)
temp[i] = 0;
if(!_stricmp(temp, cmd))
return true;
for(int i = (int)strlen(temp); i < len; i++)
{
if(!temp[i])
{
if(!_stricmp(temp + i + 1, cmd))
return true;
i += (int)strlen(temp + i + 1);
}
}
return false;
}
/**
\brief Compares two strings without case-sensitivity.
\param a The first string.
\param b The second string.
\return true if the strings are equal (case-insensitive).
*/
bool scmp(const char* a, const char* b)
{
if(_stricmp(a, b))
return false;
return true;
}
/**
\brief Formats a string to hexadecimal format (removes all non-hex characters).
\param [in,out] String to format.
*/
void formathex(char* string)
{
int len = (int)strlen(string);
_strupr(string);
Memory<char*> new_string(len + 1, "formathex:new_string");
for(int i = 0, j = 0; i < len; i++)
if(isxdigit(string[i]))
j += sprintf(new_string() + j, "%c", string[i]);
strcpy_s(string, len + 1, new_string());
}
/**
\brief Formats a string to decimal format (removed all non-numeric characters).
\param [in,out] String to format.
*/
void formatdec(char* string)
{
int len = (int)strlen(string);
_strupr(string);
Memory<char*> new_string(len + 1, "formatdec:new_string");
for(int i = 0, j = 0; i < len; i++)
if(isdigit(string[i]))
j += sprintf(new_string() + j, "%c", string[i]);
strcpy_s(string, len + 1, new_string());
}
/**
\brief Queries if a given file exists.
\param file Path to the file to check (UTF-8).
\return true if the file exists on the hard drive.
*/
bool FileExists(const char* file)
{
DWORD attrib = GetFileAttributesW(StringUtils::Utf8ToUtf16(file).c_str());
return (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
}
/**
\brief Queries if a given directory exists.
\param dir Path to the directory to check (UTF-8).
\return true if the directory exists.
*/
bool DirExists(const char* dir)
{
DWORD attrib = GetFileAttributesW(StringUtils::Utf8ToUtf16(dir).c_str());
return (attrib == FILE_ATTRIBUTE_DIRECTORY);
}
/**
\brief Gets file path from a file handle.
\param hFile File handle to get the path from.
\param [in,out] szFileName Buffer of size MAX_PATH.
\return true if it succeeds, false if it fails.
*/
bool GetFileNameFromHandle(HANDLE hFile, char* szFileName)
{
wchar_t wszFileName[MAX_PATH] = L"";
if(!PathFromFileHandleW(hFile, wszFileName, sizeof(wszFileName)))
return false;
strcpy_s(szFileName, MAX_PATH, StringUtils::Utf16ToUtf8(wszFileName).c_str());
return true;
}
/**
\brief Get a boolean setting from the configuration file.
\param section The section of the setting (UTF-8).
\param name The name of the setting (UTF-8).
\return true if the setting was set and equals to true, otherwise returns false.
*/
bool settingboolget(const char* section, const char* name)
{
duint setting;
if(!BridgeSettingGetUint(section, name, &setting))
return false;
if(setting)
return true;
return false;
}
/**
\brief Gets file architecture.
\param szFileName UTF-8 encoded file path.
\return The file architecture (::arch).
*/
arch GetFileArchitecture(const char* szFileName)
{
arch retval = notfound;
Handle hFile = CreateFileW(StringUtils::Utf8ToUtf16(szFileName).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if(hFile != INVALID_HANDLE_VALUE)
{
unsigned char data[0x1000];
DWORD read = 0;
DWORD fileSize = GetFileSize(hFile, 0);
DWORD readSize = sizeof(data);
if(readSize > fileSize)
readSize = fileSize;
if(ReadFile(hFile, data, readSize, &read, 0))
{
retval = invalid;
IMAGE_DOS_HEADER* pdh = (IMAGE_DOS_HEADER*)data;
if(pdh->e_magic == IMAGE_DOS_SIGNATURE && (size_t)pdh->e_lfanew < readSize)
{
IMAGE_NT_HEADERS* pnth = (IMAGE_NT_HEADERS*)(data + pdh->e_lfanew);
if(pnth->Signature == IMAGE_NT_SIGNATURE)
{
if(pnth->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) //x32
retval = x32;
else if(pnth->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) //x64
retval = x64;
}
}
}
}
return retval;
}
/**
\brief Query if x64dbg is running in Wow64 mode.
\return true if running in Wow64, false otherwise.
*/
bool IsWow64()
{
BOOL bIsWow64Process = FALSE;
//x64dbg supports WinXP SP3 and later only, so ignore the GetProcAddress crap :D
IsWow64Process(GetCurrentProcess(), &bIsWow64Process);
return !!bIsWow64Process;
}
//Taken from: http://www.cplusplus.com/forum/windows/64088/
bool ResolveShortcut(HWND hwnd, const wchar_t* szShortcutPath, char* szResolvedPath, size_t nSize)
{
if(szResolvedPath == NULL)
return SUCCEEDED(E_INVALIDARG);
//Initialize COM stuff
CoInitialize(NULL);
//Get a pointer to the IShellLink interface.
IShellLink* psl = NULL;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if(SUCCEEDED(hres))
{
//Get a pointer to the IPersistFile interface.
IPersistFile* ppf = NULL;
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if(SUCCEEDED(hres))
{
//Load the shortcut.
hres = ppf->Load(szShortcutPath, STGM_READ);
if(SUCCEEDED(hres))
{
//Resolve the link.
hres = psl->Resolve(hwnd, 0);
if(SUCCEEDED(hres))
{
//Get the path to the link target.
char szGotPath[MAX_PATH] = {0};
hres = psl->GetPath(szGotPath, _countof(szGotPath), NULL, SLGP_SHORTPATH);
if(SUCCEEDED(hres))
{
strcpy_s(szResolvedPath, nSize, szGotPath);
}
}
}
//Release the pointer to the IPersistFile interface.
ppf->Release();
}
//Release the pointer to the IShellLink interface.
psl->Release();
}
//Uninitialize COM stuff
CoUninitialize();
return SUCCEEDED(hres);
}
void WaitForThreadTermination(HANDLE hThread)
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
/**
\file _global.cpp
\brief Implements the global class.
*/
#include "_global.h"
#include <objbase.h>
#include <shlobj.h>
/**
\brief x64dbg library instance.
*/
HINSTANCE hInst;
/**
\brief Number of allocated buffers by emalloc(). This should be 0 when x64dbg ends.
*/
static int emalloc_count = 0;
/**
\brief Path for debugging, used to create an allocation trace file on emalloc() or efree(). Not used.
*/
static char alloctrace[MAX_PATH] = "";
/**
\brief Allocates a new buffer.
\param size The size of the buffer to allocate (in bytes).
\param reason The reason for allocation (can be used for memory allocation tracking).
\return Always returns a valid pointer to the buffer you requested. Will quit the application on errors.
*/
void* emalloc(size_t size, const char* reason)
{
ASSERT_NONZERO(size);
unsigned char* a = (unsigned char*)GlobalAlloc(GMEM_FIXED, size);
if(!a)
{
MessageBoxA(0, "Could not allocate memory", "Error", MB_ICONERROR);
ExitProcess(1);
}
memset(a, 0, size);
emalloc_count++;
/*
FILE* file = fopen(alloctrace, "a+");
fprintf(file, "DBG%.5d: alloc:" fhex ":%s:" fhex "\n", emalloc_count, a, reason, size);
fclose(file);
*/
return a;
}
/**
\brief Reallocates a buffer allocated with emalloc().
\param [in] Pointer to memory previously allocated with emalloc(). When NULL a new buffer will be allocated by emalloc().
\param size The new memory size.
\param reason The reason for allocation (can be used for memory allocation tracking).
\return Always returns a valid pointer to the buffer you requested. Will quit the application on errors.
*/
void* erealloc(void* ptr, size_t size, const char* reason)
{
ASSERT_NONZERO(size);
// Free the memory if the pointer was set (as per documentation).
if (ptr)
efree(ptr);
return emalloc(size, reason);
}
/**
\brief Free memory previously allocated with emalloc().
\param [in] Pointer to the memory to free.
\param reason The reason for freeing, should be the same as the reason for allocating.
*/
void efree(void* ptr, const char* reason)
{
emalloc_count--;
/*
FILE* file = fopen(alloctrace, "a+");
fprintf(file, "DBG%.5d: free:" fhex ":%s\n", emalloc_count, ptr, reason);
fclose(file);
*/
GlobalFree(ptr);
}
void* json_malloc(size_t size)
{
return emalloc(size, "json:ptr");
}
void json_free(void* ptr)
{
efree(ptr, "json:ptr");
}
/**
\brief Gets the number of memory leaks. This number is only valid in _dbg_dbgexitsignal().
\return The number of memory leaks.
*/
int memleaks()
{
return emalloc_count;
}
/**
\brief Sets the path for the allocation trace file.
\param file UTF-8 filepath.
*/
void setalloctrace(const char* file)
{
strcpy_s(alloctrace, file);
}
/**
\brief A function to determine if a string is contained in a specifically formatted 'array string'.
\param cmd_list Array of strings separated by '\1'.
\param cmd The string to look for.
\return true if \p cmd is contained in \p cmd_list.
*/
bool arraycontains(const char* cmd_list, const char* cmd)
{
//TODO: fix this function a little
if(!cmd_list || !cmd)
return false;
char temp[deflen] = "";
strcpy_s(temp, cmd_list);
int len = (int)strlen(cmd_list);
if(len >= deflen)
return false;
for(int i = 0; i < len; i++)
if(temp[i] == 1)
temp[i] = 0;
if(!_stricmp(temp, cmd))
return true;
for(int i = (int)strlen(temp); i < len; i++)
{
if(!temp[i])
{
if(!_stricmp(temp + i + 1, cmd))
return true;
i += (int)strlen(temp + i + 1);
}
}
return false;
}
/**
\brief Compares two strings without case-sensitivity.
\param a The first string.
\param b The second string.
\return true if the strings are equal (case-insensitive).
*/
bool scmp(const char* a, const char* b)
{
if(_stricmp(a, b))
return false;
return true;
}
/**
\brief Formats a string to hexadecimal format (removes all non-hex characters).
\param [in,out] String to format.
*/
void formathex(char* string)
{
int len = (int)strlen(string);
_strupr(string);
Memory<char*> new_string(len + 1, "formathex:new_string");
for(int i = 0, j = 0; i < len; i++)
if(isxdigit(string[i]))
j += sprintf(new_string() + j, "%c", string[i]);
strcpy_s(string, len + 1, new_string());
}
/**
\brief Formats a string to decimal format (removed all non-numeric characters).
\param [in,out] String to format.
*/
void formatdec(char* string)
{
int len = (int)strlen(string);
_strupr(string);
Memory<char*> new_string(len + 1, "formatdec:new_string");
for(int i = 0, j = 0; i < len; i++)
if(isdigit(string[i]))
j += sprintf(new_string() + j, "%c", string[i]);
strcpy_s(string, len + 1, new_string());
}
/**
\brief Queries if a given file exists.
\param file Path to the file to check (UTF-8).
\return true if the file exists on the hard drive.
*/
bool FileExists(const char* file)
{
DWORD attrib = GetFileAttributesW(StringUtils::Utf8ToUtf16(file).c_str());
return (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
}
/**
\brief Queries if a given directory exists.
\param dir Path to the directory to check (UTF-8).
\return true if the directory exists.
*/
bool DirExists(const char* dir)
{
DWORD attrib = GetFileAttributesW(StringUtils::Utf8ToUtf16(dir).c_str());
return (attrib == FILE_ATTRIBUTE_DIRECTORY);
}
/**
\brief Gets file path from a file handle.
\param hFile File handle to get the path from.
\param [in,out] szFileName Buffer of size MAX_PATH.
\return true if it succeeds, false if it fails.
*/
bool GetFileNameFromHandle(HANDLE hFile, char* szFileName)
{
wchar_t wszFileName[MAX_PATH] = L"";
if(!PathFromFileHandleW(hFile, wszFileName, sizeof(wszFileName)))
return false;
strcpy_s(szFileName, MAX_PATH, StringUtils::Utf16ToUtf8(wszFileName).c_str());
return true;
}
/**
\brief Get a boolean setting from the configuration file.
\param section The section of the setting (UTF-8).
\param name The name of the setting (UTF-8).
\return true if the setting was set and equals to true, otherwise returns false.
*/
bool settingboolget(const char* section, const char* name)
{
duint setting;
if(!BridgeSettingGetUint(section, name, &setting))
return false;
if(setting)
return true;
return false;
}
/**
\brief Gets file architecture.
\param szFileName UTF-8 encoded file path.
\return The file architecture (::arch).
*/
arch GetFileArchitecture(const char* szFileName)
{
arch retval = notfound;
Handle hFile = CreateFileW(StringUtils::Utf8ToUtf16(szFileName).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if(hFile != INVALID_HANDLE_VALUE)
{
unsigned char data[0x1000];
DWORD read = 0;
DWORD fileSize = GetFileSize(hFile, 0);
DWORD readSize = sizeof(data);
if(readSize > fileSize)
readSize = fileSize;
if(ReadFile(hFile, data, readSize, &read, 0))
{
retval = invalid;
IMAGE_DOS_HEADER* pdh = (IMAGE_DOS_HEADER*)data;
if(pdh->e_magic == IMAGE_DOS_SIGNATURE && (size_t)pdh->e_lfanew < readSize)
{
IMAGE_NT_HEADERS* pnth = (IMAGE_NT_HEADERS*)(data + pdh->e_lfanew);
if(pnth->Signature == IMAGE_NT_SIGNATURE)
{
if(pnth->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) //x32
retval = x32;
else if(pnth->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) //x64
retval = x64;
}
}
}
}
return retval;
}
/**
\brief Query if x64dbg is running in Wow64 mode.
\return true if running in Wow64, false otherwise.
*/
bool IsWow64()
{
BOOL bIsWow64Process = FALSE;
//x64dbg supports WinXP SP3 and later only, so ignore the GetProcAddress crap :D
IsWow64Process(GetCurrentProcess(), &bIsWow64Process);
return !!bIsWow64Process;
}
//Taken from: http://www.cplusplus.com/forum/windows/64088/
bool ResolveShortcut(HWND hwnd, const wchar_t* szShortcutPath, char* szResolvedPath, size_t nSize)
{
if(szResolvedPath == NULL)
return SUCCEEDED(E_INVALIDARG);
//Initialize COM stuff
CoInitialize(NULL);
//Get a pointer to the IShellLink interface.
IShellLink* psl = NULL;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if(SUCCEEDED(hres))
{
//Get a pointer to the IPersistFile interface.
IPersistFile* ppf = NULL;
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if(SUCCEEDED(hres))
{
//Load the shortcut.
hres = ppf->Load(szShortcutPath, STGM_READ);
if(SUCCEEDED(hres))
{
//Resolve the link.
hres = psl->Resolve(hwnd, 0);
if(SUCCEEDED(hres))
{
//Get the path to the link target.
char szGotPath[MAX_PATH] = {0};
hres = psl->GetPath(szGotPath, _countof(szGotPath), NULL, SLGP_SHORTPATH);
if(SUCCEEDED(hres))
{
strcpy_s(szResolvedPath, nSize, szGotPath);
}
}
}
//Release the pointer to the IPersistFile interface.
ppf->Release();
}
//Release the pointer to the IShellLink interface.
psl->Release();
}
//Uninitialize COM stuff
CoUninitialize();
return SUCCEEDED(hres);
}
void WaitForThreadTermination(HANDLE hThread)
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}

View File

@ -1,84 +1,84 @@
#ifndef _GLOBAL_H
#define _GLOBAL_H
#define _WIN32_WINNT 0x0501
#define WINVER 0x0501
#define _WIN32_IE 0x0500
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <windows.h>
#include <psapi.h>
#include <shlwapi.h>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <unordered_map>
#include <tlhelp32.h>
#include "..\dbg_types.h"
#include "..\dbg_assert.h"
#include "..\bridge\bridgemain.h"
#include "jansson\jansson.h"
#include "jansson\jansson_x64dbg.h"
#include "yara\yara.h"
#include "DeviceNameResolver\DeviceNameResolver.h"
#include "handle.h"
#include "stringutils.h"
#include "dbghelp_safe.h"
#ifndef DLL_EXPORT
#define DLL_EXPORT __declspec(dllexport)
#endif //DLL_IMPORT
#ifndef DLL_IMPORT
#define DLL_IMPORT __declspec(dllimport)
#endif //DLL_IMPORT
//defines
#define deflen 1024
#ifdef _WIN64 //defined by default
#define fhex "%.16llX"
#define fext "ll"
#else
#define fhex "%.8X"
#define fext ""
#endif // _WIN64
enum arch
{
notfound,
invalid,
x32,
x64
};
//superglobal variables
extern HINSTANCE hInst;
//functions
void* emalloc(size_t size, const char* reason = "emalloc:???");
void* erealloc(void* ptr, size_t size, const char* reason = "erealloc:???");
void efree(void* ptr, const char* reason = "efree:???");
void* json_malloc(size_t size);
void json_free(void* ptr);
int memleaks();
void setalloctrace(const char* file);
bool arraycontains(const char* cmd_list, const char* cmd);
bool scmp(const char* a, const char* b);
void formathex(char* string);
void formatdec(char* string);
bool FileExists(const char* file);
bool DirExists(const char* dir);
bool GetFileNameFromHandle(HANDLE hFile, char* szFileName);
bool settingboolget(const char* section, const char* name);
arch GetFileArchitecture(const char* szFileName);
bool IsWow64();
bool ResolveShortcut(HWND hwnd, const wchar_t* szShortcutPath, char* szResolvedPath, size_t nSize);
void WaitForThreadTermination(HANDLE hThread);
#include "dynamicmem.h"
#endif // _GLOBAL_H
#ifndef _GLOBAL_H
#define _GLOBAL_H
#define _WIN32_WINNT 0x0501
#define WINVER 0x0501
#define _WIN32_IE 0x0500
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <windows.h>
#include <psapi.h>
#include <shlwapi.h>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <unordered_map>
#include <tlhelp32.h>
#include "..\dbg_types.h"
#include "..\dbg_assert.h"
#include "..\bridge\bridgemain.h"
#include "jansson\jansson.h"
#include "jansson\jansson_x64dbg.h"
#include "yara\yara.h"
#include "DeviceNameResolver\DeviceNameResolver.h"
#include "handle.h"
#include "stringutils.h"
#include "dbghelp_safe.h"
#ifndef DLL_EXPORT
#define DLL_EXPORT __declspec(dllexport)
#endif //DLL_IMPORT
#ifndef DLL_IMPORT
#define DLL_IMPORT __declspec(dllimport)
#endif //DLL_IMPORT
//defines
#define deflen 1024
#ifdef _WIN64 //defined by default
#define fhex "%.16llX"
#define fext "ll"
#else
#define fhex "%.8X"
#define fext ""
#endif // _WIN64
enum arch
{
notfound,
invalid,
x32,
x64
};
//superglobal variables
extern HINSTANCE hInst;
//functions
void* emalloc(size_t size, const char* reason = "emalloc:???");
void* erealloc(void* ptr, size_t size, const char* reason = "erealloc:???");
void efree(void* ptr, const char* reason = "efree:???");
void* json_malloc(size_t size);
void json_free(void* ptr);
int memleaks();
void setalloctrace(const char* file);
bool arraycontains(const char* cmd_list, const char* cmd);
bool scmp(const char* a, const char* b);
void formathex(char* string);
void formatdec(char* string);
bool FileExists(const char* file);
bool DirExists(const char* dir);
bool GetFileNameFromHandle(HANDLE hFile, char* szFileName);
bool settingboolget(const char* section, const char* name);
arch GetFileArchitecture(const char* szFileName);
bool IsWow64();
bool ResolveShortcut(HWND hwnd, const wchar_t* szShortcutPath, char* szResolvedPath, size_t nSize);
void WaitForThreadTermination(HANDLE hThread);
#include "dynamicmem.h"
#endif // _GLOBAL_H

View File

@ -1,25 +1,25 @@
#ifndef _PLUGIN_DATA_H
#define _PLUGIN_DATA_H
#ifdef BUILD_DBG
#include "_global.h"
#else
#ifdef __GNUC__
#include "dbghelp\dbghelp.h"
#else
#include <dbghelp.h>
#endif // __GNUC__
#ifndef deflen
#define deflen 1024
#endif // deflen
#include "bridgemain.h"
#include "_dbgfunctions.h"
#endif // BUILD_DBG
#endif // _PLUGIN_DATA_H
#ifndef _PLUGIN_DATA_H
#define _PLUGIN_DATA_H
#ifdef BUILD_DBG
#include "_global.h"
#else
#ifdef __GNUC__
#include "dbghelp\dbghelp.h"
#else
#include <dbghelp.h>
#endif // __GNUC__
#ifndef deflen
#define deflen 1024
#endif // deflen
#include "bridgemain.h"
#include "_dbgfunctions.h"
#endif // BUILD_DBG
#endif // _PLUGIN_DATA_H

View File

@ -1,103 +1,103 @@
/**
@file _plugins.cpp
@brief Implements the plugins class.
*/
#include "_plugins.h"
#include "plugin_loader.h"
#include "console.h"
#include "debugger.h"
#include "threading.h"
///debugger plugin exports (wrappers)
PLUG_IMPEXP void _plugin_registercallback(int pluginHandle, CBTYPE cbType, CBPLUGIN cbPlugin)
{
pluginregistercallback(pluginHandle, cbType, cbPlugin);
}
PLUG_IMPEXP bool _plugin_unregistercallback(int pluginHandle, CBTYPE cbType)
{
return pluginunregistercallback(pluginHandle, cbType);
}
PLUG_IMPEXP bool _plugin_registercommand(int pluginHandle, const char* command, CBPLUGINCOMMAND cbCommand, bool debugonly)
{
return plugincmdregister(pluginHandle, command, cbCommand, debugonly);
}
PLUG_IMPEXP bool _plugin_unregistercommand(int pluginHandle, const char* command)
{
return plugincmdunregister(pluginHandle, command);
}
PLUG_IMPEXP void _plugin_logprintf(const char* format, ...)
{
va_list args;
va_start(args, format);
dprintf_args(format, args);
va_end(args);
}
PLUG_IMPEXP void _plugin_logputs(const char* text)
{
dputs(text);
}
PLUG_IMPEXP void _plugin_debugpause()
{
GuiSetDebugState(paused);
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
lock(WAITID_RUN);
SetForegroundWindow(GuiGetWindowHandle());
dbgsetskipexceptions(false);
wait(WAITID_RUN);
}
PLUG_IMPEXP void _plugin_debugskipexceptions(bool skip)
{
dbgsetskipexceptions(skip);
}
PLUG_IMPEXP int _plugin_menuadd(int hMenu, const char* title)
{
return pluginmenuadd(hMenu, title);
}
PLUG_IMPEXP bool _plugin_menuaddentry(int hMenu, int hEntry, const char* title)
{
return pluginmenuaddentry(hMenu, hEntry, title);
}
PLUG_IMPEXP bool _plugin_menuaddseparator(int hMenu)
{
return pluginmenuaddseparator(hMenu);
}
PLUG_IMPEXP bool _plugin_menuclear(int hMenu)
{
return pluginmenuclear(hMenu);
}
PLUG_IMPEXP void _plugin_menuseticon(int hMenu, const ICONDATA* icon)
{
pluginmenuseticon(hMenu, icon);
}
PLUG_IMPEXP void _plugin_menuentryseticon(int pluginHandle, int hEntry, const ICONDATA* icon)
{
pluginmenuentryseticon(pluginHandle, hEntry, icon);
}
PLUG_IMPEXP void _plugin_startscript(CBPLUGINSCRIPT cbScript)
{
dbgstartscriptthread(cbScript);
}
PLUG_IMPEXP bool _plugin_waituntilpaused()
{
while(DbgIsDebugging() && dbgisrunning()) //wait until the debugger paused
Sleep(1);
return DbgIsDebugging();
/**
@file _plugins.cpp
@brief Implements the plugins class.
*/
#include "_plugins.h"
#include "plugin_loader.h"
#include "console.h"
#include "debugger.h"
#include "threading.h"
///debugger plugin exports (wrappers)
PLUG_IMPEXP void _plugin_registercallback(int pluginHandle, CBTYPE cbType, CBPLUGIN cbPlugin)
{
pluginregistercallback(pluginHandle, cbType, cbPlugin);
}
PLUG_IMPEXP bool _plugin_unregistercallback(int pluginHandle, CBTYPE cbType)
{
return pluginunregistercallback(pluginHandle, cbType);
}
PLUG_IMPEXP bool _plugin_registercommand(int pluginHandle, const char* command, CBPLUGINCOMMAND cbCommand, bool debugonly)
{
return plugincmdregister(pluginHandle, command, cbCommand, debugonly);
}
PLUG_IMPEXP bool _plugin_unregistercommand(int pluginHandle, const char* command)
{
return plugincmdunregister(pluginHandle, command);
}
PLUG_IMPEXP void _plugin_logprintf(const char* format, ...)
{
va_list args;
va_start(args, format);
dprintf_args(format, args);
va_end(args);
}
PLUG_IMPEXP void _plugin_logputs(const char* text)
{
dputs(text);
}
PLUG_IMPEXP void _plugin_debugpause()
{
GuiSetDebugState(paused);
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
lock(WAITID_RUN);
SetForegroundWindow(GuiGetWindowHandle());
dbgsetskipexceptions(false);
wait(WAITID_RUN);
}
PLUG_IMPEXP void _plugin_debugskipexceptions(bool skip)
{
dbgsetskipexceptions(skip);
}
PLUG_IMPEXP int _plugin_menuadd(int hMenu, const char* title)
{
return pluginmenuadd(hMenu, title);
}
PLUG_IMPEXP bool _plugin_menuaddentry(int hMenu, int hEntry, const char* title)
{
return pluginmenuaddentry(hMenu, hEntry, title);
}
PLUG_IMPEXP bool _plugin_menuaddseparator(int hMenu)
{
return pluginmenuaddseparator(hMenu);
}
PLUG_IMPEXP bool _plugin_menuclear(int hMenu)
{
return pluginmenuclear(hMenu);
}
PLUG_IMPEXP void _plugin_menuseticon(int hMenu, const ICONDATA* icon)
{
pluginmenuseticon(hMenu, icon);
}
PLUG_IMPEXP void _plugin_menuentryseticon(int pluginHandle, int hEntry, const ICONDATA* icon)
{
pluginmenuentryseticon(pluginHandle, hEntry, icon);
}
PLUG_IMPEXP void _plugin_startscript(CBPLUGINSCRIPT cbScript)
{
dbgstartscriptthread(cbScript);
}
PLUG_IMPEXP bool _plugin_waituntilpaused()
{
while(DbgIsDebugging() && dbgisrunning()) //wait until the debugger paused
Sleep(1);
return DbgIsDebugging();
}

View File

@ -1,230 +1,230 @@
#ifndef _PLUGINS_H
#define _PLUGINS_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifndef PLUG_IMPEXP
#ifdef BUILD_DBG
#define PLUG_IMPEXP __declspec(dllexport)
#else
#define PLUG_IMPEXP __declspec(dllimport)
#endif //BUILD_DBG
#endif //PLUG_IMPEXP
#include "_plugin_types.h"
//default structure alignments forced
#ifdef _WIN64
#pragma pack(push, 16)
#else //x86
#pragma pack(push, 8)
#endif //_WIN64
//defines
#define PLUG_SDKVERSION 1
//structures
typedef struct
{
//provided by the debugger
int pluginHandle;
//provided by the pluginit function
int sdkVersion;
int pluginVersion;
char pluginName[256];
} PLUG_INITSTRUCT;
typedef struct
{
//provided by the debugger
HWND hwndDlg; //gui window handle
int hMenu; //plugin menu handle
int hMenuDisasm; //plugin disasm menu handle
int hMenuDump; //plugin dump menu handle
int hMenuStack; //plugin stack menu handle
} PLUG_SETUPSTRUCT;
typedef struct
{
void* data; //user data
} PLUG_SCRIPTSTRUCT;
//callback structures
typedef struct
{
const char* szFileName;
} PLUG_CB_INITDEBUG;
typedef struct
{
void* reserved;
} PLUG_CB_STOPDEBUG;
typedef struct
{
CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo;
IMAGEHLP_MODULE64* modInfo;
const char* DebugFileName;
PROCESS_INFORMATION* fdProcessInfo;
} PLUG_CB_CREATEPROCESS;
typedef struct
{
EXIT_PROCESS_DEBUG_INFO* ExitProcess;
} PLUG_CB_EXITPROCESS;
typedef struct
{
CREATE_THREAD_DEBUG_INFO* CreateThread;
DWORD dwThreadId;
} PLUG_CB_CREATETHREAD;
typedef struct
{
EXIT_THREAD_DEBUG_INFO* ExitThread;
DWORD dwThreadId;
} PLUG_CB_EXITTHREAD;
typedef struct
{
void* reserved;
} PLUG_CB_SYSTEMBREAKPOINT;
typedef struct
{
LOAD_DLL_DEBUG_INFO* LoadDll;
IMAGEHLP_MODULE64* modInfo;
const char* modname;
} PLUG_CB_LOADDLL;
typedef struct
{
UNLOAD_DLL_DEBUG_INFO* UnloadDll;
} PLUG_CB_UNLOADDLL;
typedef struct
{
OUTPUT_DEBUG_STRING_INFO* DebugString;
} PLUG_CB_OUTPUTDEBUGSTRING;
typedef struct
{
EXCEPTION_DEBUG_INFO* Exception;
} PLUG_CB_EXCEPTION;
typedef struct
{
BRIDGEBP* breakpoint;
} PLUG_CB_BREAKPOINT;
typedef struct
{
void* reserved;
} PLUG_CB_PAUSEDEBUG;
typedef struct
{
void* reserved;
} PLUG_CB_RESUMEDEBUG;
typedef struct
{
void* reserved;
} PLUG_CB_STEPPED;
typedef struct
{
DWORD dwProcessId;
} PLUG_CB_ATTACH;
typedef struct
{
PROCESS_INFORMATION* fdProcessInfo;
} PLUG_CB_DETACH;
typedef struct
{
DEBUG_EVENT* DebugEvent;
} PLUG_CB_DEBUGEVENT;
typedef struct
{
int hEntry;
} PLUG_CB_MENUENTRY;
typedef struct
{
MSG* message;
long* result;
bool retval;
} PLUG_CB_WINEVENT;
typedef struct
{
MSG* message;
bool retval;
} PLUG_CB_WINEVENTGLOBAL;
//enums
typedef enum
{
CB_INITDEBUG, //PLUG_CB_INITDEBUG
CB_STOPDEBUG, //PLUG_CB_STOPDEBUG
CB_CREATEPROCESS, //PLUG_CB_CREATEPROCESS
CB_EXITPROCESS, //PLUG_CB_EXITPROCESS
CB_CREATETHREAD, //PLUG_CB_CREATETHREAD
CB_EXITTHREAD, //PLUG_CB_EXITTHREAD
CB_SYSTEMBREAKPOINT, //PLUG_CB_SYSTEMBREAKPOINT
CB_LOADDLL, //PLUG_CB_LOADDLL
CB_UNLOADDLL, //PLUG_CB_UNLOADDLL
CB_OUTPUTDEBUGSTRING, //PLUG_CB_OUTPUTDEBUGSTRING
CB_EXCEPTION, //PLUG_CB_EXCEPTION
CB_BREAKPOINT, //PLUG_CB_BREAKPOINT
CB_PAUSEDEBUG, //PLUG_CB_PAUSEDEBUG
CB_RESUMEDEBUG, //PLUG_CB_RESUMEDEBUG
CB_STEPPED, //PLUG_CB_STEPPED
CB_ATTACH, //PLUG_CB_ATTACHED (before attaching, after CB_INITDEBUG)
CB_DETACH, //PLUG_CB_DETACH (before detaching, before CB_STOPDEBUG)
CB_DEBUGEVENT, //PLUG_CB_DEBUGEVENT (called on any debug event)
CB_MENUENTRY, //PLUG_CB_MENUENTRY
CB_WINEVENT, //PLUG_CB_WINEVENT
CB_WINEVENTGLOBAL //PLUG_CB_WINEVENTGLOBAL
} CBTYPE;
//typedefs
typedef void (*CBPLUGIN)(CBTYPE cbType, void* callbackInfo);
typedef bool (*CBPLUGINCOMMAND)(int, char**);
typedef void (*CBPLUGINSCRIPT)();
//exports
#ifdef __cplusplus
extern "C"
{
#endif
PLUG_IMPEXP void _plugin_registercallback(int pluginHandle, CBTYPE cbType, CBPLUGIN cbPlugin);
PLUG_IMPEXP bool _plugin_unregistercallback(int pluginHandle, CBTYPE cbType);
PLUG_IMPEXP bool _plugin_registercommand(int pluginHandle, const char* command, CBPLUGINCOMMAND cbCommand, bool debugonly);
PLUG_IMPEXP bool _plugin_unregistercommand(int pluginHandle, const char* command);
PLUG_IMPEXP void _plugin_logprintf(const char* format, ...);
PLUG_IMPEXP void _plugin_logputs(const char* text);
PLUG_IMPEXP void _plugin_debugpause();
PLUG_IMPEXP void _plugin_debugskipexceptions(bool skip);
PLUG_IMPEXP int _plugin_menuadd(int hMenu, const char* title);
PLUG_IMPEXP bool _plugin_menuaddentry(int hMenu, int hEntry, const char* title);
PLUG_IMPEXP bool _plugin_menuaddseparator(int hMenu);
PLUG_IMPEXP bool _plugin_menuclear(int hMenu);
PLUG_IMPEXP void _plugin_menuseticon(int hMenu, const ICONDATA* icon);
PLUG_IMPEXP void _plugin_menuentryseticon(int pluginHandle, int hEntry, const ICONDATA* icon);
PLUG_IMPEXP void _plugin_startscript(CBPLUGINSCRIPT cbScript);
PLUG_IMPEXP bool _plugin_waituntilpaused();
#ifdef __cplusplus
}
#endif
#pragma pack(pop)
#endif // _PLUGINS_H
#ifndef _PLUGINS_H
#define _PLUGINS_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifndef PLUG_IMPEXP
#ifdef BUILD_DBG
#define PLUG_IMPEXP __declspec(dllexport)
#else
#define PLUG_IMPEXP __declspec(dllimport)
#endif //BUILD_DBG
#endif //PLUG_IMPEXP
#include "_plugin_types.h"
//default structure alignments forced
#ifdef _WIN64
#pragma pack(push, 16)
#else //x86
#pragma pack(push, 8)
#endif //_WIN64
//defines
#define PLUG_SDKVERSION 1
//structures
typedef struct
{
//provided by the debugger
int pluginHandle;
//provided by the pluginit function
int sdkVersion;
int pluginVersion;
char pluginName[256];
} PLUG_INITSTRUCT;
typedef struct
{
//provided by the debugger
HWND hwndDlg; //gui window handle
int hMenu; //plugin menu handle
int hMenuDisasm; //plugin disasm menu handle
int hMenuDump; //plugin dump menu handle
int hMenuStack; //plugin stack menu handle
} PLUG_SETUPSTRUCT;
typedef struct
{
void* data; //user data
} PLUG_SCRIPTSTRUCT;
//callback structures
typedef struct
{
const char* szFileName;
} PLUG_CB_INITDEBUG;
typedef struct
{
void* reserved;
} PLUG_CB_STOPDEBUG;
typedef struct
{
CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo;
IMAGEHLP_MODULE64* modInfo;
const char* DebugFileName;
PROCESS_INFORMATION* fdProcessInfo;
} PLUG_CB_CREATEPROCESS;
typedef struct
{
EXIT_PROCESS_DEBUG_INFO* ExitProcess;
} PLUG_CB_EXITPROCESS;
typedef struct
{
CREATE_THREAD_DEBUG_INFO* CreateThread;
DWORD dwThreadId;
} PLUG_CB_CREATETHREAD;
typedef struct
{
EXIT_THREAD_DEBUG_INFO* ExitThread;
DWORD dwThreadId;
} PLUG_CB_EXITTHREAD;
typedef struct
{
void* reserved;
} PLUG_CB_SYSTEMBREAKPOINT;
typedef struct
{
LOAD_DLL_DEBUG_INFO* LoadDll;
IMAGEHLP_MODULE64* modInfo;
const char* modname;
} PLUG_CB_LOADDLL;
typedef struct
{
UNLOAD_DLL_DEBUG_INFO* UnloadDll;
} PLUG_CB_UNLOADDLL;
typedef struct
{
OUTPUT_DEBUG_STRING_INFO* DebugString;
} PLUG_CB_OUTPUTDEBUGSTRING;
typedef struct
{
EXCEPTION_DEBUG_INFO* Exception;
} PLUG_CB_EXCEPTION;
typedef struct
{
BRIDGEBP* breakpoint;
} PLUG_CB_BREAKPOINT;
typedef struct
{
void* reserved;
} PLUG_CB_PAUSEDEBUG;
typedef struct
{
void* reserved;
} PLUG_CB_RESUMEDEBUG;
typedef struct
{
void* reserved;
} PLUG_CB_STEPPED;
typedef struct
{
DWORD dwProcessId;
} PLUG_CB_ATTACH;
typedef struct
{
PROCESS_INFORMATION* fdProcessInfo;
} PLUG_CB_DETACH;
typedef struct
{
DEBUG_EVENT* DebugEvent;
} PLUG_CB_DEBUGEVENT;
typedef struct
{
int hEntry;
} PLUG_CB_MENUENTRY;
typedef struct
{
MSG* message;
long* result;
bool retval;
} PLUG_CB_WINEVENT;
typedef struct
{
MSG* message;
bool retval;
} PLUG_CB_WINEVENTGLOBAL;
//enums
typedef enum
{
CB_INITDEBUG, //PLUG_CB_INITDEBUG
CB_STOPDEBUG, //PLUG_CB_STOPDEBUG
CB_CREATEPROCESS, //PLUG_CB_CREATEPROCESS
CB_EXITPROCESS, //PLUG_CB_EXITPROCESS
CB_CREATETHREAD, //PLUG_CB_CREATETHREAD
CB_EXITTHREAD, //PLUG_CB_EXITTHREAD
CB_SYSTEMBREAKPOINT, //PLUG_CB_SYSTEMBREAKPOINT
CB_LOADDLL, //PLUG_CB_LOADDLL
CB_UNLOADDLL, //PLUG_CB_UNLOADDLL
CB_OUTPUTDEBUGSTRING, //PLUG_CB_OUTPUTDEBUGSTRING
CB_EXCEPTION, //PLUG_CB_EXCEPTION
CB_BREAKPOINT, //PLUG_CB_BREAKPOINT
CB_PAUSEDEBUG, //PLUG_CB_PAUSEDEBUG
CB_RESUMEDEBUG, //PLUG_CB_RESUMEDEBUG
CB_STEPPED, //PLUG_CB_STEPPED
CB_ATTACH, //PLUG_CB_ATTACHED (before attaching, after CB_INITDEBUG)
CB_DETACH, //PLUG_CB_DETACH (before detaching, before CB_STOPDEBUG)
CB_DEBUGEVENT, //PLUG_CB_DEBUGEVENT (called on any debug event)
CB_MENUENTRY, //PLUG_CB_MENUENTRY
CB_WINEVENT, //PLUG_CB_WINEVENT
CB_WINEVENTGLOBAL //PLUG_CB_WINEVENTGLOBAL
} CBTYPE;
//typedefs
typedef void (*CBPLUGIN)(CBTYPE cbType, void* callbackInfo);
typedef bool (*CBPLUGINCOMMAND)(int, char**);
typedef void (*CBPLUGINSCRIPT)();
//exports
#ifdef __cplusplus
extern "C"
{
#endif
PLUG_IMPEXP void _plugin_registercallback(int pluginHandle, CBTYPE cbType, CBPLUGIN cbPlugin);
PLUG_IMPEXP bool _plugin_unregistercallback(int pluginHandle, CBTYPE cbType);
PLUG_IMPEXP bool _plugin_registercommand(int pluginHandle, const char* command, CBPLUGINCOMMAND cbCommand, bool debugonly);
PLUG_IMPEXP bool _plugin_unregistercommand(int pluginHandle, const char* command);
PLUG_IMPEXP void _plugin_logprintf(const char* format, ...);
PLUG_IMPEXP void _plugin_logputs(const char* text);
PLUG_IMPEXP void _plugin_debugpause();
PLUG_IMPEXP void _plugin_debugskipexceptions(bool skip);
PLUG_IMPEXP int _plugin_menuadd(int hMenu, const char* title);
PLUG_IMPEXP bool _plugin_menuaddentry(int hMenu, int hEntry, const char* title);
PLUG_IMPEXP bool _plugin_menuaddseparator(int hMenu);
PLUG_IMPEXP bool _plugin_menuclear(int hMenu);
PLUG_IMPEXP void _plugin_menuseticon(int hMenu, const ICONDATA* icon);
PLUG_IMPEXP void _plugin_menuentryseticon(int pluginHandle, int hEntry, const ICONDATA* icon);
PLUG_IMPEXP void _plugin_startscript(CBPLUGINSCRIPT cbScript);
PLUG_IMPEXP bool _plugin_waituntilpaused();
#ifdef __cplusplus
}
#endif
#pragma pack(pop)
#endif // _PLUGINS_H

View File

@ -1,8 +1,8 @@
#ifndef _SCRIPT_API_H
#define _SCRIPT_API_H
#include "_plugins.h"
#define SCRIPT_EXPORT PLUG_IMPEXP
#ifndef _SCRIPT_API_H
#define _SCRIPT_API_H
#include "_plugins.h"
#define SCRIPT_EXPORT PLUG_IMPEXP
#endif //_SCRIPT_API_H

View File

@ -1,22 +1,22 @@
#include "_scriptapi_assembler.h"
#include "assemble.h"
SCRIPT_EXPORT bool Script::Assembler::Assemble(duint addr, unsigned char* dest, int* size, const char* instruction)
{
return assemble(addr, dest, size, instruction, nullptr);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleEx(duint addr, unsigned char* dest, int* size, const char* instruction, char* error)
{
return assemble(addr, dest, size, instruction, error);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleMem(duint addr, const char* instruction)
{
return assembleat(addr, instruction, nullptr, nullptr, false);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleMemEx(duint addr, const char* instruction, int* size, char* error, bool fillnop)
{
return assembleat(addr, instruction, size, error, fillnop);
#include "_scriptapi_assembler.h"
#include "assemble.h"
SCRIPT_EXPORT bool Script::Assembler::Assemble(duint addr, unsigned char* dest, int* size, const char* instruction)
{
return assemble(addr, dest, size, instruction, nullptr);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleEx(duint addr, unsigned char* dest, int* size, const char* instruction, char* error)
{
return assemble(addr, dest, size, instruction, error);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleMem(duint addr, const char* instruction)
{
return assembleat(addr, instruction, nullptr, nullptr, false);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleMemEx(duint addr, const char* instruction, int* size, char* error, bool fillnop)
{
return assembleat(addr, instruction, size, error, fillnop);
}

View File

@ -1,17 +1,17 @@
#ifndef _SCRIPTAPI_ASSEMBLER_H
#define _SCRIPTAPI_ASSEMBLER_H
#include "_scriptapi.h"
namespace Script
{
namespace Assembler
{
SCRIPT_EXPORT bool Assemble(duint addr, unsigned char* dest, int* size, const char* instruction); //dest[16]
SCRIPT_EXPORT bool AssembleEx(duint addr, unsigned char* dest, int* size, const char* instruction, char* error); //dest[16], error[MAX_ERROR_SIZE]
SCRIPT_EXPORT bool AssembleMem(duint addr, const char* instruction);
SCRIPT_EXPORT bool AssembleMemEx(duint addr, const char* instruction, int* size, char* error, bool fillnop); //error[MAX_ERROR_SIZE]
}; //Assembler
}; //Script
#ifndef _SCRIPTAPI_ASSEMBLER_H
#define _SCRIPTAPI_ASSEMBLER_H
#include "_scriptapi.h"
namespace Script
{
namespace Assembler
{
SCRIPT_EXPORT bool Assemble(duint addr, unsigned char* dest, int* size, const char* instruction); //dest[16]
SCRIPT_EXPORT bool AssembleEx(duint addr, unsigned char* dest, int* size, const char* instruction, char* error); //dest[16], error[MAX_ERROR_SIZE]
SCRIPT_EXPORT bool AssembleMem(duint addr, const char* instruction);
SCRIPT_EXPORT bool AssembleMemEx(duint addr, const char* instruction, int* size, char* error, bool fillnop); //error[MAX_ERROR_SIZE]
}; //Assembler
}; //Script
#endif //_SCRIPTAPI_ASSEMBLER_H

View File

@ -1,71 +1,71 @@
#include "_scriptapi_debug.h"
SCRIPT_EXPORT void Script::Debug::Wait()
{
_plugin_waituntilpaused();
}
SCRIPT_EXPORT void Script::Debug::Run()
{
DbgCmdExecDirect("run");
Wait();
}
SCRIPT_EXPORT void Script::Debug::Pause()
{
DbgCmdExecDirect("pause");
Wait();
}
SCRIPT_EXPORT void Script::Debug::Stop()
{
DbgCmdExecDirect("StopDebug");
Wait();
}
SCRIPT_EXPORT void Script::Debug::StepIn()
{
DbgCmdExecDirect("StepInto");
Wait();
}
SCRIPT_EXPORT void Script::Debug::StepOver()
{
DbgCmdExecDirect("StepOver");
Wait();
}
SCRIPT_EXPORT void Script::Debug::StepOut()
{
DbgCmdExecDirect("StepOut");
Wait();
}
SCRIPT_EXPORT bool Script::Debug::SetBreakpoint(duint address)
{
char command[128] = "";
sprintf_s(command, "bp %p", address);
return DbgCmdExecDirect(command);
}
SCRIPT_EXPORT bool Script::Debug::DeleteBreakpoint(duint address)
{
char command[128] = "";
sprintf_s(command, "bc %p", address);
return DbgCmdExecDirect(command);
}
SCRIPT_EXPORT bool Script::Debug::SetHardwareBreakpoint(duint address, HardwareType type)
{
char command[128] = "";
const char* types[] = { "rw", "w", "x" };
sprintf_s(command, "bphws %p, %s", address, types[type]);
return DbgCmdExecDirect(command);
}
SCRIPT_EXPORT bool Script::Debug::DeleteHardwareBreakpoint(duint address)
{
char command[128] = "";
sprintf_s(command, "bphwc %p", address);
return DbgCmdExecDirect(command);
#include "_scriptapi_debug.h"
SCRIPT_EXPORT void Script::Debug::Wait()
{
_plugin_waituntilpaused();
}
SCRIPT_EXPORT void Script::Debug::Run()
{
DbgCmdExecDirect("run");
Wait();
}
SCRIPT_EXPORT void Script::Debug::Pause()
{
DbgCmdExecDirect("pause");
Wait();
}
SCRIPT_EXPORT void Script::Debug::Stop()
{
DbgCmdExecDirect("StopDebug");
Wait();
}
SCRIPT_EXPORT void Script::Debug::StepIn()
{
DbgCmdExecDirect("StepInto");
Wait();
}
SCRIPT_EXPORT void Script::Debug::StepOver()
{
DbgCmdExecDirect("StepOver");
Wait();
}
SCRIPT_EXPORT void Script::Debug::StepOut()
{
DbgCmdExecDirect("StepOut");
Wait();
}
SCRIPT_EXPORT bool Script::Debug::SetBreakpoint(duint address)
{
char command[128] = "";
sprintf_s(command, "bp %p", address);
return DbgCmdExecDirect(command);
}
SCRIPT_EXPORT bool Script::Debug::DeleteBreakpoint(duint address)
{
char command[128] = "";
sprintf_s(command, "bc %p", address);
return DbgCmdExecDirect(command);
}
SCRIPT_EXPORT bool Script::Debug::SetHardwareBreakpoint(duint address, HardwareType type)
{
char command[128] = "";
const char* types[] = { "rw", "w", "x" };
sprintf_s(command, "bphws %p, %s", address, types[type]);
return DbgCmdExecDirect(command);
}
SCRIPT_EXPORT bool Script::Debug::DeleteHardwareBreakpoint(duint address)
{
char command[128] = "";
sprintf_s(command, "bphwc %p", address);
return DbgCmdExecDirect(command);
}

View File

@ -1,31 +1,31 @@
#ifndef _SCRIPTAPI_DEBUG_H
#define _SCRIPTAPI_DEBUG_H
#include "_scriptapi.h"
namespace Script
{
namespace Debug
{
enum HardwareType
{
HardwareAccess,
HardwareWrite,
HardwareExecute
};
SCRIPT_EXPORT void Wait();
SCRIPT_EXPORT void Run();
SCRIPT_EXPORT void Pause();
SCRIPT_EXPORT void Stop();
SCRIPT_EXPORT void StepIn();
SCRIPT_EXPORT void StepOver();
SCRIPT_EXPORT void StepOut();
SCRIPT_EXPORT bool SetBreakpoint(duint address);
SCRIPT_EXPORT bool DeleteBreakpoint(duint address);
SCRIPT_EXPORT bool SetHardwareBreakpoint(duint address, HardwareType type = HardwareExecute);
SCRIPT_EXPORT bool DeleteHardwareBreakpoint(duint address);
}; //Debug
}; //Script
#ifndef _SCRIPTAPI_DEBUG_H
#define _SCRIPTAPI_DEBUG_H
#include "_scriptapi.h"
namespace Script
{
namespace Debug
{
enum HardwareType
{
HardwareAccess,
HardwareWrite,
HardwareExecute
};
SCRIPT_EXPORT void Wait();
SCRIPT_EXPORT void Run();
SCRIPT_EXPORT void Pause();
SCRIPT_EXPORT void Stop();
SCRIPT_EXPORT void StepIn();
SCRIPT_EXPORT void StepOver();
SCRIPT_EXPORT void StepOut();
SCRIPT_EXPORT bool SetBreakpoint(duint address);
SCRIPT_EXPORT bool DeleteBreakpoint(duint address);
SCRIPT_EXPORT bool SetHardwareBreakpoint(duint address, HardwareType type = HardwareExecute);
SCRIPT_EXPORT bool DeleteHardwareBreakpoint(duint address);
}; //Debug
}; //Script
#endif //_SCRIPTAPI_DEBUG_H

View File

@ -1,116 +1,116 @@
#include "_scriptapi_flag.h"
#include "value.h"
static const char* flagTable[] =
{
"ZF",
"OF",
"CF",
"PF",
"SF",
"TF",
"AF",
"DF",
"IF"
};
SCRIPT_EXPORT bool Script::Flag::Get(FlagEnum flag)
{
duint value;
return valfromstring(flagTable[flag], &value) ? !!value : false;
}
SCRIPT_EXPORT bool Script::Flag::Set(FlagEnum flag, bool value)
{
return setflag(flagTable[flag], value);
}
SCRIPT_EXPORT bool Script::Flag::GetZF()
{
return Get(ZF);
}
SCRIPT_EXPORT bool Script::Flag::SetZF(bool value)
{
return Set(ZF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetOF()
{
return Get(OF);
}
SCRIPT_EXPORT bool Script::Flag::SetOF(bool value)
{
return Set(OF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetCF()
{
return Get(CF);
}
SCRIPT_EXPORT bool Script::Flag::SetCF(bool value)
{
return Set(CF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetPF()
{
return Get(PF);
}
SCRIPT_EXPORT bool Script::Flag::SetPF(bool value)
{
return Set(PF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetSF()
{
return Get(SF);
}
SCRIPT_EXPORT bool Script::Flag::SetSF(bool value)
{
return Set(SF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetTF()
{
return Get(TF);
}
SCRIPT_EXPORT bool Script::Flag::SetTF(bool value)
{
return Set(TF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetAF()
{
return Get(AF);
}
SCRIPT_EXPORT bool Script::Flag::SetAF(bool value)
{
return Set(AF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetDF()
{
return Get(DF);
}
SCRIPT_EXPORT bool Script::Flag::SetDF(bool value)
{
return Set(DF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetIF()
{
return Get(IF);
}
SCRIPT_EXPORT bool Script::Flag::SetIF(bool value)
{
return Set(IF, value);
#include "_scriptapi_flag.h"
#include "value.h"
static const char* flagTable[] =
{
"ZF",
"OF",
"CF",
"PF",
"SF",
"TF",
"AF",
"DF",
"IF"
};
SCRIPT_EXPORT bool Script::Flag::Get(FlagEnum flag)
{
duint value;
return valfromstring(flagTable[flag], &value) ? !!value : false;
}
SCRIPT_EXPORT bool Script::Flag::Set(FlagEnum flag, bool value)
{
return setflag(flagTable[flag], value);
}
SCRIPT_EXPORT bool Script::Flag::GetZF()
{
return Get(ZF);
}
SCRIPT_EXPORT bool Script::Flag::SetZF(bool value)
{
return Set(ZF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetOF()
{
return Get(OF);
}
SCRIPT_EXPORT bool Script::Flag::SetOF(bool value)
{
return Set(OF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetCF()
{
return Get(CF);
}
SCRIPT_EXPORT bool Script::Flag::SetCF(bool value)
{
return Set(CF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetPF()
{
return Get(PF);
}
SCRIPT_EXPORT bool Script::Flag::SetPF(bool value)
{
return Set(PF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetSF()
{
return Get(SF);
}
SCRIPT_EXPORT bool Script::Flag::SetSF(bool value)
{
return Set(SF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetTF()
{
return Get(TF);
}
SCRIPT_EXPORT bool Script::Flag::SetTF(bool value)
{
return Set(TF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetAF()
{
return Get(AF);
}
SCRIPT_EXPORT bool Script::Flag::SetAF(bool value)
{
return Set(AF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetDF()
{
return Get(DF);
}
SCRIPT_EXPORT bool Script::Flag::SetDF(bool value)
{
return Set(DF, value);
}
SCRIPT_EXPORT bool Script::Flag::GetIF()
{
return Get(IF);
}
SCRIPT_EXPORT bool Script::Flag::SetIF(bool value)
{
return Set(IF, value);
}

View File

@ -1,47 +1,47 @@
#ifndef _SCRIPTAPI_FLAG_H
#define _SCRIPTAPI_FLAG_H
#include "_scriptapi.h"
namespace Script
{
namespace Flag
{
enum FlagEnum
{
ZF,
OF,
CF,
PF,
SF,
TF,
AF,
DF,
IF
};
SCRIPT_EXPORT bool Get(FlagEnum flag);
SCRIPT_EXPORT bool Set(FlagEnum flag, bool value);
SCRIPT_EXPORT bool GetZF();
SCRIPT_EXPORT bool SetZF(bool value);
SCRIPT_EXPORT bool GetOF();
SCRIPT_EXPORT bool SetOF(bool value);
SCRIPT_EXPORT bool GetCF();
SCRIPT_EXPORT bool SetCF(bool value);
SCRIPT_EXPORT bool GetPF();
SCRIPT_EXPORT bool SetPF(bool value);
SCRIPT_EXPORT bool GetSF();
SCRIPT_EXPORT bool SetSF(bool value);
SCRIPT_EXPORT bool GetTF();
SCRIPT_EXPORT bool SetTF(bool value);
SCRIPT_EXPORT bool GetAF();
SCRIPT_EXPORT bool SetAF(bool value);
SCRIPT_EXPORT bool GetDF();
SCRIPT_EXPORT bool SetDF(bool value);
SCRIPT_EXPORT bool GetIF();
SCRIPT_EXPORT bool SetIF(bool value);
};
};
#ifndef _SCRIPTAPI_FLAG_H
#define _SCRIPTAPI_FLAG_H
#include "_scriptapi.h"
namespace Script
{
namespace Flag
{
enum FlagEnum
{
ZF,
OF,
CF,
PF,
SF,
TF,
AF,
DF,
IF
};
SCRIPT_EXPORT bool Get(FlagEnum flag);
SCRIPT_EXPORT bool Set(FlagEnum flag, bool value);
SCRIPT_EXPORT bool GetZF();
SCRIPT_EXPORT bool SetZF(bool value);
SCRIPT_EXPORT bool GetOF();
SCRIPT_EXPORT bool SetOF(bool value);
SCRIPT_EXPORT bool GetCF();
SCRIPT_EXPORT bool SetCF(bool value);
SCRIPT_EXPORT bool GetPF();
SCRIPT_EXPORT bool SetPF(bool value);
SCRIPT_EXPORT bool GetSF();
SCRIPT_EXPORT bool SetSF(bool value);
SCRIPT_EXPORT bool GetTF();
SCRIPT_EXPORT bool SetTF(bool value);
SCRIPT_EXPORT bool GetAF();
SCRIPT_EXPORT bool SetAF(bool value);
SCRIPT_EXPORT bool GetDF();
SCRIPT_EXPORT bool SetDF(bool value);
SCRIPT_EXPORT bool GetIF();
SCRIPT_EXPORT bool SetIF(bool value);
};
};
#endif //_SCRIPTAPI_FLAG_H

View File

@ -1,152 +1,152 @@
#include "_scriptapi_gui.h"
#include "_scriptapi_misc.h"
SCRIPT_EXPORT bool Script::Gui::Disassembly::SelectionGet(duint* start, duint* end)
{
return Gui::SelectionGet(DisassemblyWindow, start, end);
}
SCRIPT_EXPORT bool Script::Gui::Disassembly::SelectionSet(duint start, duint end)
{
return Gui::SelectionSet(DisassemblyWindow, start, end);
}
SCRIPT_EXPORT duint Script::Gui::Disassembly::SelectionGetStart()
{
return Gui::SelectionGetStart(DisassemblyWindow);
}
SCRIPT_EXPORT duint Script::Gui::Disassembly::SelectionGetEnd()
{
return Gui::SelectionGetEnd(DisassemblyWindow);
}
SCRIPT_EXPORT bool Script::Gui::Dump::SelectionGet(duint* start, duint* end)
{
return Gui::SelectionGet(DumpWindow, start, end);
}
SCRIPT_EXPORT bool Script::Gui::Dump::SelectionSet(duint start, duint end)
{
return Gui::SelectionSet(DumpWindow, start, end);
}
SCRIPT_EXPORT duint Script::Gui::Dump::SelectionGetStart()
{
return Gui::SelectionGetStart(DumpWindow);
}
SCRIPT_EXPORT duint Script::Gui::Dump::SelectionGetEnd()
{
return Gui::SelectionGetEnd(DumpWindow);
}
SCRIPT_EXPORT bool Script::Gui::Stack::SelectionGet(duint* start, duint* end)
{
return Gui::SelectionGet(StackWindow, start, end);
}
SCRIPT_EXPORT bool Script::Gui::Stack::SelectionSet(duint start, duint end)
{
return Gui::SelectionSet(StackWindow, start, end);
}
SCRIPT_EXPORT duint Script::Gui::Stack::SelectionGetStart()
{
return Gui::SelectionGetStart(StackWindow);
}
SCRIPT_EXPORT duint Script::Gui::Stack::SelectionGetEnd()
{
return Gui::SelectionGetEnd(StackWindow);
}
static inline int windowToBridge(Script::Gui::Window window)
{
switch(window)
{
case Script::Gui::DisassemblyWindow:
return GUI_DISASSEMBLY;
case Script::Gui::DumpWindow:
return GUI_DUMP;
case Script::Gui::StackWindow:
return GUI_STACK;
default:
return GUI_DISASSEMBLY;
}
}
SCRIPT_EXPORT bool Script::Gui::SelectionGet(Script::Gui::Window window, duint* start, duint* end)
{
SELECTIONDATA selection;
if(!GuiSelectionGet(windowToBridge(window), &selection))
return false;
if(start)
*start = selection.start;
if(end)
*end = selection.end;
return true;
}
SCRIPT_EXPORT bool Script::Gui::SelectionSet(Script::Gui::Window window, duint start, duint end)
{
SELECTIONDATA selection;
selection.start = start;
selection.end = end;
return GuiSelectionSet(windowToBridge(window), &selection);
}
SCRIPT_EXPORT duint Script::Gui::SelectionGetStart(Script::Gui::Window window)
{
duint start;
return Gui::SelectionGet(window, &start, nullptr) ? start : 0;
}
SCRIPT_EXPORT duint Script::Gui::SelectionGetEnd(Script::Gui::Window window)
{
duint end;
return Gui::SelectionGet(window, nullptr, &end) ? end : 0;
}
SCRIPT_EXPORT void Script::Gui::Message(const char* message)
{
GuiScriptMessage(message);
}
SCRIPT_EXPORT bool Script::Gui::MessageYesNo(const char* message)
{
return !!GuiScriptMsgyn(message);
}
SCRIPT_EXPORT bool Script::Gui::InputLine(const char* title, char* text)
{
return GuiGetLineWindow(title, text);
}
SCRIPT_EXPORT bool Script::Gui::InputValue(const char* title, duint* value)
{
Memory<char*> line(GUI_MAX_LINE_SIZE);
if(!GuiGetLineWindow(title, line()))
return false;
return Misc::ParseExpression(line(), value);
}
SCRIPT_EXPORT void Script::Gui::Refresh()
{
GuiUpdateAllViews();
}
SCRIPT_EXPORT void Script::Gui::AddQWidgetTab(void* qWidget)
{
GuiAddQWidgetTab(qWidget);
}
SCRIPT_EXPORT void Script::Gui::ShowQWidgetTab(void* qWidget)
{
GuiShowQWidgetTab(qWidget);
}
SCRIPT_EXPORT void Script::Gui::CloseQWidgetTab(void* qWidget)
{
GuiCloseQWidgetTab(qWidget);
#include "_scriptapi_gui.h"
#include "_scriptapi_misc.h"
SCRIPT_EXPORT bool Script::Gui::Disassembly::SelectionGet(duint* start, duint* end)
{
return Gui::SelectionGet(DisassemblyWindow, start, end);
}
SCRIPT_EXPORT bool Script::Gui::Disassembly::SelectionSet(duint start, duint end)
{
return Gui::SelectionSet(DisassemblyWindow, start, end);
}
SCRIPT_EXPORT duint Script::Gui::Disassembly::SelectionGetStart()
{
return Gui::SelectionGetStart(DisassemblyWindow);
}
SCRIPT_EXPORT duint Script::Gui::Disassembly::SelectionGetEnd()
{
return Gui::SelectionGetEnd(DisassemblyWindow);
}
SCRIPT_EXPORT bool Script::Gui::Dump::SelectionGet(duint* start, duint* end)
{
return Gui::SelectionGet(DumpWindow, start, end);
}
SCRIPT_EXPORT bool Script::Gui::Dump::SelectionSet(duint start, duint end)
{
return Gui::SelectionSet(DumpWindow, start, end);
}
SCRIPT_EXPORT duint Script::Gui::Dump::SelectionGetStart()
{
return Gui::SelectionGetStart(DumpWindow);
}
SCRIPT_EXPORT duint Script::Gui::Dump::SelectionGetEnd()
{
return Gui::SelectionGetEnd(DumpWindow);
}
SCRIPT_EXPORT bool Script::Gui::Stack::SelectionGet(duint* start, duint* end)
{
return Gui::SelectionGet(StackWindow, start, end);
}
SCRIPT_EXPORT bool Script::Gui::Stack::SelectionSet(duint start, duint end)
{
return Gui::SelectionSet(StackWindow, start, end);
}
SCRIPT_EXPORT duint Script::Gui::Stack::SelectionGetStart()
{
return Gui::SelectionGetStart(StackWindow);
}
SCRIPT_EXPORT duint Script::Gui::Stack::SelectionGetEnd()
{
return Gui::SelectionGetEnd(StackWindow);
}
static inline int windowToBridge(Script::Gui::Window window)
{
switch(window)
{
case Script::Gui::DisassemblyWindow:
return GUI_DISASSEMBLY;
case Script::Gui::DumpWindow:
return GUI_DUMP;
case Script::Gui::StackWindow:
return GUI_STACK;
default:
return GUI_DISASSEMBLY;
}
}
SCRIPT_EXPORT bool Script::Gui::SelectionGet(Script::Gui::Window window, duint* start, duint* end)
{
SELECTIONDATA selection;
if(!GuiSelectionGet(windowToBridge(window), &selection))
return false;
if(start)
*start = selection.start;
if(end)
*end = selection.end;
return true;
}
SCRIPT_EXPORT bool Script::Gui::SelectionSet(Script::Gui::Window window, duint start, duint end)
{
SELECTIONDATA selection;
selection.start = start;
selection.end = end;
return GuiSelectionSet(windowToBridge(window), &selection);
}
SCRIPT_EXPORT duint Script::Gui::SelectionGetStart(Script::Gui::Window window)
{
duint start;
return Gui::SelectionGet(window, &start, nullptr) ? start : 0;
}
SCRIPT_EXPORT duint Script::Gui::SelectionGetEnd(Script::Gui::Window window)
{
duint end;
return Gui::SelectionGet(window, nullptr, &end) ? end : 0;
}
SCRIPT_EXPORT void Script::Gui::Message(const char* message)
{
GuiScriptMessage(message);
}
SCRIPT_EXPORT bool Script::Gui::MessageYesNo(const char* message)
{
return !!GuiScriptMsgyn(message);
}
SCRIPT_EXPORT bool Script::Gui::InputLine(const char* title, char* text)
{
return GuiGetLineWindow(title, text);
}
SCRIPT_EXPORT bool Script::Gui::InputValue(const char* title, duint* value)
{
Memory<char*> line(GUI_MAX_LINE_SIZE);
if(!GuiGetLineWindow(title, line()))
return false;
return Misc::ParseExpression(line(), value);
}
SCRIPT_EXPORT void Script::Gui::Refresh()
{
GuiUpdateAllViews();
}
SCRIPT_EXPORT void Script::Gui::AddQWidgetTab(void* qWidget)
{
GuiAddQWidgetTab(qWidget);
}
SCRIPT_EXPORT void Script::Gui::ShowQWidgetTab(void* qWidget)
{
GuiShowQWidgetTab(qWidget);
}
SCRIPT_EXPORT void Script::Gui::CloseQWidgetTab(void* qWidget)
{
GuiCloseQWidgetTab(qWidget);
}

View File

@ -1,60 +1,60 @@
#ifndef _SCRIPTAPI_GUI_H
#define _SCRIPTAPI_GUI_H
#include "_scriptapi.h"
namespace Script
{
namespace Gui
{
namespace Disassembly
{
SCRIPT_EXPORT bool SelectionGet(duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart();
SCRIPT_EXPORT duint SelectionGetEnd();
}; //Disassembly
namespace Dump
{
SCRIPT_EXPORT bool SelectionGet(duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart();
SCRIPT_EXPORT duint SelectionGetEnd();
}; //Dump
namespace Stack
{
SCRIPT_EXPORT bool SelectionGet(duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart();
SCRIPT_EXPORT duint SelectionGetEnd();
}; //Stack
}; //Gui
namespace Gui
{
enum Window
{
DisassemblyWindow,
DumpWindow,
StackWindow
};
SCRIPT_EXPORT bool SelectionGet(Window window, duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(Window window, duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart(Window window);
SCRIPT_EXPORT duint SelectionGetEnd(Window window);
SCRIPT_EXPORT void Message(const char* message);
SCRIPT_EXPORT bool MessageYesNo(const char* message);
SCRIPT_EXPORT bool InputLine(const char* title, char* text); //text[GUI_MAX_LINE_SIZE]
SCRIPT_EXPORT bool InputValue(const char* title, duint* value);
SCRIPT_EXPORT void Refresh();
SCRIPT_EXPORT void AddQWidgetTab(void* qWidget);
SCRIPT_EXPORT void ShowQWidgetTab(void* qWidget);
SCRIPT_EXPORT void CloseQWidgetTab(void* qWidget);
}; //Gui
}; //Script
#ifndef _SCRIPTAPI_GUI_H
#define _SCRIPTAPI_GUI_H
#include "_scriptapi.h"
namespace Script
{
namespace Gui
{
namespace Disassembly
{
SCRIPT_EXPORT bool SelectionGet(duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart();
SCRIPT_EXPORT duint SelectionGetEnd();
}; //Disassembly
namespace Dump
{
SCRIPT_EXPORT bool SelectionGet(duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart();
SCRIPT_EXPORT duint SelectionGetEnd();
}; //Dump
namespace Stack
{
SCRIPT_EXPORT bool SelectionGet(duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart();
SCRIPT_EXPORT duint SelectionGetEnd();
}; //Stack
}; //Gui
namespace Gui
{
enum Window
{
DisassemblyWindow,
DumpWindow,
StackWindow
};
SCRIPT_EXPORT bool SelectionGet(Window window, duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(Window window, duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart(Window window);
SCRIPT_EXPORT duint SelectionGetEnd(Window window);
SCRIPT_EXPORT void Message(const char* message);
SCRIPT_EXPORT bool MessageYesNo(const char* message);
SCRIPT_EXPORT bool InputLine(const char* title, char* text); //text[GUI_MAX_LINE_SIZE]
SCRIPT_EXPORT bool InputValue(const char* title, duint* value);
SCRIPT_EXPORT void Refresh();
SCRIPT_EXPORT void AddQWidgetTab(void* qWidget);
SCRIPT_EXPORT void ShowQWidgetTab(void* qWidget);
SCRIPT_EXPORT void CloseQWidgetTab(void* qWidget);
}; //Gui
}; //Script
#endif //_SCRIPTAPI_GUI_H

View File

@ -1,87 +1,87 @@
#include "_scriptapi_memory.h"
#include "memory.h"
SCRIPT_EXPORT bool Script::Memory::Read(duint addr, void* data, duint size, duint* sizeRead)
{
return MemRead(addr, data, size, sizeRead);
}
SCRIPT_EXPORT bool Script::Memory::Write(duint addr, const void* data, duint size, duint* sizeWritten)
{
return MemWrite(addr, (void*)data, size, sizeWritten);
}
SCRIPT_EXPORT bool Script::Memory::IsValidPtr(duint addr)
{
return MemIsValidReadPtr(addr);
}
SCRIPT_EXPORT duint Script::Memory::RemoteAlloc(duint addr, duint size)
{
return (duint)MemAllocRemote(addr, size);
}
SCRIPT_EXPORT bool Script::Memory::RemoteFree(duint addr)
{
return MemFreeRemote(addr);
}
SCRIPT_EXPORT unsigned char Script::Memory::ReadByte(duint addr)
{
unsigned char data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WriteByte(duint addr, unsigned char data)
{
return Write(addr, &data, sizeof(data), nullptr);
}
SCRIPT_EXPORT unsigned short Script::Memory::ReadWord(duint addr)
{
unsigned short data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WriteWord(duint addr, unsigned short data)
{
return Write(addr, &data, sizeof(data), nullptr);
}
SCRIPT_EXPORT unsigned int Script::Memory::ReadDword(duint addr)
{
unsigned int data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WriteDword(duint addr, unsigned int data)
{
return Write(addr, &data, sizeof(data), nullptr);
}
SCRIPT_EXPORT unsigned long long Script::Memory::ReadQword(duint addr)
{
unsigned long long data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WriteQword(duint addr, unsigned long long data)
{
return Write(addr, &data, sizeof(data), nullptr);
}
SCRIPT_EXPORT duint Script::Memory::ReadPtr(duint addr)
{
duint data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WritePtr(duint addr, duint data)
{
return Write(addr, &data, sizeof(data), nullptr);
#include "_scriptapi_memory.h"
#include "memory.h"
SCRIPT_EXPORT bool Script::Memory::Read(duint addr, void* data, duint size, duint* sizeRead)
{
return MemRead(addr, data, size, sizeRead);
}
SCRIPT_EXPORT bool Script::Memory::Write(duint addr, const void* data, duint size, duint* sizeWritten)
{
return MemWrite(addr, (void*)data, size, sizeWritten);
}
SCRIPT_EXPORT bool Script::Memory::IsValidPtr(duint addr)
{
return MemIsValidReadPtr(addr);
}
SCRIPT_EXPORT duint Script::Memory::RemoteAlloc(duint addr, duint size)
{
return (duint)MemAllocRemote(addr, size);
}
SCRIPT_EXPORT bool Script::Memory::RemoteFree(duint addr)
{
return MemFreeRemote(addr);
}
SCRIPT_EXPORT unsigned char Script::Memory::ReadByte(duint addr)
{
unsigned char data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WriteByte(duint addr, unsigned char data)
{
return Write(addr, &data, sizeof(data), nullptr);
}
SCRIPT_EXPORT unsigned short Script::Memory::ReadWord(duint addr)
{
unsigned short data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WriteWord(duint addr, unsigned short data)
{
return Write(addr, &data, sizeof(data), nullptr);
}
SCRIPT_EXPORT unsigned int Script::Memory::ReadDword(duint addr)
{
unsigned int data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WriteDword(duint addr, unsigned int data)
{
return Write(addr, &data, sizeof(data), nullptr);
}
SCRIPT_EXPORT unsigned long long Script::Memory::ReadQword(duint addr)
{
unsigned long long data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WriteQword(duint addr, unsigned long long data)
{
return Write(addr, &data, sizeof(data), nullptr);
}
SCRIPT_EXPORT duint Script::Memory::ReadPtr(duint addr)
{
duint data;
Read(addr, &data, sizeof(data), nullptr);
return data;
}
SCRIPT_EXPORT bool Script::Memory::WritePtr(duint addr, duint data)
{
return Write(addr, &data, sizeof(data), nullptr);
}

View File

@ -1,29 +1,29 @@
#ifndef _SCRIPTAPI_MEMORY_H
#define _SCRIPTAPI_MEMORY_H
#include "_scriptapi.h"
namespace Script
{
namespace Memory
{
SCRIPT_EXPORT bool Read(duint addr, void* data, duint size, duint* sizeRead);
SCRIPT_EXPORT bool Write(duint addr, const void* data, duint size, duint* sizeWritten);
SCRIPT_EXPORT bool IsValidPtr(duint addr);
SCRIPT_EXPORT duint RemoteAlloc(duint addr, duint size);
SCRIPT_EXPORT bool RemoteFree(duint addr);
SCRIPT_EXPORT unsigned char ReadByte(duint addr);
SCRIPT_EXPORT bool WriteByte(duint addr, unsigned char data);
SCRIPT_EXPORT unsigned short ReadWord(duint addr);
SCRIPT_EXPORT bool WriteWord(duint addr, unsigned short data);
SCRIPT_EXPORT unsigned int ReadDword(duint addr);
SCRIPT_EXPORT bool WriteDword(duint addr, unsigned int data);
SCRIPT_EXPORT unsigned long long ReadQword(duint addr);
SCRIPT_EXPORT bool WriteQword(duint addr, unsigned long long data);
SCRIPT_EXPORT duint ReadPtr(duint addr);
SCRIPT_EXPORT bool WritePtr(duint addr, duint data);
}; //Memory
}; //Script
#ifndef _SCRIPTAPI_MEMORY_H
#define _SCRIPTAPI_MEMORY_H
#include "_scriptapi.h"
namespace Script
{
namespace Memory
{
SCRIPT_EXPORT bool Read(duint addr, void* data, duint size, duint* sizeRead);
SCRIPT_EXPORT bool Write(duint addr, const void* data, duint size, duint* sizeWritten);
SCRIPT_EXPORT bool IsValidPtr(duint addr);
SCRIPT_EXPORT duint RemoteAlloc(duint addr, duint size);
SCRIPT_EXPORT bool RemoteFree(duint addr);
SCRIPT_EXPORT unsigned char ReadByte(duint addr);
SCRIPT_EXPORT bool WriteByte(duint addr, unsigned char data);
SCRIPT_EXPORT unsigned short ReadWord(duint addr);
SCRIPT_EXPORT bool WriteWord(duint addr, unsigned short data);
SCRIPT_EXPORT unsigned int ReadDword(duint addr);
SCRIPT_EXPORT bool WriteDword(duint addr, unsigned int data);
SCRIPT_EXPORT unsigned long long ReadQword(duint addr);
SCRIPT_EXPORT bool WriteQword(duint addr, unsigned long long data);
SCRIPT_EXPORT duint ReadPtr(duint addr);
SCRIPT_EXPORT bool WritePtr(duint addr, duint data);
}; //Memory
}; //Script
#endif //_SCRIPTAPI_MEMORY_H

View File

@ -1,33 +1,33 @@
#include "_scriptapi_misc.h"
#include "value.h"
SCRIPT_EXPORT bool Script::Misc::ParseExpression(const char* expression, duint* value)
{
return valfromstring(expression, value);
}
SCRIPT_EXPORT duint Script::Misc::RemoteGetProcAddress(const char* module, const char* api)
{
duint value;
if(!ParseExpression(StringUtils::sprintf("%s:%s", module, api).c_str(), &value))
return 0;
return value;
}
SCRIPT_EXPORT duint Script::Misc::ResolveLabel(const char* label)
{
duint value;
if(!ParseExpression(label, &value))
return 0;
return value;
}
SCRIPT_EXPORT void* Script::Misc::Alloc(duint size)
{
return BridgeAlloc(size);
}
SCRIPT_EXPORT void Script::Misc::Free(void* ptr)
{
return BridgeFree(ptr);
#include "_scriptapi_misc.h"
#include "value.h"
SCRIPT_EXPORT bool Script::Misc::ParseExpression(const char* expression, duint* value)
{
return valfromstring(expression, value);
}
SCRIPT_EXPORT duint Script::Misc::RemoteGetProcAddress(const char* module, const char* api)
{
duint value;
if(!ParseExpression(StringUtils::sprintf("%s:%s", module, api).c_str(), &value))
return 0;
return value;
}
SCRIPT_EXPORT duint Script::Misc::ResolveLabel(const char* label)
{
duint value;
if(!ParseExpression(label, &value))
return 0;
return value;
}
SCRIPT_EXPORT void* Script::Misc::Alloc(duint size)
{
return BridgeAlloc(size);
}
SCRIPT_EXPORT void Script::Misc::Free(void* ptr)
{
return BridgeFree(ptr);
}

View File

@ -1,18 +1,18 @@
#ifndef _SCRIPTAPI_MISC_H
#define _SCRIPTAPI_MISC_H
#include "_scriptapi.h"
namespace Script
{
namespace Misc
{
SCRIPT_EXPORT bool ParseExpression(const char* expression, duint* value);
SCRIPT_EXPORT duint RemoteGetProcAddress(const char* module, const char* api);
SCRIPT_EXPORT duint ResolveLabel(const char* label);
SCRIPT_EXPORT void* Alloc(duint size);
SCRIPT_EXPORT void Free(void* ptr);
}; //Misc
}; //Script
#ifndef _SCRIPTAPI_MISC_H
#define _SCRIPTAPI_MISC_H
#include "_scriptapi.h"
namespace Script
{
namespace Misc
{
SCRIPT_EXPORT bool ParseExpression(const char* expression, duint* value);
SCRIPT_EXPORT duint RemoteGetProcAddress(const char* module, const char* api);
SCRIPT_EXPORT duint ResolveLabel(const char* label);
SCRIPT_EXPORT void* Alloc(duint size);
SCRIPT_EXPORT void Free(void* ptr);
}; //Misc
}; //Script
#endif //_SCRIPTAPI_MISC_H

View File

@ -1,185 +1,185 @@
#include "_scriptapi_module.h"
#include "threading.h"
#include "module.h"
#include "debugger.h"
SCRIPT_EXPORT bool Script::Module::InfoFromAddr(duint addr, Script::Module::ModuleInfo* info)
{
SHARED_ACQUIRE(LockModules);
MODINFO* modInfo = ModInfoFromAddr(addr);
if(!info || !modInfo)
return false;
info->base = modInfo->base;
info->size = modInfo->size;
info->entry = modInfo->entry;
info->sectionCount = int(modInfo->sections.size());
strcpy_s(info->name, modInfo->name);
strcat_s(info->name, modInfo->extension);
strcpy_s(info->path, modInfo->path);
return true;
}
SCRIPT_EXPORT bool Script::Module::InfoFromName(const char* name, Script::Module::ModuleInfo* info)
{
return Module::InfoFromAddr(Module::BaseFromName(name), info);
}
SCRIPT_EXPORT duint Script::Module::BaseFromAddr(duint addr)
{
return ModBaseFromAddr(addr);
}
SCRIPT_EXPORT duint Script::Module::BaseFromName(const char* name)
{
return ModBaseFromName(name);
}
SCRIPT_EXPORT duint Script::Module::SizeFromAddr(duint addr)
{
return ModSizeFromAddr(addr);
}
SCRIPT_EXPORT duint Script::Module::SizeFromName(const char* name)
{
return Module::SizeFromAddr(Module::BaseFromName(name));
}
SCRIPT_EXPORT bool Script::Module::NameFromAddr(duint addr, char* name)
{
return ModNameFromAddr(addr, name, true);
}
SCRIPT_EXPORT bool Script::Module::PathFromAddr(duint addr, char* path)
{
return !!ModPathFromAddr(addr, path, MAX_PATH);
}
SCRIPT_EXPORT bool Script::Module::PathFromName(const char* name, char* path)
{
return Module::PathFromAddr(Module::BaseFromName(name), path);
}
SCRIPT_EXPORT duint Script::Module::EntryFromAddr(duint addr)
{
return ModEntryFromAddr(addr);
}
SCRIPT_EXPORT duint Script::Module::EntryFromName(const char* name)
{
return Module::EntryFromAddr(Module::BaseFromName(name));
}
SCRIPT_EXPORT int Script::Module::SectionCountFromAddr(duint addr)
{
SHARED_ACQUIRE(LockModules);
MODINFO* modInfo = ModInfoFromAddr(addr);
return modInfo ? int(modInfo->sections.size()) : 0;
}
SCRIPT_EXPORT int Script::Module::SectionCountFromName(const char* name)
{
return Module::SectionCountFromAddr(Module::BaseFromName(name));
}
SCRIPT_EXPORT bool Script::Module::SectionFromAddr(duint addr, int number, ModuleSectionInfo* section)
{
SHARED_ACQUIRE(LockModules);
MODINFO* modInfo = ModInfoFromAddr(addr);
if(!section || !modInfo || number < 0 || number >= int(modInfo->sections.size()))
return false;
const MODSECTIONINFO & secInfo = modInfo->sections.at(number);
section->addr = secInfo.addr;
section->size = secInfo.size;
strcpy_s(section->name, secInfo.name);
return true;
}
SCRIPT_EXPORT bool Script::Module::SectionFromName(const char* name, int number, ModuleSectionInfo* section)
{
return Module::SectionFromAddr(Module::BaseFromName(name), number, section);
}
SCRIPT_EXPORT bool Script::Module::SectionListFromAddr(duint addr, ListOf(ModuleSectionInfo) listInfo)
{
SHARED_ACQUIRE(LockModules);
MODINFO* modInfo = ModInfoFromAddr(addr);
if(!modInfo)
return false;
std::vector<ModuleSectionInfo> scriptSectionList;
scriptSectionList.reserve(modInfo->sections.size());
for(const auto & section : modInfo->sections)
{
ModuleSectionInfo scriptSection;
scriptSection.addr = section.addr;
scriptSection.size = section.size;
strcpy_s(scriptSection.name, section.name);
scriptSectionList.push_back(scriptSection);
}
return List<ModuleSectionInfo>::CopyData(listInfo, scriptSectionList);
}
SCRIPT_EXPORT bool Script::Module::SectionListFromName(const char* name, ListOf(ModuleSectionInfo) listInfo)
{
return Module::SectionListFromAddr(Module::BaseFromName(name), listInfo);
}
SCRIPT_EXPORT bool Script::Module::GetMainModuleInfo(ModuleInfo* info)
{
return Module::InfoFromAddr(Module::GetMainModuleBase(), info);
}
SCRIPT_EXPORT duint Script::Module::GetMainModuleBase()
{
return dbggetdebuggedbase();
}
SCRIPT_EXPORT duint Script::Module::GetMainModuleSize()
{
return Module::SizeFromAddr(Module::GetMainModuleBase());
}
SCRIPT_EXPORT duint Script::Module::GetMainModuleEntry()
{
return Module::EntryFromAddr(Module::GetMainModuleBase());
}
SCRIPT_EXPORT int Script::Module::GetMainModuleSectionCount()
{
return Module::SectionCountFromAddr(Module::GetMainModuleBase());
}
SCRIPT_EXPORT bool Script::Module::GetMainModuleName(char* name)
{
return Module::NameFromAddr(Module::GetMainModuleBase(), name);
}
SCRIPT_EXPORT bool Script::Module::GetMainModulePath(char* path)
{
return Module::PathFromAddr(Module::GetMainModuleBase(), path);
}
SCRIPT_EXPORT bool Script::Module::GetMainModuleSectionList(ListOf(ModuleSectionInfo) listInfo)
{
return Module::SectionListFromAddr(Module::GetMainModuleBase(), listInfo);
}
SCRIPT_EXPORT bool Script::Module::GetList(ListOf(ModuleInfo) listInfo)
{
std::vector<MODINFO> modList;
ModGetList(modList);
std::vector<ModuleInfo> modScriptList;
modScriptList.reserve(modList.size());
for(const auto & mod : modList)
{
ModuleInfo scriptMod;
scriptMod.base = mod.base;
scriptMod.size = mod.size;
scriptMod.entry = mod.entry;
scriptMod.sectionCount = int(mod.sections.size());
strcpy_s(scriptMod.name, mod.name);
strcat_s(scriptMod.name, mod.extension);
strcpy_s(scriptMod.path, mod.path);
modScriptList.push_back(scriptMod);
}
return List<ModuleInfo>::CopyData(listInfo, modScriptList);
#include "_scriptapi_module.h"
#include "threading.h"
#include "module.h"
#include "debugger.h"
SCRIPT_EXPORT bool Script::Module::InfoFromAddr(duint addr, Script::Module::ModuleInfo* info)
{
SHARED_ACQUIRE(LockModules);
MODINFO* modInfo = ModInfoFromAddr(addr);
if(!info || !modInfo)
return false;
info->base = modInfo->base;
info->size = modInfo->size;
info->entry = modInfo->entry;
info->sectionCount = int(modInfo->sections.size());
strcpy_s(info->name, modInfo->name);
strcat_s(info->name, modInfo->extension);
strcpy_s(info->path, modInfo->path);
return true;
}
SCRIPT_EXPORT bool Script::Module::InfoFromName(const char* name, Script::Module::ModuleInfo* info)
{
return Module::InfoFromAddr(Module::BaseFromName(name), info);
}
SCRIPT_EXPORT duint Script::Module::BaseFromAddr(duint addr)
{
return ModBaseFromAddr(addr);
}
SCRIPT_EXPORT duint Script::Module::BaseFromName(const char* name)
{
return ModBaseFromName(name);
}
SCRIPT_EXPORT duint Script::Module::SizeFromAddr(duint addr)
{
return ModSizeFromAddr(addr);
}
SCRIPT_EXPORT duint Script::Module::SizeFromName(const char* name)
{
return Module::SizeFromAddr(Module::BaseFromName(name));
}
SCRIPT_EXPORT bool Script::Module::NameFromAddr(duint addr, char* name)
{
return ModNameFromAddr(addr, name, true);
}
SCRIPT_EXPORT bool Script::Module::PathFromAddr(duint addr, char* path)
{
return !!ModPathFromAddr(addr, path, MAX_PATH);
}
SCRIPT_EXPORT bool Script::Module::PathFromName(const char* name, char* path)
{
return Module::PathFromAddr(Module::BaseFromName(name), path);
}
SCRIPT_EXPORT duint Script::Module::EntryFromAddr(duint addr)
{
return ModEntryFromAddr(addr);
}
SCRIPT_EXPORT duint Script::Module::EntryFromName(const char* name)
{
return Module::EntryFromAddr(Module::BaseFromName(name));
}
SCRIPT_EXPORT int Script::Module::SectionCountFromAddr(duint addr)
{
SHARED_ACQUIRE(LockModules);
MODINFO* modInfo = ModInfoFromAddr(addr);
return modInfo ? int(modInfo->sections.size()) : 0;
}
SCRIPT_EXPORT int Script::Module::SectionCountFromName(const char* name)
{
return Module::SectionCountFromAddr(Module::BaseFromName(name));
}
SCRIPT_EXPORT bool Script::Module::SectionFromAddr(duint addr, int number, ModuleSectionInfo* section)
{
SHARED_ACQUIRE(LockModules);
MODINFO* modInfo = ModInfoFromAddr(addr);
if(!section || !modInfo || number < 0 || number >= int(modInfo->sections.size()))
return false;
const MODSECTIONINFO & secInfo = modInfo->sections.at(number);
section->addr = secInfo.addr;
section->size = secInfo.size;
strcpy_s(section->name, secInfo.name);
return true;
}
SCRIPT_EXPORT bool Script::Module::SectionFromName(const char* name, int number, ModuleSectionInfo* section)
{
return Module::SectionFromAddr(Module::BaseFromName(name), number, section);
}
SCRIPT_EXPORT bool Script::Module::SectionListFromAddr(duint addr, ListOf(ModuleSectionInfo) listInfo)
{
SHARED_ACQUIRE(LockModules);
MODINFO* modInfo = ModInfoFromAddr(addr);
if(!modInfo)
return false;
std::vector<ModuleSectionInfo> scriptSectionList;
scriptSectionList.reserve(modInfo->sections.size());
for(const auto & section : modInfo->sections)
{
ModuleSectionInfo scriptSection;
scriptSection.addr = section.addr;
scriptSection.size = section.size;
strcpy_s(scriptSection.name, section.name);
scriptSectionList.push_back(scriptSection);
}
return List<ModuleSectionInfo>::CopyData(listInfo, scriptSectionList);
}
SCRIPT_EXPORT bool Script::Module::SectionListFromName(const char* name, ListOf(ModuleSectionInfo) listInfo)
{
return Module::SectionListFromAddr(Module::BaseFromName(name), listInfo);
}
SCRIPT_EXPORT bool Script::Module::GetMainModuleInfo(ModuleInfo* info)
{
return Module::InfoFromAddr(Module::GetMainModuleBase(), info);
}
SCRIPT_EXPORT duint Script::Module::GetMainModuleBase()
{
return dbggetdebuggedbase();
}
SCRIPT_EXPORT duint Script::Module::GetMainModuleSize()
{
return Module::SizeFromAddr(Module::GetMainModuleBase());
}
SCRIPT_EXPORT duint Script::Module::GetMainModuleEntry()
{
return Module::EntryFromAddr(Module::GetMainModuleBase());
}
SCRIPT_EXPORT int Script::Module::GetMainModuleSectionCount()
{
return Module::SectionCountFromAddr(Module::GetMainModuleBase());
}
SCRIPT_EXPORT bool Script::Module::GetMainModuleName(char* name)
{
return Module::NameFromAddr(Module::GetMainModuleBase(), name);
}
SCRIPT_EXPORT bool Script::Module::GetMainModulePath(char* path)
{
return Module::PathFromAddr(Module::GetMainModuleBase(), path);
}
SCRIPT_EXPORT bool Script::Module::GetMainModuleSectionList(ListOf(ModuleSectionInfo) listInfo)
{
return Module::SectionListFromAddr(Module::GetMainModuleBase(), listInfo);
}
SCRIPT_EXPORT bool Script::Module::GetList(ListOf(ModuleInfo) listInfo)
{
std::vector<MODINFO> modList;
ModGetList(modList);
std::vector<ModuleInfo> modScriptList;
modScriptList.reserve(modList.size());
for(const auto & mod : modList)
{
ModuleInfo scriptMod;
scriptMod.base = mod.base;
scriptMod.size = mod.size;
scriptMod.entry = mod.entry;
scriptMod.sectionCount = int(mod.sections.size());
strcpy_s(scriptMod.name, mod.name);
strcat_s(scriptMod.name, mod.extension);
strcpy_s(scriptMod.path, mod.path);
modScriptList.push_back(scriptMod);
}
return List<ModuleInfo>::CopyData(listInfo, modScriptList);
}

View File

@ -1,56 +1,56 @@
#ifndef _SCRIPTAPI_MODULE_H
#define _SCRIPTAPI_MODULE_H
#include "_scriptapi.h"
namespace Script
{
namespace Module
{
struct ModuleInfo
{
duint base;
duint size;
duint entry;
int sectionCount;
char name[MAX_MODULE_SIZE];
char path[MAX_PATH];
};
struct ModuleSectionInfo
{
duint addr;
duint size;
char name[MAX_SECTION_SIZE * 5];
};
SCRIPT_EXPORT bool InfoFromAddr(duint addr, ModuleInfo* info);
SCRIPT_EXPORT bool InfoFromName(const char* name, ModuleInfo* info);
SCRIPT_EXPORT duint BaseFromAddr(duint addr);
SCRIPT_EXPORT duint BaseFromName(const char* name);
SCRIPT_EXPORT duint SizeFromAddr(duint addr);
SCRIPT_EXPORT duint SizeFromName(const char* name);
SCRIPT_EXPORT bool NameFromAddr(duint addr, char* name); //name[MAX_MODULE_SIZE]
SCRIPT_EXPORT bool PathFromAddr(duint addr, char* path); //path[MAX_MODULE_PATH_SIZE]
SCRIPT_EXPORT bool PathFromName(const char* name, char* path); //path[MAX_PATH]
SCRIPT_EXPORT duint EntryFromAddr(duint addr);
SCRIPT_EXPORT duint EntryFromName(const char* name);
SCRIPT_EXPORT int SectionCountFromAddr(duint addr);
SCRIPT_EXPORT int SectionCountFromName(const char* name);
SCRIPT_EXPORT bool SectionFromAddr(duint addr, int number, ModuleSectionInfo* section);
SCRIPT_EXPORT bool SectionFromName(const char* name, int number, ModuleSectionInfo* section);
SCRIPT_EXPORT bool SectionListFromAddr(duint addr, ListOf(ModuleSectionInfo) listInfo);
SCRIPT_EXPORT bool SectionListFromName(const char* name, ListOf(ModuleSectionInfo) listInfo);
SCRIPT_EXPORT bool GetMainModuleInfo(ModuleInfo* info);
SCRIPT_EXPORT duint GetMainModuleBase();
SCRIPT_EXPORT duint GetMainModuleSize();
SCRIPT_EXPORT duint GetMainModuleEntry();
SCRIPT_EXPORT int GetMainModuleSectionCount();
SCRIPT_EXPORT bool GetMainModuleName(char* name); //name[MAX_MODULE_SIZE]
SCRIPT_EXPORT bool GetMainModulePath(char* path); //path[MAX_PATH]
SCRIPT_EXPORT bool GetMainModuleSectionList(ListOf(ModuleSectionInfo) listInfo); //caller has the responsibility to free the list
SCRIPT_EXPORT bool GetList(ListOf(ModuleInfo) listInfo); //caller has the responsibility to free the list
}; //Module
}; //Script
#ifndef _SCRIPTAPI_MODULE_H
#define _SCRIPTAPI_MODULE_H
#include "_scriptapi.h"
namespace Script
{
namespace Module
{
struct ModuleInfo
{
duint base;
duint size;
duint entry;
int sectionCount;
char name[MAX_MODULE_SIZE];
char path[MAX_PATH];
};
struct ModuleSectionInfo
{
duint addr;
duint size;
char name[MAX_SECTION_SIZE * 5];
};
SCRIPT_EXPORT bool InfoFromAddr(duint addr, ModuleInfo* info);
SCRIPT_EXPORT bool InfoFromName(const char* name, ModuleInfo* info);
SCRIPT_EXPORT duint BaseFromAddr(duint addr);
SCRIPT_EXPORT duint BaseFromName(const char* name);
SCRIPT_EXPORT duint SizeFromAddr(duint addr);
SCRIPT_EXPORT duint SizeFromName(const char* name);
SCRIPT_EXPORT bool NameFromAddr(duint addr, char* name); //name[MAX_MODULE_SIZE]
SCRIPT_EXPORT bool PathFromAddr(duint addr, char* path); //path[MAX_MODULE_PATH_SIZE]
SCRIPT_EXPORT bool PathFromName(const char* name, char* path); //path[MAX_PATH]
SCRIPT_EXPORT duint EntryFromAddr(duint addr);
SCRIPT_EXPORT duint EntryFromName(const char* name);
SCRIPT_EXPORT int SectionCountFromAddr(duint addr);
SCRIPT_EXPORT int SectionCountFromName(const char* name);
SCRIPT_EXPORT bool SectionFromAddr(duint addr, int number, ModuleSectionInfo* section);
SCRIPT_EXPORT bool SectionFromName(const char* name, int number, ModuleSectionInfo* section);
SCRIPT_EXPORT bool SectionListFromAddr(duint addr, ListOf(ModuleSectionInfo) listInfo);
SCRIPT_EXPORT bool SectionListFromName(const char* name, ListOf(ModuleSectionInfo) listInfo);
SCRIPT_EXPORT bool GetMainModuleInfo(ModuleInfo* info);
SCRIPT_EXPORT duint GetMainModuleBase();
SCRIPT_EXPORT duint GetMainModuleSize();
SCRIPT_EXPORT duint GetMainModuleEntry();
SCRIPT_EXPORT int GetMainModuleSectionCount();
SCRIPT_EXPORT bool GetMainModuleName(char* name); //name[MAX_MODULE_SIZE]
SCRIPT_EXPORT bool GetMainModulePath(char* path); //path[MAX_PATH]
SCRIPT_EXPORT bool GetMainModuleSectionList(ListOf(ModuleSectionInfo) listInfo); //caller has the responsibility to free the list
SCRIPT_EXPORT bool GetList(ListOf(ModuleInfo) listInfo); //caller has the responsibility to free the list
}; //Module
}; //Script
#endif //_SCRIPTAPI_MODULE_H

View File

@ -1,48 +1,48 @@
#include "_scriptapi_pattern.h"
#include "patternfind.h"
#include "memory.h"
SCRIPT_EXPORT duint Script::Pattern::Find(unsigned char* data, duint datasize, const char* pattern)
{
return patternfind(data, datasize, pattern);
}
SCRIPT_EXPORT duint Script::Pattern::FindMem(duint start, duint size, const char* pattern)
{
Memory<unsigned char*> data(size, "Script::Pattern::FindMem::data");
if(!MemRead(start, data(), size))
return -1;
return Pattern::Find(data(), data.size(), pattern) + start;
}
SCRIPT_EXPORT void Script::Pattern::Write(unsigned char* data, duint datasize, const char* pattern)
{
patternwrite(data, datasize, pattern);
}
SCRIPT_EXPORT void Script::Pattern::WriteMem(duint start, duint size, const char* pattern)
{
Memory<unsigned char*> data(size, "Script::Pattern::WriteMem::data");
if(!MemRead(start, data(), data.size()))
return;
patternwrite(data(), data.size(), pattern);
MemWrite(start, data(), data.size());
}
SCRIPT_EXPORT bool Script::Pattern::SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern)
{
return patternsnr(data, datasize, searchpattern, replacepattern);
}
SCRIPT_EXPORT bool Script::Pattern::SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern)
{
Memory<unsigned char*> data(size, "Script::Pattern::SearchAndReplaceMem::data");
if(!MemRead(start, data(), size))
return false;
duint found = patternfind(data(), data.size(), searchpattern);
if(found == -1)
return false;
patternwrite(data() + found, data.size() - found, replacepattern);
MemWrite((start + found), data() + found, data.size() - found);
return true;
#include "_scriptapi_pattern.h"
#include "patternfind.h"
#include "memory.h"
SCRIPT_EXPORT duint Script::Pattern::Find(unsigned char* data, duint datasize, const char* pattern)
{
return patternfind(data, datasize, pattern);
}
SCRIPT_EXPORT duint Script::Pattern::FindMem(duint start, duint size, const char* pattern)
{
Memory<unsigned char*> data(size, "Script::Pattern::FindMem::data");
if(!MemRead(start, data(), size))
return -1;
return Pattern::Find(data(), data.size(), pattern) + start;
}
SCRIPT_EXPORT void Script::Pattern::Write(unsigned char* data, duint datasize, const char* pattern)
{
patternwrite(data, datasize, pattern);
}
SCRIPT_EXPORT void Script::Pattern::WriteMem(duint start, duint size, const char* pattern)
{
Memory<unsigned char*> data(size, "Script::Pattern::WriteMem::data");
if(!MemRead(start, data(), data.size()))
return;
patternwrite(data(), data.size(), pattern);
MemWrite(start, data(), data.size());
}
SCRIPT_EXPORT bool Script::Pattern::SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern)
{
return patternsnr(data, datasize, searchpattern, replacepattern);
}
SCRIPT_EXPORT bool Script::Pattern::SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern)
{
Memory<unsigned char*> data(size, "Script::Pattern::SearchAndReplaceMem::data");
if(!MemRead(start, data(), size))
return false;
duint found = patternfind(data(), data.size(), searchpattern);
if(found == -1)
return false;
patternwrite(data() + found, data.size() - found, replacepattern);
MemWrite((start + found), data() + found, data.size() - found);
return true;
}

View File

@ -1,19 +1,19 @@
#ifndef _SCRIPTAPI_PATTERN_H
#define _SCRIPTAPI_PATTERN_H
#include "_scriptapi.h"
namespace Script
{
namespace Pattern
{
SCRIPT_EXPORT duint Find(unsigned char* data, duint datasize, const char* pattern);
SCRIPT_EXPORT duint FindMem(duint start, duint size, const char* pattern);
SCRIPT_EXPORT void Write(unsigned char* data, duint datasize, const char* pattern);
SCRIPT_EXPORT void WriteMem(duint start, duint size, const char* pattern);
SCRIPT_EXPORT bool SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern);
SCRIPT_EXPORT bool SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern);
};
};
#ifndef _SCRIPTAPI_PATTERN_H
#define _SCRIPTAPI_PATTERN_H
#include "_scriptapi.h"
namespace Script
{
namespace Pattern
{
SCRIPT_EXPORT duint Find(unsigned char* data, duint datasize, const char* pattern);
SCRIPT_EXPORT duint FindMem(duint start, duint size, const char* pattern);
SCRIPT_EXPORT void Write(unsigned char* data, duint datasize, const char* pattern);
SCRIPT_EXPORT void WriteMem(duint start, duint size, const char* pattern);
SCRIPT_EXPORT bool SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern);
SCRIPT_EXPORT bool SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern);
};
};
#endif //_SCRIPTAPI_FIND_H

File diff suppressed because it is too large Load Diff

View File

@ -1,265 +1,265 @@
#ifndef _SCRIPTAPI_REGISTER_H
#define _SCRIPTAPI_REGISTER_H
#include "_scriptapi.h"
namespace Script
{
namespace Register
{
enum RegisterEnum
{
DR0,
DR1,
DR2,
DR3,
DR6,
DR7,
EAX,
AX,
AH,
AL,
EBX,
BX,
BH,
BL,
ECX,
CX,
CH,
CL,
EDX,
DX,
DH,
DL,
EDI,
DI,
ESI,
SI,
EBP,
BP,
ESP,
SP,
EIP,
#ifdef _WIN64
RAX,
RBX,
RCX,
RDX,
RSI,
SIL,
RDI,
DIL,
RBP,
BPL,
RSP,
SPL,
RIP,
R8,
R8D,
R8W,
R8B,
R9,
R9D,
R9W,
R9B,
R10,
R10D,
R10W,
R10B,
R11,
R11D,
R11W,
R11B,
R12,
R12D,
R12W,
R12B,
R13,
R13D,
R13W,
R13B,
R14,
R14D,
R14W,
R14B,
R15,
R15D,
R15W,
R15B,
#endif //_WIN64
CIP,
CSP,
}; //RegisterEnum
SCRIPT_EXPORT duint Get(RegisterEnum reg);
SCRIPT_EXPORT bool Set(RegisterEnum reg, duint value);
SCRIPT_EXPORT int Size(); //gets architecture register size in bytes
SCRIPT_EXPORT duint GetDR0();
SCRIPT_EXPORT bool SetDR0(duint value);
SCRIPT_EXPORT duint GetDR1();
SCRIPT_EXPORT bool SetDR1(duint value);
SCRIPT_EXPORT duint GetDR2();
SCRIPT_EXPORT bool SetDR2(duint value);
SCRIPT_EXPORT duint GetDR3();
SCRIPT_EXPORT bool SetDR3(duint value);
SCRIPT_EXPORT duint GetDR6();
SCRIPT_EXPORT bool SetDR6(duint value);
SCRIPT_EXPORT duint GetDR7();
SCRIPT_EXPORT bool SetDR7(duint value);
SCRIPT_EXPORT unsigned int GetEAX();
SCRIPT_EXPORT bool SetEAX(unsigned int value);
SCRIPT_EXPORT unsigned short GetAX();
SCRIPT_EXPORT bool SetAX(unsigned short value);
SCRIPT_EXPORT unsigned char GetAH();
SCRIPT_EXPORT bool SetAH(unsigned char value);
SCRIPT_EXPORT unsigned char GetAL();
SCRIPT_EXPORT bool SetAL(unsigned char value);
SCRIPT_EXPORT unsigned int GetEBX();
SCRIPT_EXPORT bool SetEBX(unsigned int value);
SCRIPT_EXPORT unsigned short GetBX();
SCRIPT_EXPORT bool SetBX(unsigned short value);
SCRIPT_EXPORT unsigned char GetBH();
SCRIPT_EXPORT bool SetBH(unsigned char value);
SCRIPT_EXPORT unsigned char GetBL();
SCRIPT_EXPORT bool SetBL(unsigned char value);
SCRIPT_EXPORT unsigned int GetECX();
SCRIPT_EXPORT bool SetECX(unsigned int value);
SCRIPT_EXPORT unsigned short GetCX();
SCRIPT_EXPORT bool SetCX(unsigned short value);
SCRIPT_EXPORT unsigned char GetCH();
SCRIPT_EXPORT bool SetCH(unsigned char value);
SCRIPT_EXPORT unsigned char GetCL();
SCRIPT_EXPORT bool SetCL(unsigned char value);
SCRIPT_EXPORT unsigned int GetEDX();
SCRIPT_EXPORT bool SetEDX(unsigned int value);
SCRIPT_EXPORT unsigned short GetDX();
SCRIPT_EXPORT bool SetDX(unsigned short value);
SCRIPT_EXPORT unsigned char GetDH();
SCRIPT_EXPORT bool SetDH(unsigned char value);
SCRIPT_EXPORT unsigned char GetDL();
SCRIPT_EXPORT bool SetDL(unsigned char value);
SCRIPT_EXPORT unsigned int GetEDI();
SCRIPT_EXPORT bool SetEDI(unsigned int value);
SCRIPT_EXPORT unsigned short GetDI();
SCRIPT_EXPORT bool SetDI(unsigned short value);
SCRIPT_EXPORT unsigned int GetESI();
SCRIPT_EXPORT bool SetESI(unsigned int value);
SCRIPT_EXPORT unsigned short GetSI();
SCRIPT_EXPORT bool SetSI(unsigned short value);
SCRIPT_EXPORT unsigned int GetEBP();
SCRIPT_EXPORT bool SetEBP(unsigned int value);
SCRIPT_EXPORT unsigned short GetBP();
SCRIPT_EXPORT bool SetBP(unsigned short value);
SCRIPT_EXPORT unsigned int GetESP();
SCRIPT_EXPORT bool SetESP(unsigned int value);
SCRIPT_EXPORT unsigned short GetSP();
SCRIPT_EXPORT bool SetSP(unsigned short value);
SCRIPT_EXPORT unsigned int GetEIP();
SCRIPT_EXPORT bool SetEIP(unsigned int value);
#ifdef _WIN64
SCRIPT_EXPORT unsigned long long GetRAX();
SCRIPT_EXPORT bool SetRAX(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetRBX();
SCRIPT_EXPORT bool SetRBX(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetRCX();
SCRIPT_EXPORT bool SetRCX(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetRDX();
SCRIPT_EXPORT bool SetRDX(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetRSI();
SCRIPT_EXPORT bool SetRSI(unsigned long long value);
SCRIPT_EXPORT unsigned char GetSIL();
SCRIPT_EXPORT bool SetSIL(unsigned char value);
SCRIPT_EXPORT unsigned long long GetRDI();
SCRIPT_EXPORT bool SetRDI(unsigned long long value);
SCRIPT_EXPORT unsigned char GetDIL();
SCRIPT_EXPORT bool SetDIL(unsigned char value);
SCRIPT_EXPORT unsigned long long GetRBP();
SCRIPT_EXPORT bool SetRBP(unsigned long long value);
SCRIPT_EXPORT unsigned char GetBPL();
SCRIPT_EXPORT bool SetBPL(unsigned char value);
SCRIPT_EXPORT unsigned long long GetRSP();
SCRIPT_EXPORT bool SetRSP(unsigned long long value);
SCRIPT_EXPORT unsigned char GetSPL();
SCRIPT_EXPORT bool SetSPL(unsigned char value);
SCRIPT_EXPORT unsigned long long GetRIP();
SCRIPT_EXPORT bool SetRIP(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetR8();
SCRIPT_EXPORT bool SetR8(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR8D();
SCRIPT_EXPORT bool SetR8D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR8W();
SCRIPT_EXPORT bool SetR8W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR8B();
SCRIPT_EXPORT bool SetR8B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR9();
SCRIPT_EXPORT bool SetR9(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR9D();
SCRIPT_EXPORT bool SetR9D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR9W();
SCRIPT_EXPORT bool SetR9W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR9B();
SCRIPT_EXPORT bool SetR9B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR10();
SCRIPT_EXPORT bool SetR10(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR10D();
SCRIPT_EXPORT bool SetR10D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR10W();
SCRIPT_EXPORT bool SetR10W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR10B();
SCRIPT_EXPORT bool SetR10B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR11();
SCRIPT_EXPORT bool SetR11(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR11D();
SCRIPT_EXPORT bool SetR11D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR11W();
SCRIPT_EXPORT bool SetR11W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR11B();
SCRIPT_EXPORT bool SetR11B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR12();
SCRIPT_EXPORT bool SetR12(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR12D();
SCRIPT_EXPORT bool SetR12D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR12W();
SCRIPT_EXPORT bool SetR12W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR12B();
SCRIPT_EXPORT bool SetR12B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR13();
SCRIPT_EXPORT bool SetR13(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR13D();
SCRIPT_EXPORT bool SetR13D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR13W();
SCRIPT_EXPORT bool SetR13W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR13B();
SCRIPT_EXPORT bool SetR13B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR14();
SCRIPT_EXPORT bool SetR14(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR14D();
SCRIPT_EXPORT bool SetR14D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR14W();
SCRIPT_EXPORT bool SetR14W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR14B();
SCRIPT_EXPORT bool SetR14B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR15();
SCRIPT_EXPORT bool SetR15(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR15D();
SCRIPT_EXPORT bool SetR15D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR15W();
SCRIPT_EXPORT bool SetR15W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR15B();
SCRIPT_EXPORT bool SetR15B(unsigned char value);
#endif //_WIN64
SCRIPT_EXPORT duint GetCIP();
SCRIPT_EXPORT bool SetCIP(duint value);
SCRIPT_EXPORT duint GetCSP();
SCRIPT_EXPORT bool SetCSP(duint value);
}; //Register
}; //Script
#ifndef _SCRIPTAPI_REGISTER_H
#define _SCRIPTAPI_REGISTER_H
#include "_scriptapi.h"
namespace Script
{
namespace Register
{
enum RegisterEnum
{
DR0,
DR1,
DR2,
DR3,
DR6,
DR7,
EAX,
AX,
AH,
AL,
EBX,
BX,
BH,
BL,
ECX,
CX,
CH,
CL,
EDX,
DX,
DH,
DL,
EDI,
DI,
ESI,
SI,
EBP,
BP,
ESP,
SP,
EIP,
#ifdef _WIN64
RAX,
RBX,
RCX,
RDX,
RSI,
SIL,
RDI,
DIL,
RBP,
BPL,
RSP,
SPL,
RIP,
R8,
R8D,
R8W,
R8B,
R9,
R9D,
R9W,
R9B,
R10,
R10D,
R10W,
R10B,
R11,
R11D,
R11W,
R11B,
R12,
R12D,
R12W,
R12B,
R13,
R13D,
R13W,
R13B,
R14,
R14D,
R14W,
R14B,
R15,
R15D,
R15W,
R15B,
#endif //_WIN64
CIP,
CSP,
}; //RegisterEnum
SCRIPT_EXPORT duint Get(RegisterEnum reg);
SCRIPT_EXPORT bool Set(RegisterEnum reg, duint value);
SCRIPT_EXPORT int Size(); //gets architecture register size in bytes
SCRIPT_EXPORT duint GetDR0();
SCRIPT_EXPORT bool SetDR0(duint value);
SCRIPT_EXPORT duint GetDR1();
SCRIPT_EXPORT bool SetDR1(duint value);
SCRIPT_EXPORT duint GetDR2();
SCRIPT_EXPORT bool SetDR2(duint value);
SCRIPT_EXPORT duint GetDR3();
SCRIPT_EXPORT bool SetDR3(duint value);
SCRIPT_EXPORT duint GetDR6();
SCRIPT_EXPORT bool SetDR6(duint value);
SCRIPT_EXPORT duint GetDR7();
SCRIPT_EXPORT bool SetDR7(duint value);
SCRIPT_EXPORT unsigned int GetEAX();
SCRIPT_EXPORT bool SetEAX(unsigned int value);
SCRIPT_EXPORT unsigned short GetAX();
SCRIPT_EXPORT bool SetAX(unsigned short value);
SCRIPT_EXPORT unsigned char GetAH();
SCRIPT_EXPORT bool SetAH(unsigned char value);
SCRIPT_EXPORT unsigned char GetAL();
SCRIPT_EXPORT bool SetAL(unsigned char value);
SCRIPT_EXPORT unsigned int GetEBX();
SCRIPT_EXPORT bool SetEBX(unsigned int value);
SCRIPT_EXPORT unsigned short GetBX();
SCRIPT_EXPORT bool SetBX(unsigned short value);
SCRIPT_EXPORT unsigned char GetBH();
SCRIPT_EXPORT bool SetBH(unsigned char value);
SCRIPT_EXPORT unsigned char GetBL();
SCRIPT_EXPORT bool SetBL(unsigned char value);
SCRIPT_EXPORT unsigned int GetECX();
SCRIPT_EXPORT bool SetECX(unsigned int value);
SCRIPT_EXPORT unsigned short GetCX();
SCRIPT_EXPORT bool SetCX(unsigned short value);
SCRIPT_EXPORT unsigned char GetCH();
SCRIPT_EXPORT bool SetCH(unsigned char value);
SCRIPT_EXPORT unsigned char GetCL();
SCRIPT_EXPORT bool SetCL(unsigned char value);
SCRIPT_EXPORT unsigned int GetEDX();
SCRIPT_EXPORT bool SetEDX(unsigned int value);
SCRIPT_EXPORT unsigned short GetDX();
SCRIPT_EXPORT bool SetDX(unsigned short value);
SCRIPT_EXPORT unsigned char GetDH();
SCRIPT_EXPORT bool SetDH(unsigned char value);
SCRIPT_EXPORT unsigned char GetDL();
SCRIPT_EXPORT bool SetDL(unsigned char value);
SCRIPT_EXPORT unsigned int GetEDI();
SCRIPT_EXPORT bool SetEDI(unsigned int value);
SCRIPT_EXPORT unsigned short GetDI();
SCRIPT_EXPORT bool SetDI(unsigned short value);
SCRIPT_EXPORT unsigned int GetESI();
SCRIPT_EXPORT bool SetESI(unsigned int value);
SCRIPT_EXPORT unsigned short GetSI();
SCRIPT_EXPORT bool SetSI(unsigned short value);
SCRIPT_EXPORT unsigned int GetEBP();
SCRIPT_EXPORT bool SetEBP(unsigned int value);
SCRIPT_EXPORT unsigned short GetBP();
SCRIPT_EXPORT bool SetBP(unsigned short value);
SCRIPT_EXPORT unsigned int GetESP();
SCRIPT_EXPORT bool SetESP(unsigned int value);
SCRIPT_EXPORT unsigned short GetSP();
SCRIPT_EXPORT bool SetSP(unsigned short value);
SCRIPT_EXPORT unsigned int GetEIP();
SCRIPT_EXPORT bool SetEIP(unsigned int value);
#ifdef _WIN64
SCRIPT_EXPORT unsigned long long GetRAX();
SCRIPT_EXPORT bool SetRAX(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetRBX();
SCRIPT_EXPORT bool SetRBX(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetRCX();
SCRIPT_EXPORT bool SetRCX(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetRDX();
SCRIPT_EXPORT bool SetRDX(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetRSI();
SCRIPT_EXPORT bool SetRSI(unsigned long long value);
SCRIPT_EXPORT unsigned char GetSIL();
SCRIPT_EXPORT bool SetSIL(unsigned char value);
SCRIPT_EXPORT unsigned long long GetRDI();
SCRIPT_EXPORT bool SetRDI(unsigned long long value);
SCRIPT_EXPORT unsigned char GetDIL();
SCRIPT_EXPORT bool SetDIL(unsigned char value);
SCRIPT_EXPORT unsigned long long GetRBP();
SCRIPT_EXPORT bool SetRBP(unsigned long long value);
SCRIPT_EXPORT unsigned char GetBPL();
SCRIPT_EXPORT bool SetBPL(unsigned char value);
SCRIPT_EXPORT unsigned long long GetRSP();
SCRIPT_EXPORT bool SetRSP(unsigned long long value);
SCRIPT_EXPORT unsigned char GetSPL();
SCRIPT_EXPORT bool SetSPL(unsigned char value);
SCRIPT_EXPORT unsigned long long GetRIP();
SCRIPT_EXPORT bool SetRIP(unsigned long long value);
SCRIPT_EXPORT unsigned long long GetR8();
SCRIPT_EXPORT bool SetR8(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR8D();
SCRIPT_EXPORT bool SetR8D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR8W();
SCRIPT_EXPORT bool SetR8W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR8B();
SCRIPT_EXPORT bool SetR8B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR9();
SCRIPT_EXPORT bool SetR9(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR9D();
SCRIPT_EXPORT bool SetR9D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR9W();
SCRIPT_EXPORT bool SetR9W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR9B();
SCRIPT_EXPORT bool SetR9B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR10();
SCRIPT_EXPORT bool SetR10(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR10D();
SCRIPT_EXPORT bool SetR10D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR10W();
SCRIPT_EXPORT bool SetR10W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR10B();
SCRIPT_EXPORT bool SetR10B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR11();
SCRIPT_EXPORT bool SetR11(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR11D();
SCRIPT_EXPORT bool SetR11D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR11W();
SCRIPT_EXPORT bool SetR11W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR11B();
SCRIPT_EXPORT bool SetR11B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR12();
SCRIPT_EXPORT bool SetR12(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR12D();
SCRIPT_EXPORT bool SetR12D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR12W();
SCRIPT_EXPORT bool SetR12W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR12B();
SCRIPT_EXPORT bool SetR12B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR13();
SCRIPT_EXPORT bool SetR13(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR13D();
SCRIPT_EXPORT bool SetR13D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR13W();
SCRIPT_EXPORT bool SetR13W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR13B();
SCRIPT_EXPORT bool SetR13B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR14();
SCRIPT_EXPORT bool SetR14(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR14D();
SCRIPT_EXPORT bool SetR14D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR14W();
SCRIPT_EXPORT bool SetR14W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR14B();
SCRIPT_EXPORT bool SetR14B(unsigned char value);
SCRIPT_EXPORT unsigned long long GetR15();
SCRIPT_EXPORT bool SetR15(unsigned long long value);
SCRIPT_EXPORT unsigned int GetR15D();
SCRIPT_EXPORT bool SetR15D(unsigned int value);
SCRIPT_EXPORT unsigned short GetR15W();
SCRIPT_EXPORT bool SetR15W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR15B();
SCRIPT_EXPORT bool SetR15B(unsigned char value);
#endif //_WIN64
SCRIPT_EXPORT duint GetCIP();
SCRIPT_EXPORT bool SetCIP(duint value);
SCRIPT_EXPORT duint GetCSP();
SCRIPT_EXPORT bool SetCSP(duint value);
}; //Register
}; //Script
#endif //_SCRIPTAPI_REGISTER_H

View File

@ -1,24 +1,24 @@
#include "_scriptapi_stack.h"
#include "_scriptapi_memory.h"
#include "_scriptapi_register.h"
SCRIPT_EXPORT duint Script::Stack::Pop()
{
duint csp = Register::GetCSP();
duint top = Memory::ReadPtr(csp);
Register::SetCSP(csp + sizeof(duint));
return top;
}
SCRIPT_EXPORT duint Script::Stack::Push(duint value)
{
duint csp = Register::GetCSP();
Register::SetCSP(csp - sizeof(duint));
Memory::WritePtr(csp - sizeof(duint), value);
return Memory::ReadPtr(csp);
}
SCRIPT_EXPORT duint Script::Stack::Peek(int offset)
{
return Memory::ReadPtr(Register::GetCSP() + offset * sizeof(duint));
#include "_scriptapi_stack.h"
#include "_scriptapi_memory.h"
#include "_scriptapi_register.h"
SCRIPT_EXPORT duint Script::Stack::Pop()
{
duint csp = Register::GetCSP();
duint top = Memory::ReadPtr(csp);
Register::SetCSP(csp + sizeof(duint));
return top;
}
SCRIPT_EXPORT duint Script::Stack::Push(duint value)
{
duint csp = Register::GetCSP();
Register::SetCSP(csp - sizeof(duint));
Memory::WritePtr(csp - sizeof(duint), value);
return Memory::ReadPtr(csp);
}
SCRIPT_EXPORT duint Script::Stack::Peek(int offset)
{
return Memory::ReadPtr(Register::GetCSP() + offset * sizeof(duint));
}

View File

@ -1,16 +1,16 @@
#ifndef _SCRIPTAPI_STACK_H
#define _SCRIPTAPI_STACK_H
#include "_scriptapi.h"
namespace Script
{
namespace Stack
{
SCRIPT_EXPORT duint Pop();
SCRIPT_EXPORT duint Push(duint value); //returns the previous top, equal to Peek(1)
SCRIPT_EXPORT duint Peek(int offset = 0); //offset is in multiples of Register::Size(), for easy x32/x64 portability
}; //Stack
}; //Script
#ifndef _SCRIPTAPI_STACK_H
#define _SCRIPTAPI_STACK_H
#include "_scriptapi.h"
namespace Script
{
namespace Stack
{
SCRIPT_EXPORT duint Pop();
SCRIPT_EXPORT duint Push(duint value); //returns the previous top, equal to Peek(1)
SCRIPT_EXPORT duint Peek(int offset = 0); //offset is in multiples of Register::Size(), for easy x32/x64 portability
}; //Stack
}; //Script
#endif //_SCRIPTAPI_STACK_H

View File

@ -1,91 +1,91 @@
/**
@file addrinfo.cpp
@brief Implements the addrinfo class.
*/
#include "addrinfo.h"
#include "debugger.h"
#include "console.h"
#include "memory.h"
#include "breakpoint.h"
#include "lz4\lz4file.h"
#include "patches.h"
#include "module.h"
#include "comment.h"
#include "label.h"
#include "bookmark.h"
#include "function.h"
#include "loop.h"
///api functions
bool apienumexports(duint base, EXPORTENUMCALLBACK cbEnum)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQueryEx(fdProcessInfo->hProcess, (const void*)base, &mbi, sizeof(mbi));
duint size = mbi.RegionSize;
Memory<void*> buffer(size, "apienumexports:buffer");
if(!MemRead(base, buffer(), size))
return false;
IMAGE_NT_HEADERS* pnth = (IMAGE_NT_HEADERS*)((duint)buffer() + GetPE32DataFromMappedFile((ULONG_PTR)buffer(), 0, UE_PE_OFFSET));
duint export_dir_rva = pnth->OptionalHeader.DataDirectory[0].VirtualAddress;
duint export_dir_size = pnth->OptionalHeader.DataDirectory[0].Size;
IMAGE_EXPORT_DIRECTORY export_dir;
memset(&export_dir, 0, sizeof(export_dir));
MemRead((export_dir_rva + base), &export_dir, sizeof(export_dir));
unsigned int NumberOfNames = export_dir.NumberOfNames;
if(!export_dir.NumberOfFunctions || !NumberOfNames) //no named exports
return false;
char modname[MAX_MODULE_SIZE] = "";
ModNameFromAddr(base, modname, true);
duint original_name_va = export_dir.Name + base;
char original_name[deflen] = "";
memset(original_name, 0, sizeof(original_name));
MemRead(original_name_va, original_name, deflen);
char* AddrOfFunctions_va = (char*)(export_dir.AddressOfFunctions + base); //not a valid local pointer
char* AddrOfNames_va = (char*)(export_dir.AddressOfNames + base); //not a valid local pointer
char* AddrOfNameOrdinals_va = (char*)(export_dir.AddressOfNameOrdinals + base); //not a valid local pointer
for(DWORD i = 0; i < NumberOfNames; i++)
{
DWORD curAddrOfName = 0;
MemRead((duint)(AddrOfNames_va + sizeof(DWORD)*i), &curAddrOfName, sizeof(DWORD));
char* cur_name_va = (char*)(curAddrOfName + base);
char cur_name[deflen] = "";
memset(cur_name, 0, deflen);
MemRead((duint)cur_name_va, cur_name, deflen);
WORD curAddrOfNameOrdinals = 0;
MemRead((duint)(AddrOfNameOrdinals_va + sizeof(WORD)*i), &curAddrOfNameOrdinals, sizeof(WORD));
DWORD curFunctionRva = 0;
MemRead((duint)(AddrOfFunctions_va + sizeof(DWORD)*curAddrOfNameOrdinals), &curFunctionRva, sizeof(DWORD));
if(curFunctionRva >= export_dir_rva && curFunctionRva < export_dir_rva + export_dir_size)
{
char forwarded_api[deflen] = "";
memset(forwarded_api, 0, deflen);
MemRead((curFunctionRva + base), forwarded_api, deflen);
int len = (int)strlen(forwarded_api);
int j = 0;
while(forwarded_api[j] != '.' && j < len)
j++;
if(forwarded_api[j] == '.')
{
forwarded_api[j] = 0;
HINSTANCE hTempDll = LoadLibraryExA(forwarded_api, 0, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
if(hTempDll)
{
duint local_addr = (duint)GetProcAddress(hTempDll, forwarded_api + j + 1);
if(local_addr)
{
duint remote_addr = ImporterGetRemoteAPIAddress(fdProcessInfo->hProcess, local_addr);
cbEnum(base, modname, cur_name, remote_addr);
}
}
}
}
else
{
cbEnum(base, modname, cur_name, curFunctionRva + base);
}
}
return true;
/**
@file addrinfo.cpp
@brief Implements the addrinfo class.
*/
#include "addrinfo.h"
#include "debugger.h"
#include "console.h"
#include "memory.h"
#include "breakpoint.h"
#include "lz4\lz4file.h"
#include "patches.h"
#include "module.h"
#include "comment.h"
#include "label.h"
#include "bookmark.h"
#include "function.h"
#include "loop.h"
///api functions
bool apienumexports(duint base, EXPORTENUMCALLBACK cbEnum)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQueryEx(fdProcessInfo->hProcess, (const void*)base, &mbi, sizeof(mbi));
duint size = mbi.RegionSize;
Memory<void*> buffer(size, "apienumexports:buffer");
if(!MemRead(base, buffer(), size))
return false;
IMAGE_NT_HEADERS* pnth = (IMAGE_NT_HEADERS*)((duint)buffer() + GetPE32DataFromMappedFile((ULONG_PTR)buffer(), 0, UE_PE_OFFSET));
duint export_dir_rva = pnth->OptionalHeader.DataDirectory[0].VirtualAddress;
duint export_dir_size = pnth->OptionalHeader.DataDirectory[0].Size;
IMAGE_EXPORT_DIRECTORY export_dir;
memset(&export_dir, 0, sizeof(export_dir));
MemRead((export_dir_rva + base), &export_dir, sizeof(export_dir));
unsigned int NumberOfNames = export_dir.NumberOfNames;
if(!export_dir.NumberOfFunctions || !NumberOfNames) //no named exports
return false;
char modname[MAX_MODULE_SIZE] = "";
ModNameFromAddr(base, modname, true);
duint original_name_va = export_dir.Name + base;
char original_name[deflen] = "";
memset(original_name, 0, sizeof(original_name));
MemRead(original_name_va, original_name, deflen);
char* AddrOfFunctions_va = (char*)(export_dir.AddressOfFunctions + base); //not a valid local pointer
char* AddrOfNames_va = (char*)(export_dir.AddressOfNames + base); //not a valid local pointer
char* AddrOfNameOrdinals_va = (char*)(export_dir.AddressOfNameOrdinals + base); //not a valid local pointer
for(DWORD i = 0; i < NumberOfNames; i++)
{
DWORD curAddrOfName = 0;
MemRead((duint)(AddrOfNames_va + sizeof(DWORD)*i), &curAddrOfName, sizeof(DWORD));
char* cur_name_va = (char*)(curAddrOfName + base);
char cur_name[deflen] = "";
memset(cur_name, 0, deflen);
MemRead((duint)cur_name_va, cur_name, deflen);
WORD curAddrOfNameOrdinals = 0;
MemRead((duint)(AddrOfNameOrdinals_va + sizeof(WORD)*i), &curAddrOfNameOrdinals, sizeof(WORD));
DWORD curFunctionRva = 0;
MemRead((duint)(AddrOfFunctions_va + sizeof(DWORD)*curAddrOfNameOrdinals), &curFunctionRva, sizeof(DWORD));
if(curFunctionRva >= export_dir_rva && curFunctionRva < export_dir_rva + export_dir_size)
{
char forwarded_api[deflen] = "";
memset(forwarded_api, 0, deflen);
MemRead((curFunctionRva + base), forwarded_api, deflen);
int len = (int)strlen(forwarded_api);
int j = 0;
while(forwarded_api[j] != '.' && j < len)
j++;
if(forwarded_api[j] == '.')
{
forwarded_api[j] = 0;
HINSTANCE hTempDll = LoadLibraryExA(forwarded_api, 0, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
if(hTempDll)
{
duint local_addr = (duint)GetProcAddress(hTempDll, forwarded_api + j + 1);
if(local_addr)
{
duint remote_addr = ImporterGetRemoteAPIAddress(fdProcessInfo->hProcess, local_addr);
cbEnum(base, modname, cur_name, remote_addr);
}
}
}
}
else
{
cbEnum(base, modname, cur_name, curFunctionRva + base);
}
}
return true;
}

View File

@ -1,61 +1,61 @@
#ifndef _ADDRINFO_H
#define _ADDRINFO_H
#include "_global.h"
#include <functional>
//ranges
typedef std::pair<duint, duint> Range;
typedef std::pair<duint, Range> ModuleRange; //modhash + RVA range
typedef std::pair<int, ModuleRange> DepthModuleRange; //depth + modulerange
struct RangeCompare
{
bool operator()(const Range & a, const Range & b) //a before b?
{
return a.second < b.first;
}
};
struct OverlappingRangeCompare
{
bool operator()(const Range & a, const Range & b) //a before b?
{
return a.second < b.first || a.second < b.second;
}
};
struct ModuleRangeCompare
{
bool operator()(const ModuleRange & a, const ModuleRange & b)
{
if(a.first < b.first) //module hash is smaller
return true;
if(a.first != b.first) //module hashes are not equal
return false;
return a.second.second < b.second.first; //a.second is before b.second
}
};
struct DepthModuleRangeCompare
{
bool operator()(const DepthModuleRange & a, const DepthModuleRange & b)
{
if(a.first < b.first) //module depth is smaller
return true;
if(a.first != b.first) //module depths are not equal
return false;
if(a.second.first < b.second.first) //module hash is smaller
return true;
if(a.second.first != b.second.first) //module hashes are not equal
return false;
return a.second.second.second < b.second.second.first; //a.second.second is before b.second.second
}
};
//typedefs
typedef std::function<void (duint base, const char* mod, const char* name, duint addr)> EXPORTENUMCALLBACK;
bool apienumexports(duint base, EXPORTENUMCALLBACK cbEnum);
#endif // _ADDRINFO_H
#ifndef _ADDRINFO_H
#define _ADDRINFO_H
#include "_global.h"
#include <functional>
//ranges
typedef std::pair<duint, duint> Range;
typedef std::pair<duint, Range> ModuleRange; //modhash + RVA range
typedef std::pair<int, ModuleRange> DepthModuleRange; //depth + modulerange
struct RangeCompare
{
bool operator()(const Range & a, const Range & b) //a before b?
{
return a.second < b.first;
}
};
struct OverlappingRangeCompare
{
bool operator()(const Range & a, const Range & b) //a before b?
{
return a.second < b.first || a.second < b.second;
}
};
struct ModuleRangeCompare
{
bool operator()(const ModuleRange & a, const ModuleRange & b)
{
if(a.first < b.first) //module hash is smaller
return true;
if(a.first != b.first) //module hashes are not equal
return false;
return a.second.second < b.second.first; //a.second is before b.second
}
};
struct DepthModuleRangeCompare
{
bool operator()(const DepthModuleRange & a, const DepthModuleRange & b)
{
if(a.first < b.first) //module depth is smaller
return true;
if(a.first != b.first) //module depths are not equal
return false;
if(a.second.first < b.second.first) //module hash is smaller
return true;
if(a.second.first != b.second.first) //module hashes are not equal
return false;
return a.second.second.second < b.second.second.first; //a.second.second is before b.second.second
}
};
//typedefs
typedef std::function<void (duint base, const char* mod, const char* name, duint addr)> EXPORTENUMCALLBACK;
bool apienumexports(duint base, EXPORTENUMCALLBACK cbEnum);
#endif // _ADDRINFO_H

View File

@ -1,25 +1,25 @@
#include "analysis.h"
#include "memory.h"
Analysis::Analysis(duint base, duint size)
{
_base = base;
_size = size;
_data = new unsigned char[_size + MAX_DISASM_BUFFER];
MemRead(_base, _data, _size);
}
Analysis::~Analysis()
{
delete[] _data;
}
bool Analysis::IsValidAddress(duint addr)
{
return addr >= _base && addr < _base + _size;
}
const unsigned char* Analysis::TranslateAddress(duint addr)
{
return IsValidAddress(addr) ? _data + (addr - _base) : nullptr;
#include "analysis.h"
#include "memory.h"
Analysis::Analysis(duint base, duint size)
{
_base = base;
_size = size;
_data = new unsigned char[_size + MAX_DISASM_BUFFER];
MemRead(_base, _data, _size);
}
Analysis::~Analysis()
{
delete[] _data;
}
bool Analysis::IsValidAddress(duint addr)
{
return addr >= _base && addr < _base + _size;
}
const unsigned char* Analysis::TranslateAddress(duint addr)
{
return IsValidAddress(addr) ? _data + (addr - _base) : nullptr;
}

View File

@ -1,26 +1,26 @@
#ifndef _ANALYSIS_H
#define _ANALYSIS_H
#include "_global.h"
#include <capstone_wrapper.h>
class Analysis
{
public:
explicit Analysis(duint base, duint size);
Analysis(const Analysis & that) = delete;
virtual ~Analysis();
virtual void Analyse() = 0;
virtual void SetMarkers() = 0;
protected:
duint _base;
duint _size;
unsigned char* _data;
Capstone _cp;
bool IsValidAddress(duint addr);
const unsigned char* TranslateAddress(duint addr);
};
#ifndef _ANALYSIS_H
#define _ANALYSIS_H
#include "_global.h"
#include <capstone_wrapper.h>
class Analysis
{
public:
explicit Analysis(duint base, duint size);
Analysis(const Analysis & that) = delete;
virtual ~Analysis();
virtual void Analyse() = 0;
virtual void SetMarkers() = 0;
protected:
duint _base;
duint _size;
unsigned char* _data;
Capstone _cp;
bool IsValidAddress(duint addr);
const unsigned char* TranslateAddress(duint addr);
};
#endif //_ANALYSIS_H

View File

@ -1,23 +1,23 @@
#include "analysis_nukem.h"
#include "BasicBlock.h"
#include "LinearPass.h"
#include "FunctionPass.h"
#include "console.h"
void Analyse_nukem(duint base, duint size)
{
dputs("Starting analysis (Nukem)...");
DWORD ticks = GetTickCount();
duint end = base + size;
BBlockArray blocks;
LinearPass* pass1 = new LinearPass(base, end, blocks);
pass1->Analyse();
FunctionPass* pass2 = new FunctionPass(base, end, blocks);
pass2->Analyse();
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
#include "analysis_nukem.h"
#include "BasicBlock.h"
#include "LinearPass.h"
#include "FunctionPass.h"
#include "console.h"
void Analyse_nukem(duint base, duint size)
{
dputs("Starting analysis (Nukem)...");
DWORD ticks = GetTickCount();
duint end = base + size;
BBlockArray blocks;
LinearPass* pass1 = new LinearPass(base, end, blocks);
pass1->Analyse();
FunctionPass* pass2 = new FunctionPass(base, end, blocks);
pass2->Analyse();
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
}

View File

@ -1,5 +1,5 @@
#pragma once
#include "_global.h"
#pragma once
#include "_global.h"
void Analyse_nukem(duint base, duint size);

View File

@ -1,93 +1,93 @@
/**
@file assemble.cpp
@brief Implements the assemble class.
*/
#include "assemble.h"
#include "memory.h"
#include "XEDParse\XEDParse.h"
#include "value.h"
#include "disasm_helper.h"
static bool cbUnknown(const char* text, ULONGLONG* value)
{
if(!text || !value)
return false;
duint val;
if(!valfromstring(text, &val))
return false;
*value = val;
return true;
}
bool assemble(duint addr, unsigned char* dest, int* size, const char* instruction, char* error)
{
if(strlen(instruction) >= XEDPARSE_MAXBUFSIZE)
return false;
XEDPARSE parse;
memset(&parse, 0, sizeof(parse));
#ifdef _WIN64
parse.x64 = true;
#else //x86
parse.x64 = false;
#endif
parse.cbUnknown = cbUnknown;
parse.cip = addr;
strcpy_s(parse.instr, instruction);
if(XEDParseAssemble(&parse) == XEDPARSE_ERROR)
{
if(error)
strcpy_s(error, MAX_ERROR_SIZE, parse.error);
return false;
}
if(dest)
memcpy(dest, parse.dest, parse.dest_size);
if(size)
*size = parse.dest_size;
return true;
}
bool assembleat(duint addr, const char* instruction, int* size, char* error, bool fillnop)
{
int destSize;
unsigned char dest[16];
if(!assemble(addr, dest, &destSize, instruction, error))
return false;
//calculate the number of NOPs to insert
int origLen = disasmgetsize(addr);
while(origLen < destSize)
origLen += disasmgetsize(addr + origLen);
int nopsize = origLen - destSize;
unsigned char nops[16];
memset(nops, 0x90, sizeof(nops));
if(size)
*size = destSize;
bool ret = MemPatch(addr, dest, destSize);
if (ret)
{
if (fillnop && nopsize)
{
if (size)
*size += nopsize;
// Ignored if the memory patch for NOPs fail (although it should not)
MemPatch(addr + destSize, nops, nopsize);
}
// Update GUI if any patching succeeded
GuiUpdatePatches();
}
else
{
// Tell the user writing is blocked
strcpy_s(error, MAX_ERROR_SIZE, "Error while writing process memory");
}
return ret;
}
/**
@file assemble.cpp
@brief Implements the assemble class.
*/
#include "assemble.h"
#include "memory.h"
#include "XEDParse\XEDParse.h"
#include "value.h"
#include "disasm_helper.h"
static bool cbUnknown(const char* text, ULONGLONG* value)
{
if(!text || !value)
return false;
duint val;
if(!valfromstring(text, &val))
return false;
*value = val;
return true;
}
bool assemble(duint addr, unsigned char* dest, int* size, const char* instruction, char* error)
{
if(strlen(instruction) >= XEDPARSE_MAXBUFSIZE)
return false;
XEDPARSE parse;
memset(&parse, 0, sizeof(parse));
#ifdef _WIN64
parse.x64 = true;
#else //x86
parse.x64 = false;
#endif
parse.cbUnknown = cbUnknown;
parse.cip = addr;
strcpy_s(parse.instr, instruction);
if(XEDParseAssemble(&parse) == XEDPARSE_ERROR)
{
if(error)
strcpy_s(error, MAX_ERROR_SIZE, parse.error);
return false;
}
if(dest)
memcpy(dest, parse.dest, parse.dest_size);
if(size)
*size = parse.dest_size;
return true;
}
bool assembleat(duint addr, const char* instruction, int* size, char* error, bool fillnop)
{
int destSize;
unsigned char dest[16];
if(!assemble(addr, dest, &destSize, instruction, error))
return false;
//calculate the number of NOPs to insert
int origLen = disasmgetsize(addr);
while(origLen < destSize)
origLen += disasmgetsize(addr + origLen);
int nopsize = origLen - destSize;
unsigned char nops[16];
memset(nops, 0x90, sizeof(nops));
if(size)
*size = destSize;
bool ret = MemPatch(addr, dest, destSize);
if (ret)
{
if (fillnop && nopsize)
{
if (size)
*size += nopsize;
// Ignored if the memory patch for NOPs fail (although it should not)
MemPatch(addr + destSize, nops, nopsize);
}
// Update GUI if any patching succeeded
GuiUpdatePatches();
}
else
{
// Tell the user writing is blocked
strcpy_s(error, MAX_ERROR_SIZE, "Error while writing process memory");
}
return ret;
}

View File

@ -1,9 +1,9 @@
#ifndef _ASSEMBLE_H
#define _ASSEMBLE_H
#include "_global.h"
bool assemble(duint addr, unsigned char* dest, int* size, const char* instruction, char* error);
bool assembleat(duint addr, const char* instruction, int* size, char* error, bool fillnop);
#endif // _ASSEMBLE_H
#ifndef _ASSEMBLE_H
#define _ASSEMBLE_H
#include "_global.h"
bool assemble(duint addr, unsigned char* dest, int* size, const char* instruction, char* error);
bool assembleat(duint addr, const char* instruction, int* size, char* error, bool fillnop);
#endif // _ASSEMBLE_H

View File

@ -1,199 +1,199 @@
#include "bookmark.h"
#include "threading.h"
#include "module.h"
#include "memory.h"
std::unordered_map<duint, BOOKMARKSINFO> bookmarks;
bool BookmarkSet(duint Address, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// Validate the incoming address
if(!MemIsValidReadPtr(Address))
return false;
BOOKMARKSINFO bookmark;
ModNameFromAddr(Address, bookmark.mod, true);
bookmark.addr = Address - ModBaseFromAddr(Address);
bookmark.manual = Manual;
// Exclusive lock to insert new data
EXCLUSIVE_ACQUIRE(LockBookmarks);
if(!bookmarks.insert(std::make_pair(ModHashFromAddr(Address), bookmark)).second)
{
EXCLUSIVE_RELEASE();
return BookmarkDelete(Address);
}
return true;
}
bool BookmarkGet(duint Address)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockBookmarks);
return (bookmarks.count(ModHashFromAddr(Address)) > 0);
}
bool BookmarkDelete(duint Address)
{
ASSERT_DEBUGGING("Export call");
EXCLUSIVE_ACQUIRE(LockBookmarks);
return (bookmarks.erase(ModHashFromAddr(Address)) > 0);
}
void BookmarkDelRange(duint Start, duint End)
{
ASSERT_DEBUGGING("Export call");
// Are all bookmarks going to be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
{
BookmarkClear();
}
else
{
// Make sure 'Start' and 'End' reference the same module
duint moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
// Virtual -> relative offset
Start -= moduleBase;
End -= moduleBase;
EXCLUSIVE_ACQUIRE(LockBookmarks);
for(auto itr = bookmarks.begin(); itr != bookmarks.end();)
{
const auto & currentBookmark = itr->second;
// Ignore manually set entries
if(currentBookmark.manual)
{
++itr;
continue;
}
// [Start, End)
if(currentBookmark.addr >= Start && currentBookmark.addr < End)
itr = bookmarks.erase(itr);
else
++itr;
}
}
}
void BookmarkCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
const JSON jsonBookmarks = json_array();
const JSON jsonAutoBookmarks = json_array();
// Save to the JSON root
for(auto & itr : bookmarks)
{
JSON currentBookmark = json_object();
json_object_set_new(currentBookmark, "module", json_string(itr.second.mod));
json_object_set_new(currentBookmark, "address", json_hex(itr.second.addr));
if(itr.second.manual)
json_array_append_new(jsonBookmarks, currentBookmark);
else
json_array_append_new(jsonAutoBookmarks, currentBookmark);
}
if(json_array_size(jsonBookmarks))
json_object_set(Root, "bookmarks", jsonBookmarks);
if(json_array_size(jsonAutoBookmarks))
json_object_set(Root, "autobookmarks", jsonAutoBookmarks);
json_decref(jsonBookmarks);
json_decref(jsonAutoBookmarks);
}
void BookmarkCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
// Inline lambda to parse each JSON entry
auto AddBookmarks = [](const JSON Object, bool Manual)
{
size_t i;
JSON value;
json_array_foreach(Object, i, value)
{
BOOKMARKSINFO bookmarkInfo;
memset(&bookmarkInfo, 0, sizeof(BOOKMARKSINFO));
// Load the module name
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(bookmarkInfo.mod, mod);
// Load address and set auto-generated flag
bookmarkInfo.addr = (duint)json_hex_value(json_object_get(value, "address"));
bookmarkInfo.manual = Manual;
const duint key = ModHashFromName(bookmarkInfo.mod) + bookmarkInfo.addr;
bookmarks.insert(std::make_pair(key, bookmarkInfo));
}
};
// Remove existing entries
bookmarks.clear();
const JSON jsonBookmarks = json_object_get(Root, "bookmarks");
const JSON jsonAutoBookmarks = json_object_get(Root, "autobookmarks");
// Load user-set bookmarks
if(jsonBookmarks)
AddBookmarks(jsonBookmarks, true);
// Load auto-set bookmarks
if(jsonAutoBookmarks)
AddBookmarks(jsonAutoBookmarks, false);
}
bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size)
{
// The array container must be set, or the size must be set, or both
ASSERT_FALSE(!List && !Size);
SHARED_ACQUIRE(LockBookmarks);
// Return the size if set
if(Size)
{
*Size = bookmarks.size() * sizeof(BOOKMARKSINFO);
if(!List)
return true;
}
// Copy struct and adjust the relative offset to a virtual address
for(auto & itr : bookmarks)
{
*List = itr.second;
List->addr += ModBaseFromName(List->mod);
List++;
}
return true;
}
void BookmarkClear()
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
bookmarks.clear();
#include "bookmark.h"
#include "threading.h"
#include "module.h"
#include "memory.h"
std::unordered_map<duint, BOOKMARKSINFO> bookmarks;
bool BookmarkSet(duint Address, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// Validate the incoming address
if(!MemIsValidReadPtr(Address))
return false;
BOOKMARKSINFO bookmark;
ModNameFromAddr(Address, bookmark.mod, true);
bookmark.addr = Address - ModBaseFromAddr(Address);
bookmark.manual = Manual;
// Exclusive lock to insert new data
EXCLUSIVE_ACQUIRE(LockBookmarks);
if(!bookmarks.insert(std::make_pair(ModHashFromAddr(Address), bookmark)).second)
{
EXCLUSIVE_RELEASE();
return BookmarkDelete(Address);
}
return true;
}
bool BookmarkGet(duint Address)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockBookmarks);
return (bookmarks.count(ModHashFromAddr(Address)) > 0);
}
bool BookmarkDelete(duint Address)
{
ASSERT_DEBUGGING("Export call");
EXCLUSIVE_ACQUIRE(LockBookmarks);
return (bookmarks.erase(ModHashFromAddr(Address)) > 0);
}
void BookmarkDelRange(duint Start, duint End)
{
ASSERT_DEBUGGING("Export call");
// Are all bookmarks going to be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
{
BookmarkClear();
}
else
{
// Make sure 'Start' and 'End' reference the same module
duint moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
// Virtual -> relative offset
Start -= moduleBase;
End -= moduleBase;
EXCLUSIVE_ACQUIRE(LockBookmarks);
for(auto itr = bookmarks.begin(); itr != bookmarks.end();)
{
const auto & currentBookmark = itr->second;
// Ignore manually set entries
if(currentBookmark.manual)
{
++itr;
continue;
}
// [Start, End)
if(currentBookmark.addr >= Start && currentBookmark.addr < End)
itr = bookmarks.erase(itr);
else
++itr;
}
}
}
void BookmarkCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
const JSON jsonBookmarks = json_array();
const JSON jsonAutoBookmarks = json_array();
// Save to the JSON root
for(auto & itr : bookmarks)
{
JSON currentBookmark = json_object();
json_object_set_new(currentBookmark, "module", json_string(itr.second.mod));
json_object_set_new(currentBookmark, "address", json_hex(itr.second.addr));
if(itr.second.manual)
json_array_append_new(jsonBookmarks, currentBookmark);
else
json_array_append_new(jsonAutoBookmarks, currentBookmark);
}
if(json_array_size(jsonBookmarks))
json_object_set(Root, "bookmarks", jsonBookmarks);
if(json_array_size(jsonAutoBookmarks))
json_object_set(Root, "autobookmarks", jsonAutoBookmarks);
json_decref(jsonBookmarks);
json_decref(jsonAutoBookmarks);
}
void BookmarkCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
// Inline lambda to parse each JSON entry
auto AddBookmarks = [](const JSON Object, bool Manual)
{
size_t i;
JSON value;
json_array_foreach(Object, i, value)
{
BOOKMARKSINFO bookmarkInfo;
memset(&bookmarkInfo, 0, sizeof(BOOKMARKSINFO));
// Load the module name
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(bookmarkInfo.mod, mod);
// Load address and set auto-generated flag
bookmarkInfo.addr = (duint)json_hex_value(json_object_get(value, "address"));
bookmarkInfo.manual = Manual;
const duint key = ModHashFromName(bookmarkInfo.mod) + bookmarkInfo.addr;
bookmarks.insert(std::make_pair(key, bookmarkInfo));
}
};
// Remove existing entries
bookmarks.clear();
const JSON jsonBookmarks = json_object_get(Root, "bookmarks");
const JSON jsonAutoBookmarks = json_object_get(Root, "autobookmarks");
// Load user-set bookmarks
if(jsonBookmarks)
AddBookmarks(jsonBookmarks, true);
// Load auto-set bookmarks
if(jsonAutoBookmarks)
AddBookmarks(jsonAutoBookmarks, false);
}
bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size)
{
// The array container must be set, or the size must be set, or both
ASSERT_FALSE(!List && !Size);
SHARED_ACQUIRE(LockBookmarks);
// Return the size if set
if(Size)
{
*Size = bookmarks.size() * sizeof(BOOKMARKSINFO);
if(!List)
return true;
}
// Copy struct and adjust the relative offset to a virtual address
for(auto & itr : bookmarks)
{
*List = itr.second;
List->addr += ModBaseFromName(List->mod);
List++;
}
return true;
}
void BookmarkClear()
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
bookmarks.clear();
}

View File

@ -1,19 +1,19 @@
#pragma once
#include "_global.h"
struct BOOKMARKSINFO
{
char mod[MAX_MODULE_SIZE];
duint addr;
bool manual;
};
bool BookmarkSet(duint Address, bool Manual);
bool BookmarkGet(duint Address);
bool BookmarkDelete(duint Address);
void BookmarkDelRange(duint Start, duint End);
void BookmarkCacheSave(JSON Root);
void BookmarkCacheLoad(JSON Root);
bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size);
#pragma once
#include "_global.h"
struct BOOKMARKSINFO
{
char mod[MAX_MODULE_SIZE];
duint addr;
bool manual;
};
bool BookmarkSet(duint Address, bool Manual);
bool BookmarkGet(duint Address);
bool BookmarkDelete(duint Address);
void BookmarkDelRange(duint Start, duint End);
void BookmarkCacheSave(JSON Root);
void BookmarkCacheLoad(JSON Root);
bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size);
void BookmarkClear();

View File

@ -1,381 +1,381 @@
/**
@file breakpoint.cpp
@brief Implements the breakpoint class.
*/
#include "breakpoint.h"
#include "memory.h"
#include "threading.h"
#include "module.h"
typedef std::pair<BP_TYPE, duint> BreakpointKey;
std::map<BreakpointKey, BREAKPOINT> breakpoints;
BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, duint Address)
{
//
// NOTE: THIS DOES _NOT_ USE LOCKS
//
auto found = breakpoints.find(BreakpointKey(Type, ModHashFromAddr(Address)));
// Was the module found with this address?
if(found == breakpoints.end())
return nullptr;
return &found->second;
}
int BpGetList(std::vector<BREAKPOINT>* List)
{
SHARED_ACQUIRE(LockBreakpoints);
// Did the caller request an output?
if(List)
{
// Enumerate all breakpoints in the global list, fixing the relative
// offset to a virtual address
for(auto & i : breakpoints)
{
BREAKPOINT currentBp = i.second;
currentBp.addr += ModBaseFromName(currentBp.mod);
currentBp.active = MemIsValidReadPtr(currentBp.addr);
List->push_back(currentBp);
}
}
return (int)breakpoints.size();
}
bool BpNew(duint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name)
{
ASSERT_DEBUGGING("Export call");
// Fail if the address is a bad memory region
if(!MemIsValidReadPtr(Address))
return false;
// Fail if the breakpoint already exists
if(BpGet(Address, Type, Name, nullptr))
return false;
// Default to an empty name if one wasn't supplied
if(!Name)
Name = "";
BREAKPOINT bp;
memset(&bp, 0, sizeof(BREAKPOINT));
ModNameFromAddr(Address, bp.mod, true);
strcpy_s(bp.name, Name);
bp.active = true;
bp.addr = Address - ModBaseFromAddr(Address);
bp.enabled = Enable;
bp.oldbytes = OldBytes;
bp.singleshoot = Singleshot;
bp.titantype = TitanType;
bp.type = Type;
// Insert new entry to the global list
EXCLUSIVE_ACQUIRE(LockBreakpoints);
breakpoints.insert(std::make_pair(BreakpointKey(Type, ModHashFromAddr(Address)), bp));
return true;
}
bool BpGet(duint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockBreakpoints);
// Name is optional
if(!Name || Name[0] == '\0')
{
// Perform a lookup by address only
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
if(!bpInfo)
return false;
// Succeed even if the user didn't request anything
if(!Bp)
return true;
*Bp = *bpInfo;
Bp->addr += ModBaseFromAddr(Address);
Bp->active = MemIsValidReadPtr(Bp->addr);
return true;
}
// Do a lookup by breakpoint name
for(auto & i : breakpoints)
{
// Do the names match?
if(strcmp(Name, i.second.name) != 0)
continue;
// Fill out the optional user buffer
if(Bp)
{
*Bp = i.second;
Bp->addr += ModBaseFromAddr(Address);
Bp->active = MemIsValidReadPtr(Bp->addr);
}
// Return true if the name was found at all
return true;
}
return false;
}
bool BpDelete(duint Address, BP_TYPE Type)
{
ASSERT_DEBUGGING("Command function call");
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Erase the index from the global list
return (breakpoints.erase(BreakpointKey(Type, ModHashFromAddr(Address))) > 0);
}
bool BpEnable(duint Address, BP_TYPE Type, bool Enable)
{
ASSERT_DEBUGGING("Command function call");
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Check if the breakpoint exists first
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
if(!bpInfo)
return false;
bpInfo->enabled = Enable;
return true;
}
bool BpSetName(duint Address, BP_TYPE Type, const char* Name)
{
ASSERT_DEBUGGING("Future(?): This is not used anywhere");
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// If a name wasn't supplied, set to nothing
if(!Name)
Name = "";
// Check if the breakpoint exists first
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
if(!bpInfo)
return false;
strcpy_s(bpInfo->name, Name);
return true;
}
bool BpSetTitanType(duint Address, BP_TYPE Type, int TitanType)
{
ASSERT_DEBUGGING("Command function call");
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Set the TitanEngine type, separate from BP_TYPE
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
if(!bpInfo)
return false;
bpInfo->titantype = TitanType;
return true;
}
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockBreakpoints);
// Loop each entry, executing the user's callback
bool callbackStatus = true;
for (auto i = breakpoints.begin(); i != breakpoints.end();)
{
auto j = i;
++i; // Increment here, because the callback might remove the current entry
// If a module name was sent, check it
if(Module && Module[0] != '\0')
{
if(strcmp(j->second.mod, Module) != 0)
continue;
}
BREAKPOINT bpInfo = j->second;
bpInfo.addr += ModBaseFromName(bpInfo.mod);
bpInfo.active = MemIsValidReadPtr(bpInfo.addr);
// Lock must be released due to callback sub-locks
SHARED_RELEASE();
// Execute the callback
if(!EnumCallback(&bpInfo))
callbackStatus = false;
// Restore the breakpoint map lock
SHARED_REACQUIRE();
}
return callbackStatus;
}
bool BpEnumAll(BPENUMCALLBACK EnumCallback)
{
return BpEnumAll(EnumCallback, nullptr);
}
int BpGetCount(BP_TYPE Type, bool EnabledOnly)
{
SHARED_ACQUIRE(LockBreakpoints);
// Count the number of enabled/disabled breakpoint types
int count = 0;
for(auto & i : breakpoints)
{
// Check if the type matches
if(i.first.first != Type)
continue;
// If it's not enabled, skip it
if(EnabledOnly && !i.second.enabled)
continue;
count++;
}
return count;
}
void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp)
{
//
// Convert a debugger breakpoint to an open/exported
// bridge breakpoint
//
ASSERT_NONNULL(Bp);
ASSERT_NONNULL(BridgeBp);
memset(BridgeBp, 0, sizeof(BRIDGEBP));
strcpy_s(BridgeBp->mod, Bp->mod);
strcpy_s(BridgeBp->name, Bp->name);
BridgeBp->active = Bp->active;
BridgeBp->addr = Bp->addr;
BridgeBp->enabled = Bp->enabled;
BridgeBp->singleshoot = Bp->singleshoot;
switch(Bp->type)
{
case BPNORMAL:
BridgeBp->type = bp_normal;
break;
case BPHARDWARE:
BridgeBp->type = bp_hardware;
break;
case BPMEMORY:
BridgeBp->type = bp_memory;
break;
default:
BridgeBp->type = bp_none;
break;
}
}
void BpCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Create a JSON array to store each sub-object with a breakpoint
const JSON jsonBreakpoints = json_array();
// Loop all breakpoints
for(auto & i : breakpoints)
{
auto & breakpoint = i.second;
// Ignore single-shot breakpoints
if(breakpoint.singleshoot)
continue;
JSON jsonObj = json_object();
json_object_set_new(jsonObj, "address", json_hex(breakpoint.addr));
json_object_set_new(jsonObj, "enabled", json_boolean(breakpoint.enabled));
// "Normal" breakpoints save the old data
if(breakpoint.type == BPNORMAL)
json_object_set_new(jsonObj, "oldbytes", json_hex(breakpoint.oldbytes));
json_object_set_new(jsonObj, "type", json_integer(breakpoint.type));
json_object_set_new(jsonObj, "titantype", json_hex(breakpoint.titantype));
json_object_set_new(jsonObj, "name", json_string(breakpoint.name));
json_object_set_new(jsonObj, "module", json_string(breakpoint.mod));
json_array_append_new(jsonBreakpoints, jsonObj);
}
if(json_array_size(jsonBreakpoints))
json_object_set(Root, "breakpoints", jsonBreakpoints);
// Notify garbage collector
json_decref(jsonBreakpoints);
}
void BpCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Remove all existing elements
breakpoints.clear();
// Get a handle to the root object -> breakpoints subtree
const JSON jsonBreakpoints = json_object_get(Root, "breakpoints");
// Return if there was nothing to load
if(!jsonBreakpoints)
return;
size_t i;
JSON value;
json_array_foreach(jsonBreakpoints, i, value)
{
BREAKPOINT breakpoint;
memset(&breakpoint, 0, sizeof(BREAKPOINT));
if(breakpoint.type == BPNORMAL)
breakpoint.oldbytes = (short)json_hex_value(json_object_get(value, "oldbytes"));
breakpoint.type = (BP_TYPE)json_integer_value(json_object_get(value, "type"));
breakpoint.addr = (duint)json_hex_value(json_object_get(value, "address"));
breakpoint.enabled = json_boolean_value(json_object_get(value, "enabled"));
breakpoint.titantype = (DWORD)json_hex_value(json_object_get(value, "titantype"));
// Name
const char* name = json_string_value(json_object_get(value, "name"));
if(name)
strcpy_s(breakpoint.name, name);
// Module
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(breakpoint.mod, mod);
// Build the hash map key: MOD_HASH + ADDRESS
const duint key = ModHashFromName(breakpoint.mod) + breakpoint.addr;
breakpoints.insert(std::make_pair(BreakpointKey(breakpoint.type, key), breakpoint));
}
}
void BpClear()
{
EXCLUSIVE_ACQUIRE(LockBreakpoints);
breakpoints.clear();
/**
@file breakpoint.cpp
@brief Implements the breakpoint class.
*/
#include "breakpoint.h"
#include "memory.h"
#include "threading.h"
#include "module.h"
typedef std::pair<BP_TYPE, duint> BreakpointKey;
std::map<BreakpointKey, BREAKPOINT> breakpoints;
BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, duint Address)
{
//
// NOTE: THIS DOES _NOT_ USE LOCKS
//
auto found = breakpoints.find(BreakpointKey(Type, ModHashFromAddr(Address)));
// Was the module found with this address?
if(found == breakpoints.end())
return nullptr;
return &found->second;
}
int BpGetList(std::vector<BREAKPOINT>* List)
{
SHARED_ACQUIRE(LockBreakpoints);
// Did the caller request an output?
if(List)
{
// Enumerate all breakpoints in the global list, fixing the relative
// offset to a virtual address
for(auto & i : breakpoints)
{
BREAKPOINT currentBp = i.second;
currentBp.addr += ModBaseFromName(currentBp.mod);
currentBp.active = MemIsValidReadPtr(currentBp.addr);
List->push_back(currentBp);
}
}
return (int)breakpoints.size();
}
bool BpNew(duint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name)
{
ASSERT_DEBUGGING("Export call");
// Fail if the address is a bad memory region
if(!MemIsValidReadPtr(Address))
return false;
// Fail if the breakpoint already exists
if(BpGet(Address, Type, Name, nullptr))
return false;
// Default to an empty name if one wasn't supplied
if(!Name)
Name = "";
BREAKPOINT bp;
memset(&bp, 0, sizeof(BREAKPOINT));
ModNameFromAddr(Address, bp.mod, true);
strcpy_s(bp.name, Name);
bp.active = true;
bp.addr = Address - ModBaseFromAddr(Address);
bp.enabled = Enable;
bp.oldbytes = OldBytes;
bp.singleshoot = Singleshot;
bp.titantype = TitanType;
bp.type = Type;
// Insert new entry to the global list
EXCLUSIVE_ACQUIRE(LockBreakpoints);
breakpoints.insert(std::make_pair(BreakpointKey(Type, ModHashFromAddr(Address)), bp));
return true;
}
bool BpGet(duint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockBreakpoints);
// Name is optional
if(!Name || Name[0] == '\0')
{
// Perform a lookup by address only
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
if(!bpInfo)
return false;
// Succeed even if the user didn't request anything
if(!Bp)
return true;
*Bp = *bpInfo;
Bp->addr += ModBaseFromAddr(Address);
Bp->active = MemIsValidReadPtr(Bp->addr);
return true;
}
// Do a lookup by breakpoint name
for(auto & i : breakpoints)
{
// Do the names match?
if(strcmp(Name, i.second.name) != 0)
continue;
// Fill out the optional user buffer
if(Bp)
{
*Bp = i.second;
Bp->addr += ModBaseFromAddr(Address);
Bp->active = MemIsValidReadPtr(Bp->addr);
}
// Return true if the name was found at all
return true;
}
return false;
}
bool BpDelete(duint Address, BP_TYPE Type)
{
ASSERT_DEBUGGING("Command function call");
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Erase the index from the global list
return (breakpoints.erase(BreakpointKey(Type, ModHashFromAddr(Address))) > 0);
}
bool BpEnable(duint Address, BP_TYPE Type, bool Enable)
{
ASSERT_DEBUGGING("Command function call");
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Check if the breakpoint exists first
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
if(!bpInfo)
return false;
bpInfo->enabled = Enable;
return true;
}
bool BpSetName(duint Address, BP_TYPE Type, const char* Name)
{
ASSERT_DEBUGGING("Future(?): This is not used anywhere");
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// If a name wasn't supplied, set to nothing
if(!Name)
Name = "";
// Check if the breakpoint exists first
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
if(!bpInfo)
return false;
strcpy_s(bpInfo->name, Name);
return true;
}
bool BpSetTitanType(duint Address, BP_TYPE Type, int TitanType)
{
ASSERT_DEBUGGING("Command function call");
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Set the TitanEngine type, separate from BP_TYPE
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
if(!bpInfo)
return false;
bpInfo->titantype = TitanType;
return true;
}
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockBreakpoints);
// Loop each entry, executing the user's callback
bool callbackStatus = true;
for (auto i = breakpoints.begin(); i != breakpoints.end();)
{
auto j = i;
++i; // Increment here, because the callback might remove the current entry
// If a module name was sent, check it
if(Module && Module[0] != '\0')
{
if(strcmp(j->second.mod, Module) != 0)
continue;
}
BREAKPOINT bpInfo = j->second;
bpInfo.addr += ModBaseFromName(bpInfo.mod);
bpInfo.active = MemIsValidReadPtr(bpInfo.addr);
// Lock must be released due to callback sub-locks
SHARED_RELEASE();
// Execute the callback
if(!EnumCallback(&bpInfo))
callbackStatus = false;
// Restore the breakpoint map lock
SHARED_REACQUIRE();
}
return callbackStatus;
}
bool BpEnumAll(BPENUMCALLBACK EnumCallback)
{
return BpEnumAll(EnumCallback, nullptr);
}
int BpGetCount(BP_TYPE Type, bool EnabledOnly)
{
SHARED_ACQUIRE(LockBreakpoints);
// Count the number of enabled/disabled breakpoint types
int count = 0;
for(auto & i : breakpoints)
{
// Check if the type matches
if(i.first.first != Type)
continue;
// If it's not enabled, skip it
if(EnabledOnly && !i.second.enabled)
continue;
count++;
}
return count;
}
void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp)
{
//
// Convert a debugger breakpoint to an open/exported
// bridge breakpoint
//
ASSERT_NONNULL(Bp);
ASSERT_NONNULL(BridgeBp);
memset(BridgeBp, 0, sizeof(BRIDGEBP));
strcpy_s(BridgeBp->mod, Bp->mod);
strcpy_s(BridgeBp->name, Bp->name);
BridgeBp->active = Bp->active;
BridgeBp->addr = Bp->addr;
BridgeBp->enabled = Bp->enabled;
BridgeBp->singleshoot = Bp->singleshoot;
switch(Bp->type)
{
case BPNORMAL:
BridgeBp->type = bp_normal;
break;
case BPHARDWARE:
BridgeBp->type = bp_hardware;
break;
case BPMEMORY:
BridgeBp->type = bp_memory;
break;
default:
BridgeBp->type = bp_none;
break;
}
}
void BpCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Create a JSON array to store each sub-object with a breakpoint
const JSON jsonBreakpoints = json_array();
// Loop all breakpoints
for(auto & i : breakpoints)
{
auto & breakpoint = i.second;
// Ignore single-shot breakpoints
if(breakpoint.singleshoot)
continue;
JSON jsonObj = json_object();
json_object_set_new(jsonObj, "address", json_hex(breakpoint.addr));
json_object_set_new(jsonObj, "enabled", json_boolean(breakpoint.enabled));
// "Normal" breakpoints save the old data
if(breakpoint.type == BPNORMAL)
json_object_set_new(jsonObj, "oldbytes", json_hex(breakpoint.oldbytes));
json_object_set_new(jsonObj, "type", json_integer(breakpoint.type));
json_object_set_new(jsonObj, "titantype", json_hex(breakpoint.titantype));
json_object_set_new(jsonObj, "name", json_string(breakpoint.name));
json_object_set_new(jsonObj, "module", json_string(breakpoint.mod));
json_array_append_new(jsonBreakpoints, jsonObj);
}
if(json_array_size(jsonBreakpoints))
json_object_set(Root, "breakpoints", jsonBreakpoints);
// Notify garbage collector
json_decref(jsonBreakpoints);
}
void BpCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBreakpoints);
// Remove all existing elements
breakpoints.clear();
// Get a handle to the root object -> breakpoints subtree
const JSON jsonBreakpoints = json_object_get(Root, "breakpoints");
// Return if there was nothing to load
if(!jsonBreakpoints)
return;
size_t i;
JSON value;
json_array_foreach(jsonBreakpoints, i, value)
{
BREAKPOINT breakpoint;
memset(&breakpoint, 0, sizeof(BREAKPOINT));
if(breakpoint.type == BPNORMAL)
breakpoint.oldbytes = (short)json_hex_value(json_object_get(value, "oldbytes"));
breakpoint.type = (BP_TYPE)json_integer_value(json_object_get(value, "type"));
breakpoint.addr = (duint)json_hex_value(json_object_get(value, "address"));
breakpoint.enabled = json_boolean_value(json_object_get(value, "enabled"));
breakpoint.titantype = (DWORD)json_hex_value(json_object_get(value, "titantype"));
// Name
const char* name = json_string_value(json_object_get(value, "name"));
if(name)
strcpy_s(breakpoint.name, name);
// Module
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(breakpoint.mod, mod);
// Build the hash map key: MOD_HASH + ADDRESS
const duint key = ModHashFromName(breakpoint.mod) + breakpoint.addr;
breakpoints.insert(std::make_pair(BreakpointKey(breakpoint.type, key), breakpoint));
}
}
void BpClear()
{
EXCLUSIVE_ACQUIRE(LockBreakpoints);
breakpoints.clear();
}

View File

@ -1,49 +1,49 @@
#pragma once
#include "_global.h"
#define TITANSETDRX(titantype, drx) titantype &= 0x0FF; titantype |= (drx<<8)
#define TITANGETDRX(titantype) (titantype >> 8) & 0xF
#define TITANSETTYPE(titantype, type) titantype &= 0xF0F; titantype |= (type<<4)
#define TITANGETTYPE(titantype) (titantype >> 4) & 0xF
#define TITANSETSIZE(titantype, size) titantype &= 0xFF0; titantype |= size;
#define TITANGETSIZE(titantype) titantype & 0xF
enum BP_TYPE
{
BPNORMAL = 0,
BPHARDWARE = 1,
BPMEMORY = 2
};
struct BREAKPOINT
{
duint addr;
bool enabled;
bool singleshoot;
bool active;
short oldbytes;
BP_TYPE type;
DWORD titantype;
char name[MAX_BREAKPOINT_SIZE];
char mod[MAX_MODULE_SIZE];
};
// Breakpoint enumeration callback
typedef bool (*BPENUMCALLBACK)(const BREAKPOINT* bp);
BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, duint Address);
int BpGetList(std::vector<BREAKPOINT>* List);
bool BpNew(duint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name);
bool BpGet(duint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp);
bool BpDelete(duint Address, BP_TYPE Type);
bool BpEnable(duint Address, BP_TYPE Type, bool Enable);
bool BpSetName(duint Address, BP_TYPE Type, const char* Name);
bool BpSetTitanType(duint Address, BP_TYPE Type, int TitanType);
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module);
bool BpEnumAll(BPENUMCALLBACK EnumCallback);
int BpGetCount(BP_TYPE Type, bool EnabledOnly = false);
void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp);
void BpCacheSave(JSON Root);
void BpCacheLoad(JSON Root);
#pragma once
#include "_global.h"
#define TITANSETDRX(titantype, drx) titantype &= 0x0FF; titantype |= (drx<<8)
#define TITANGETDRX(titantype) (titantype >> 8) & 0xF
#define TITANSETTYPE(titantype, type) titantype &= 0xF0F; titantype |= (type<<4)
#define TITANGETTYPE(titantype) (titantype >> 4) & 0xF
#define TITANSETSIZE(titantype, size) titantype &= 0xFF0; titantype |= size;
#define TITANGETSIZE(titantype) titantype & 0xF
enum BP_TYPE
{
BPNORMAL = 0,
BPHARDWARE = 1,
BPMEMORY = 2
};
struct BREAKPOINT
{
duint addr;
bool enabled;
bool singleshoot;
bool active;
short oldbytes;
BP_TYPE type;
DWORD titantype;
char name[MAX_BREAKPOINT_SIZE];
char mod[MAX_MODULE_SIZE];
};
// Breakpoint enumeration callback
typedef bool (*BPENUMCALLBACK)(const BREAKPOINT* bp);
BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, duint Address);
int BpGetList(std::vector<BREAKPOINT>* List);
bool BpNew(duint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name);
bool BpGet(duint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp);
bool BpDelete(duint Address, BP_TYPE Type);
bool BpEnable(duint Address, BP_TYPE Type, bool Enable);
bool BpSetName(duint Address, BP_TYPE Type, const char* Name);
bool BpSetTitanType(duint Address, BP_TYPE Type, int TitanType);
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module);
bool BpEnumAll(BPENUMCALLBACK EnumCallback);
int BpGetCount(BP_TYPE Type, bool EnabledOnly = false);
void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp);
void BpCacheSave(JSON Root);
void BpCacheLoad(JSON Root);
void BpClear();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,28 @@
/* Capstone Disassembly Engine */
/* By Axel Souchet & Nguyen Anh Quynh, 2014 */
// handle C99 issue (for pre-2013 VisualStudio)
#ifndef CAPSTONE_PLATFORM_H
#define CAPSTONE_PLATFORM_H
#if !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
// MSVC
// stdbool.h
#if (_MSC_VER < 1800)
#ifndef __cplusplus
typedef unsigned char bool;
#define false 0
#define true 1
#endif
#else
// VisualStudio 2013+ -> C99 is supported
#include <stdbool.h>
#endif
#else // not MSVC -> C99 is supported
#include <stdbool.h>
#endif
#endif
/* Capstone Disassembly Engine */
/* By Axel Souchet & Nguyen Anh Quynh, 2014 */
// handle C99 issue (for pre-2013 VisualStudio)
#ifndef CAPSTONE_PLATFORM_H
#define CAPSTONE_PLATFORM_H
#if !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
// MSVC
// stdbool.h
#if (_MSC_VER < 1800)
#ifndef __cplusplus
typedef unsigned char bool;
#define false 0
#define true 1
#endif
#else
// VisualStudio 2013+ -> C99 is supported
#include <stdbool.h>
#endif
#else // not MSVC -> C99 is supported
#include <stdbool.h>
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,242 +1,242 @@
#ifndef CAPSTONE_XCORE_H
#define CAPSTONE_XCORE_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014 */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
//> Operand type for instruction's operands
typedef enum xcore_op_type
{
XCORE_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized).
XCORE_OP_REG, // = CS_OP_REG (Register operand).
XCORE_OP_IMM, // = CS_OP_IMM (Immediate operand).
XCORE_OP_MEM, // = CS_OP_MEM (Memory operand).
} xcore_op_type;
// Instruction's operand referring to memory
// This is associated with XCORE_OP_MEM operand type above
typedef struct xcore_op_mem
{
uint8_t base; // base register
uint8_t index; // index register
int32_t disp; // displacement/offset value
int direct; // +1: forward, -1: backward
} xcore_op_mem;
// Instruction operand
typedef struct cs_xcore_op
{
xcore_op_type type; // operand type
union
{
unsigned int reg; // register value for REG operand
int32_t imm; // immediate value for IMM operand
xcore_op_mem mem; // base/disp value for MEM operand
};
} cs_xcore_op;
// Instruction structure
typedef struct cs_xcore
{
// Number of operands of this instruction,
// or 0 when instruction has no operand.
uint8_t op_count;
cs_xcore_op operands[8]; // operands for this instruction.
} cs_xcore;
//> XCore registers
typedef enum xcore_reg
{
XCORE_REG_INVALID = 0,
XCORE_REG_CP,
XCORE_REG_DP,
XCORE_REG_LR,
XCORE_REG_SP,
XCORE_REG_R0,
XCORE_REG_R1,
XCORE_REG_R2,
XCORE_REG_R3,
XCORE_REG_R4,
XCORE_REG_R5,
XCORE_REG_R6,
XCORE_REG_R7,
XCORE_REG_R8,
XCORE_REG_R9,
XCORE_REG_R10,
XCORE_REG_R11,
//> pseudo registers
XCORE_REG_PC, // pc
// internal thread registers
// see The-XMOS-XS1-Architecture(X7879A).pdf
XCORE_REG_SCP, // save pc
XCORE_REG_SSR, // save status
XCORE_REG_ET, // exception type
XCORE_REG_ED, // exception data
XCORE_REG_SED, // save exception data
XCORE_REG_KEP, // kernel entry pointer
XCORE_REG_KSP, // kernel stack pointer
XCORE_REG_ID, // thread ID
XCORE_REG_ENDING, // <-- mark the end of the list of registers
} xcore_reg;
//> XCore instruction
typedef enum xcore_insn
{
XCORE_INS_INVALID = 0,
XCORE_INS_ADD,
XCORE_INS_ANDNOT,
XCORE_INS_AND,
XCORE_INS_ASHR,
XCORE_INS_BAU,
XCORE_INS_BITREV,
XCORE_INS_BLA,
XCORE_INS_BLAT,
XCORE_INS_BL,
XCORE_INS_BF,
XCORE_INS_BT,
XCORE_INS_BU,
XCORE_INS_BRU,
XCORE_INS_BYTEREV,
XCORE_INS_CHKCT,
XCORE_INS_CLRE,
XCORE_INS_CLRPT,
XCORE_INS_CLRSR,
XCORE_INS_CLZ,
XCORE_INS_CRC8,
XCORE_INS_CRC32,
XCORE_INS_DCALL,
XCORE_INS_DENTSP,
XCORE_INS_DGETREG,
XCORE_INS_DIVS,
XCORE_INS_DIVU,
XCORE_INS_DRESTSP,
XCORE_INS_DRET,
XCORE_INS_ECALLF,
XCORE_INS_ECALLT,
XCORE_INS_EDU,
XCORE_INS_EEF,
XCORE_INS_EET,
XCORE_INS_EEU,
XCORE_INS_ENDIN,
XCORE_INS_ENTSP,
XCORE_INS_EQ,
XCORE_INS_EXTDP,
XCORE_INS_EXTSP,
XCORE_INS_FREER,
XCORE_INS_FREET,
XCORE_INS_GETD,
XCORE_INS_GET,
XCORE_INS_GETN,
XCORE_INS_GETR,
XCORE_INS_GETSR,
XCORE_INS_GETST,
XCORE_INS_GETTS,
XCORE_INS_INCT,
XCORE_INS_INIT,
XCORE_INS_INPW,
XCORE_INS_INSHR,
XCORE_INS_INT,
XCORE_INS_IN,
XCORE_INS_KCALL,
XCORE_INS_KENTSP,
XCORE_INS_KRESTSP,
XCORE_INS_KRET,
XCORE_INS_LADD,
XCORE_INS_LD16S,
XCORE_INS_LD8U,
XCORE_INS_LDA16,
XCORE_INS_LDAP,
XCORE_INS_LDAW,
XCORE_INS_LDC,
XCORE_INS_LDW,
XCORE_INS_LDIVU,
XCORE_INS_LMUL,
XCORE_INS_LSS,
XCORE_INS_LSUB,
XCORE_INS_LSU,
XCORE_INS_MACCS,
XCORE_INS_MACCU,
XCORE_INS_MJOIN,
XCORE_INS_MKMSK,
XCORE_INS_MSYNC,
XCORE_INS_MUL,
XCORE_INS_NEG,
XCORE_INS_NOT,
XCORE_INS_OR,
XCORE_INS_OUTCT,
XCORE_INS_OUTPW,
XCORE_INS_OUTSHR,
XCORE_INS_OUTT,
XCORE_INS_OUT,
XCORE_INS_PEEK,
XCORE_INS_REMS,
XCORE_INS_REMU,
XCORE_INS_RETSP,
XCORE_INS_SETCLK,
XCORE_INS_SET,
XCORE_INS_SETC,
XCORE_INS_SETD,
XCORE_INS_SETEV,
XCORE_INS_SETN,
XCORE_INS_SETPSC,
XCORE_INS_SETPT,
XCORE_INS_SETRDY,
XCORE_INS_SETSR,
XCORE_INS_SETTW,
XCORE_INS_SETV,
XCORE_INS_SEXT,
XCORE_INS_SHL,
XCORE_INS_SHR,
XCORE_INS_SSYNC,
XCORE_INS_ST16,
XCORE_INS_ST8,
XCORE_INS_STW,
XCORE_INS_SUB,
XCORE_INS_SYNCR,
XCORE_INS_TESTCT,
XCORE_INS_TESTLCL,
XCORE_INS_TESTWCT,
XCORE_INS_TSETMR,
XCORE_INS_START,
XCORE_INS_WAITEF,
XCORE_INS_WAITET,
XCORE_INS_WAITEU,
XCORE_INS_XOR,
XCORE_INS_ZEXT,
XCORE_INS_ENDING, // <-- mark the end of the list of instructions
} xcore_insn;
//> Group of XCore instructions
typedef enum xcore_insn_group
{
XCORE_GRP_INVALID = 0, // = CS_GRP_INVALID
//> Generic groups
// all jump instructions (conditional+direct+indirect jumps)
XCORE_GRP_JUMP, // = CS_GRP_JUMP
XCORE_GRP_ENDING, // <-- mark the end of the list of groups
} xcore_insn_group;
#ifdef __cplusplus
}
#endif
#endif
#ifndef CAPSTONE_XCORE_H
#define CAPSTONE_XCORE_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014 */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
//> Operand type for instruction's operands
typedef enum xcore_op_type
{
XCORE_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized).
XCORE_OP_REG, // = CS_OP_REG (Register operand).
XCORE_OP_IMM, // = CS_OP_IMM (Immediate operand).
XCORE_OP_MEM, // = CS_OP_MEM (Memory operand).
} xcore_op_type;
// Instruction's operand referring to memory
// This is associated with XCORE_OP_MEM operand type above
typedef struct xcore_op_mem
{
uint8_t base; // base register
uint8_t index; // index register
int32_t disp; // displacement/offset value
int direct; // +1: forward, -1: backward
} xcore_op_mem;
// Instruction operand
typedef struct cs_xcore_op
{
xcore_op_type type; // operand type
union
{
unsigned int reg; // register value for REG operand
int32_t imm; // immediate value for IMM operand
xcore_op_mem mem; // base/disp value for MEM operand
};
} cs_xcore_op;
// Instruction structure
typedef struct cs_xcore
{
// Number of operands of this instruction,
// or 0 when instruction has no operand.
uint8_t op_count;
cs_xcore_op operands[8]; // operands for this instruction.
} cs_xcore;
//> XCore registers
typedef enum xcore_reg
{
XCORE_REG_INVALID = 0,
XCORE_REG_CP,
XCORE_REG_DP,
XCORE_REG_LR,
XCORE_REG_SP,
XCORE_REG_R0,
XCORE_REG_R1,
XCORE_REG_R2,
XCORE_REG_R3,
XCORE_REG_R4,
XCORE_REG_R5,
XCORE_REG_R6,
XCORE_REG_R7,
XCORE_REG_R8,
XCORE_REG_R9,
XCORE_REG_R10,
XCORE_REG_R11,
//> pseudo registers
XCORE_REG_PC, // pc
// internal thread registers
// see The-XMOS-XS1-Architecture(X7879A).pdf
XCORE_REG_SCP, // save pc
XCORE_REG_SSR, // save status
XCORE_REG_ET, // exception type
XCORE_REG_ED, // exception data
XCORE_REG_SED, // save exception data
XCORE_REG_KEP, // kernel entry pointer
XCORE_REG_KSP, // kernel stack pointer
XCORE_REG_ID, // thread ID
XCORE_REG_ENDING, // <-- mark the end of the list of registers
} xcore_reg;
//> XCore instruction
typedef enum xcore_insn
{
XCORE_INS_INVALID = 0,
XCORE_INS_ADD,
XCORE_INS_ANDNOT,
XCORE_INS_AND,
XCORE_INS_ASHR,
XCORE_INS_BAU,
XCORE_INS_BITREV,
XCORE_INS_BLA,
XCORE_INS_BLAT,
XCORE_INS_BL,
XCORE_INS_BF,
XCORE_INS_BT,
XCORE_INS_BU,
XCORE_INS_BRU,
XCORE_INS_BYTEREV,
XCORE_INS_CHKCT,
XCORE_INS_CLRE,
XCORE_INS_CLRPT,
XCORE_INS_CLRSR,
XCORE_INS_CLZ,
XCORE_INS_CRC8,
XCORE_INS_CRC32,
XCORE_INS_DCALL,
XCORE_INS_DENTSP,
XCORE_INS_DGETREG,
XCORE_INS_DIVS,
XCORE_INS_DIVU,
XCORE_INS_DRESTSP,
XCORE_INS_DRET,
XCORE_INS_ECALLF,
XCORE_INS_ECALLT,
XCORE_INS_EDU,
XCORE_INS_EEF,
XCORE_INS_EET,
XCORE_INS_EEU,
XCORE_INS_ENDIN,
XCORE_INS_ENTSP,
XCORE_INS_EQ,
XCORE_INS_EXTDP,
XCORE_INS_EXTSP,
XCORE_INS_FREER,
XCORE_INS_FREET,
XCORE_INS_GETD,
XCORE_INS_GET,
XCORE_INS_GETN,
XCORE_INS_GETR,
XCORE_INS_GETSR,
XCORE_INS_GETST,
XCORE_INS_GETTS,
XCORE_INS_INCT,
XCORE_INS_INIT,
XCORE_INS_INPW,
XCORE_INS_INSHR,
XCORE_INS_INT,
XCORE_INS_IN,
XCORE_INS_KCALL,
XCORE_INS_KENTSP,
XCORE_INS_KRESTSP,
XCORE_INS_KRET,
XCORE_INS_LADD,
XCORE_INS_LD16S,
XCORE_INS_LD8U,
XCORE_INS_LDA16,
XCORE_INS_LDAP,
XCORE_INS_LDAW,
XCORE_INS_LDC,
XCORE_INS_LDW,
XCORE_INS_LDIVU,
XCORE_INS_LMUL,
XCORE_INS_LSS,
XCORE_INS_LSUB,
XCORE_INS_LSU,
XCORE_INS_MACCS,
XCORE_INS_MACCU,
XCORE_INS_MJOIN,
XCORE_INS_MKMSK,
XCORE_INS_MSYNC,
XCORE_INS_MUL,
XCORE_INS_NEG,
XCORE_INS_NOT,
XCORE_INS_OR,
XCORE_INS_OUTCT,
XCORE_INS_OUTPW,
XCORE_INS_OUTSHR,
XCORE_INS_OUTT,
XCORE_INS_OUT,
XCORE_INS_PEEK,
XCORE_INS_REMS,
XCORE_INS_REMU,
XCORE_INS_RETSP,
XCORE_INS_SETCLK,
XCORE_INS_SET,
XCORE_INS_SETC,
XCORE_INS_SETD,
XCORE_INS_SETEV,
XCORE_INS_SETN,
XCORE_INS_SETPSC,
XCORE_INS_SETPT,
XCORE_INS_SETRDY,
XCORE_INS_SETSR,
XCORE_INS_SETTW,
XCORE_INS_SETV,
XCORE_INS_SEXT,
XCORE_INS_SHL,
XCORE_INS_SHR,
XCORE_INS_SSYNC,
XCORE_INS_ST16,
XCORE_INS_ST8,
XCORE_INS_STW,
XCORE_INS_SUB,
XCORE_INS_SYNCR,
XCORE_INS_TESTCT,
XCORE_INS_TESTLCL,
XCORE_INS_TESTWCT,
XCORE_INS_TSETMR,
XCORE_INS_START,
XCORE_INS_WAITEF,
XCORE_INS_WAITET,
XCORE_INS_WAITEU,
XCORE_INS_XOR,
XCORE_INS_ZEXT,
XCORE_INS_ENDING, // <-- mark the end of the list of instructions
} xcore_insn;
//> Group of XCore instructions
typedef enum xcore_insn_group
{
XCORE_GRP_INVALID = 0, // = CS_GRP_INVALID
//> Generic groups
// all jump instructions (conditional+direct+indirect jumps)
XCORE_GRP_JUMP, // = CS_GRP_JUMP
XCORE_GRP_ENDING, // <-- mark the end of the list of groups
} xcore_insn_group;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,412 +1,412 @@
/**
@file command.cpp
@brief Implements the command class.
*/
#include "command.h"
#include "value.h"
#include "console.h"
#include "commandparser.h"
COMMAND* cmd_list = 0;
/**
\brief Finds a ::COMMAND in a command list.
\param [in] command list.
\param name The name of the command to find.
\param [out] Link to the command.
\return null if it fails, else a ::COMMAND*.
*/
COMMAND* cmdfind(const char* name, COMMAND** link)
{
COMMAND* cur = cmd_list;
if(!cur->name)
return 0;
COMMAND* prev = 0;
while(cur)
{
if(arraycontains(cur->name, name))
{
if(link)
*link = prev;
return cur;
}
prev = cur;
cur = cur->next;
}
return 0;
}
/**
\brief Initialize a command list.
\return a ::COMMAND*
*/
COMMAND* cmdinit()
{
cmd_list = (COMMAND*)emalloc(sizeof(COMMAND), "cmdinit:cmd");
memset(cmd_list, 0, sizeof(COMMAND));
return cmd_list;
}
/**
\brief Clear a command list.
\param [in] cmd_list Command list to clear.
*/
void cmdfree()
{
COMMAND* cur = cmd_list;
while(cur)
{
efree(cur->name, "cmdfree:cur->name");
COMMAND* next = cur->next;
efree(cur, "cmdfree:cur");
cur = next;
}
}
/**
\brief Creates a new command and adds it to the list.
\param [in,out] command_list Command list. Cannot be null.
\param name The command name.
\param cbCommand The command callback.
\param debugonly true if the command can only be executed in a debugging context.
\return true if the command was successfully added to the list.
*/
bool cmdnew(const char* name, CBCOMMAND cbCommand, bool debugonly)
{
if (!cmd_list || !cbCommand || !name || !*name || cmdfind(name, 0))
return false;
COMMAND* cmd;
bool nonext = false;
if (!cmd_list->name)
{
cmd = cmd_list;
nonext = true;
}
else
cmd = (COMMAND*)emalloc(sizeof(COMMAND), "cmdnew:cmd");
memset(cmd, 0, sizeof(COMMAND));
cmd->name = (char*)emalloc(strlen(name) + 1, "cmdnew:cmd->name");
strcpy(cmd->name, name);
cmd->cbCommand = cbCommand;
cmd->debugonly = debugonly;
COMMAND* cur = cmd_list;
if(!nonext)
{
while(cur->next)
cur = cur->next;
cur->next = cmd;
}
return true;
}
/**
\brief Gets a ::COMMAND from the command list.
\param [in] command_list Command list.
\param cmd The command to get from the list.
\return null if the command was not found. Otherwise a ::COMMAND*.
*/
COMMAND* cmdget(const char* cmd)
{
char new_cmd[deflen] = "";
strcpy_s(new_cmd, deflen, cmd);
int len = (int)strlen(new_cmd);
int start = 0;
while(new_cmd[start] != ' ' && start < len)
start++;
new_cmd[start] = 0;
COMMAND* found = cmdfind(new_cmd, 0);
if(!found)
return 0;
return found;
}
/**
\brief Sets a new command callback and debugonly property in a command list.
\param [in] command_list Command list.
\param name The name of the command to change.
\param cbCommand The new command callback.
\param debugonly The new debugonly value.
\return The old command callback.
*/
CBCOMMAND cmdset(const char* name, CBCOMMAND cbCommand, bool debugonly)
{
if(!cbCommand)
return 0;
COMMAND* found = cmdfind(name, 0);
if(!found)
return 0;
CBCOMMAND old = found->cbCommand;
found->cbCommand = cbCommand;
found->debugonly = debugonly;
return old;
}
/**
\brief Deletes a command from a command list.
\param [in] command_list Command list.
\param name The name of the command to delete.
\return true if the command was deleted.
*/
bool cmddel(const char* name)
{
COMMAND* prev = 0;
COMMAND* found = cmdfind(name, &prev);
if(!found)
return false;
efree(found->name, "cmddel:found->name");
if (found == cmd_list)
{
COMMAND* next = cmd_list->next;
if(next)
{
memcpy(cmd_list, cmd_list->next, sizeof(COMMAND));
cmd_list->next = next->next;
efree(next, "cmddel:next");
}
else
memset(cmd_list, 0, sizeof(COMMAND));
}
else
{
prev->next = found->next;
efree(found, "cmddel:found");
}
return true;
}
/*
command_list: command list
cbUnknownCommand: function to execute when an unknown command was found
cbCommandProvider: function that provides commands (fgets for example), does not return until a command was found
cbCommandFinder: non-default command finder
error_is_fatal: error return of a command callback stops the command processing
*/
/**
\brief Initiates a command loop. This function will not return until a command returns ::STATUS_EXIT.
\param [in] command_list Command list to use for the command lookups.
\param cbUnknownCommand The unknown command callback.
\param cbCommandProvider The command provider callback.
\param cbCommandFinder The command finder callback.
\param error_is_fatal true if commands that return ::STATUS_ERROR terminate the command loop.
\return A CMDRESULT, will always be ::STATUS_EXIT.
*/
CMDRESULT cmdloop(CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal)
{
if(!cbUnknownCommand || !cbCommandProvider)
return STATUS_ERROR;
char command[deflen] = "";
bool bLoop = true;
while(bLoop)
{
if(!cbCommandProvider(command, deflen))
break;
if(strlen(command))
{
strcpy_s(command, StringUtils::Trim(command).c_str());
COMMAND* cmd;
if(!cbCommandFinder) //'clean' command processing
cmd = cmdget(command);
else //'dirty' command processing
cmd = cbCommandFinder(command);
if(!cmd || !cmd->cbCommand) //unknown command
{
char* argv[1];
*argv = command;
CMDRESULT res = cbUnknownCommand(1, argv);
if((error_is_fatal && res == STATUS_ERROR) || res == STATUS_EXIT)
bLoop = false;
}
else
{
if(cmd->debugonly && !DbgIsDebugging())
{
dputs("this command is debug-only");
if(error_is_fatal)
bLoop = false;
}
else
{
Command commandParsed(command);
int argcount = commandParsed.GetArgCount();
char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmdloop:argv");
argv[0] = command;
for(int i = 0; i < argcount; i++)
{
argv[i + 1] = (char*)emalloc(deflen, "cmdloop:argv[i+1]");
*argv[i + 1] = 0;
strcpy_s(argv[i + 1], deflen, commandParsed.GetArg(i).c_str());
}
CMDRESULT res = cmd->cbCommand(argcount + 1, argv);
for(int i = 0; i < argcount; i++)
efree(argv[i + 1], "cmdloop:argv[i+1]");
efree(argv, "cmdloop:argv");
if((error_is_fatal && res == STATUS_ERROR) || res == STATUS_EXIT)
bLoop = false;
}
}
}
}
return STATUS_EXIT;
}
/*
- custom command formatting rules
*/
/**
\brief Query if a string is a valid expression.
\param expression The expression to check.
\return true if the string is a valid expression.
*/
static bool isvalidexpression(const char* expression)
{
duint value;
return valfromstring(expression, &value);
}
/**
\brief Check if a character is a mathematical operator. Used to determine stuff like "a *= b"
\param ch The character to check.
\return true if the character is an operator, false otherwise.
*/
static bool mathisoperator(const char ch)
{
switch(ch)
{
case '*':
case '`':
case '/':
case '%':
case '+':
case '-':
case '<':
case '>':
case '&':
case '^':
case '|':
return true;
default:
return false;
}
}
/**
\brief Special formats a given command. Used as a little hack to support stuff like 'x++' and 'x=y'
\param [in,out] string String to format.
*/
static void specialformat(char* string)
{
int len = (int)strlen(string);
char* found = strstr(string, "=");
char str[deflen] = "";
char backup[deflen] = "";
strcpy_s(backup, string); //create a backup of the string
if(found) //contains =
{
char* a = (found - 1);
*found = 0;
found++;
if(!*found)
{
*found = '=';
return;
}
if(mathisoperator(*a)) //x*=3 -> x=x*3
{
char op = *a;
*a = 0;
if(isvalidexpression(string))
sprintf_s(str, "mov %s,%s%c%s", string, string, op, found);
else
strcpy_s(str, backup);
}
else //x=y
{
if(isvalidexpression(found))
sprintf_s(str, "mov %s,%s", string, found);
else
strcpy_s(str, backup);
}
strcpy_s(string, deflen, str);
}
else if((string[len - 1] == '+' && string[len - 2] == '+') || (string[len - 1] == '-' && string[len - 2] == '-')) //eax++/eax--
{
string[len - 2] = 0;
char op = string[len - 1];
if(isvalidexpression(string))
sprintf_s(str, "mov %s,%s%c1", string, string, op);
else
strcpy_s(str, backup);
strcpy_s(string, deflen, str);
}
}
/*
- 'default' command finder, with some custom rules
*/
/**
\brief Default command finder. It uses specialformat() and mathformat() to make sure the command is optimally checked.
\param [in] cmd_list Command list.
\param [in] command Command name.
\return null if it fails, else a COMMAND*.
*/
COMMAND* cmdfindmain(char* command)
{
COMMAND* cmd = cmdfind(command, 0);
if(!cmd)
{
specialformat(command);
cmd = cmdget(command);
}
return cmd;
}
/**
\brief Directly execute a command.
\param [in,out] cmd_list Command list.
\param cmd The command to execute.
\return A CMDRESULT.
*/
CMDRESULT cmddirectexec(const char* cmd, ...)
{
// Fail on null strings
ASSERT_NONNULL(cmd);
// Don't allow anyone to send in empty strings
if(!cmd || strlen(cmd) <= 0)
return STATUS_ERROR;
char command[deflen];
va_list ap;
va_start(ap, cmd);
_vsnprintf_s(command, _TRUNCATE, cmd, ap);
va_end(ap);
strcpy_s(command, StringUtils::Trim(cmd).c_str());
COMMAND* found = cmdfindmain(command);
if(!found || !found->cbCommand)
return STATUS_ERROR;
if(found->debugonly && !DbgIsDebugging())
return STATUS_ERROR;
Command cmdParsed(command);
int argcount = cmdParsed.GetArgCount();
char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmddirectexec:argv");
argv[0] = command;
for(int i = 0; i < argcount; i++)
{
argv[i + 1] = (char*)emalloc(deflen, "cmddirectexec:argv[i+1]");
*argv[i + 1] = 0;
strcpy_s(argv[i + 1], deflen, cmdParsed.GetArg(i).c_str());
}
CMDRESULT res = found->cbCommand(argcount + 1, argv);
for(int i = 0; i < argcount; i++)
efree(argv[i + 1], "cmddirectexec:argv[i+1]");
efree(argv, "cmddirectexec:argv");
return res;
}
/**
@file command.cpp
@brief Implements the command class.
*/
#include "command.h"
#include "value.h"
#include "console.h"
#include "commandparser.h"
COMMAND* cmd_list = 0;
/**
\brief Finds a ::COMMAND in a command list.
\param [in] command list.
\param name The name of the command to find.
\param [out] Link to the command.
\return null if it fails, else a ::COMMAND*.
*/
COMMAND* cmdfind(const char* name, COMMAND** link)
{
COMMAND* cur = cmd_list;
if(!cur->name)
return 0;
COMMAND* prev = 0;
while(cur)
{
if(arraycontains(cur->name, name))
{
if(link)
*link = prev;
return cur;
}
prev = cur;
cur = cur->next;
}
return 0;
}
/**
\brief Initialize a command list.
\return a ::COMMAND*
*/
COMMAND* cmdinit()
{
cmd_list = (COMMAND*)emalloc(sizeof(COMMAND), "cmdinit:cmd");
memset(cmd_list, 0, sizeof(COMMAND));
return cmd_list;
}
/**
\brief Clear a command list.
\param [in] cmd_list Command list to clear.
*/
void cmdfree()
{
COMMAND* cur = cmd_list;
while(cur)
{
efree(cur->name, "cmdfree:cur->name");
COMMAND* next = cur->next;
efree(cur, "cmdfree:cur");
cur = next;
}
}
/**
\brief Creates a new command and adds it to the list.
\param [in,out] command_list Command list. Cannot be null.
\param name The command name.
\param cbCommand The command callback.
\param debugonly true if the command can only be executed in a debugging context.
\return true if the command was successfully added to the list.
*/
bool cmdnew(const char* name, CBCOMMAND cbCommand, bool debugonly)
{
if (!cmd_list || !cbCommand || !name || !*name || cmdfind(name, 0))
return false;
COMMAND* cmd;
bool nonext = false;
if (!cmd_list->name)
{
cmd = cmd_list;
nonext = true;
}
else
cmd = (COMMAND*)emalloc(sizeof(COMMAND), "cmdnew:cmd");
memset(cmd, 0, sizeof(COMMAND));
cmd->name = (char*)emalloc(strlen(name) + 1, "cmdnew:cmd->name");
strcpy(cmd->name, name);
cmd->cbCommand = cbCommand;
cmd->debugonly = debugonly;
COMMAND* cur = cmd_list;
if(!nonext)
{
while(cur->next)
cur = cur->next;
cur->next = cmd;
}
return true;
}
/**
\brief Gets a ::COMMAND from the command list.
\param [in] command_list Command list.
\param cmd The command to get from the list.
\return null if the command was not found. Otherwise a ::COMMAND*.
*/
COMMAND* cmdget(const char* cmd)
{
char new_cmd[deflen] = "";
strcpy_s(new_cmd, deflen, cmd);
int len = (int)strlen(new_cmd);
int start = 0;
while(new_cmd[start] != ' ' && start < len)
start++;
new_cmd[start] = 0;
COMMAND* found = cmdfind(new_cmd, 0);
if(!found)
return 0;
return found;
}
/**
\brief Sets a new command callback and debugonly property in a command list.
\param [in] command_list Command list.
\param name The name of the command to change.
\param cbCommand The new command callback.
\param debugonly The new debugonly value.
\return The old command callback.
*/
CBCOMMAND cmdset(const char* name, CBCOMMAND cbCommand, bool debugonly)
{
if(!cbCommand)
return 0;
COMMAND* found = cmdfind(name, 0);
if(!found)
return 0;
CBCOMMAND old = found->cbCommand;
found->cbCommand = cbCommand;
found->debugonly = debugonly;
return old;
}
/**
\brief Deletes a command from a command list.
\param [in] command_list Command list.
\param name The name of the command to delete.
\return true if the command was deleted.
*/
bool cmddel(const char* name)
{
COMMAND* prev = 0;
COMMAND* found = cmdfind(name, &prev);
if(!found)
return false;
efree(found->name, "cmddel:found->name");
if (found == cmd_list)
{
COMMAND* next = cmd_list->next;
if(next)
{
memcpy(cmd_list, cmd_list->next, sizeof(COMMAND));
cmd_list->next = next->next;
efree(next, "cmddel:next");
}
else
memset(cmd_list, 0, sizeof(COMMAND));
}
else
{
prev->next = found->next;
efree(found, "cmddel:found");
}
return true;
}
/*
command_list: command list
cbUnknownCommand: function to execute when an unknown command was found
cbCommandProvider: function that provides commands (fgets for example), does not return until a command was found
cbCommandFinder: non-default command finder
error_is_fatal: error return of a command callback stops the command processing
*/
/**
\brief Initiates a command loop. This function will not return until a command returns ::STATUS_EXIT.
\param [in] command_list Command list to use for the command lookups.
\param cbUnknownCommand The unknown command callback.
\param cbCommandProvider The command provider callback.
\param cbCommandFinder The command finder callback.
\param error_is_fatal true if commands that return ::STATUS_ERROR terminate the command loop.
\return A CMDRESULT, will always be ::STATUS_EXIT.
*/
CMDRESULT cmdloop(CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal)
{
if(!cbUnknownCommand || !cbCommandProvider)
return STATUS_ERROR;
char command[deflen] = "";
bool bLoop = true;
while(bLoop)
{
if(!cbCommandProvider(command, deflen))
break;
if(strlen(command))
{
strcpy_s(command, StringUtils::Trim(command).c_str());
COMMAND* cmd;
if(!cbCommandFinder) //'clean' command processing
cmd = cmdget(command);
else //'dirty' command processing
cmd = cbCommandFinder(command);
if(!cmd || !cmd->cbCommand) //unknown command
{
char* argv[1];
*argv = command;
CMDRESULT res = cbUnknownCommand(1, argv);
if((error_is_fatal && res == STATUS_ERROR) || res == STATUS_EXIT)
bLoop = false;
}
else
{
if(cmd->debugonly && !DbgIsDebugging())
{
dputs("this command is debug-only");
if(error_is_fatal)
bLoop = false;
}
else
{
Command commandParsed(command);
int argcount = commandParsed.GetArgCount();
char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmdloop:argv");
argv[0] = command;
for(int i = 0; i < argcount; i++)
{
argv[i + 1] = (char*)emalloc(deflen, "cmdloop:argv[i+1]");
*argv[i + 1] = 0;
strcpy_s(argv[i + 1], deflen, commandParsed.GetArg(i).c_str());
}
CMDRESULT res = cmd->cbCommand(argcount + 1, argv);
for(int i = 0; i < argcount; i++)
efree(argv[i + 1], "cmdloop:argv[i+1]");
efree(argv, "cmdloop:argv");
if((error_is_fatal && res == STATUS_ERROR) || res == STATUS_EXIT)
bLoop = false;
}
}
}
}
return STATUS_EXIT;
}
/*
- custom command formatting rules
*/
/**
\brief Query if a string is a valid expression.
\param expression The expression to check.
\return true if the string is a valid expression.
*/
static bool isvalidexpression(const char* expression)
{
duint value;
return valfromstring(expression, &value);
}
/**
\brief Check if a character is a mathematical operator. Used to determine stuff like "a *= b"
\param ch The character to check.
\return true if the character is an operator, false otherwise.
*/
static bool mathisoperator(const char ch)
{
switch(ch)
{
case '*':
case '`':
case '/':
case '%':
case '+':
case '-':
case '<':
case '>':
case '&':
case '^':
case '|':
return true;
default:
return false;
}
}
/**
\brief Special formats a given command. Used as a little hack to support stuff like 'x++' and 'x=y'
\param [in,out] string String to format.
*/
static void specialformat(char* string)
{
int len = (int)strlen(string);
char* found = strstr(string, "=");
char str[deflen] = "";
char backup[deflen] = "";
strcpy_s(backup, string); //create a backup of the string
if(found) //contains =
{
char* a = (found - 1);
*found = 0;
found++;
if(!*found)
{
*found = '=';
return;
}
if(mathisoperator(*a)) //x*=3 -> x=x*3
{
char op = *a;
*a = 0;
if(isvalidexpression(string))
sprintf_s(str, "mov %s,%s%c%s", string, string, op, found);
else
strcpy_s(str, backup);
}
else //x=y
{
if(isvalidexpression(found))
sprintf_s(str, "mov %s,%s", string, found);
else
strcpy_s(str, backup);
}
strcpy_s(string, deflen, str);
}
else if((string[len - 1] == '+' && string[len - 2] == '+') || (string[len - 1] == '-' && string[len - 2] == '-')) //eax++/eax--
{
string[len - 2] = 0;
char op = string[len - 1];
if(isvalidexpression(string))
sprintf_s(str, "mov %s,%s%c1", string, string, op);
else
strcpy_s(str, backup);
strcpy_s(string, deflen, str);
}
}
/*
- 'default' command finder, with some custom rules
*/
/**
\brief Default command finder. It uses specialformat() and mathformat() to make sure the command is optimally checked.
\param [in] cmd_list Command list.
\param [in] command Command name.
\return null if it fails, else a COMMAND*.
*/
COMMAND* cmdfindmain(char* command)
{
COMMAND* cmd = cmdfind(command, 0);
if(!cmd)
{
specialformat(command);
cmd = cmdget(command);
}
return cmd;
}
/**
\brief Directly execute a command.
\param [in,out] cmd_list Command list.
\param cmd The command to execute.
\return A CMDRESULT.
*/
CMDRESULT cmddirectexec(const char* cmd, ...)
{
// Fail on null strings
ASSERT_NONNULL(cmd);
// Don't allow anyone to send in empty strings
if(!cmd || strlen(cmd) <= 0)
return STATUS_ERROR;
char command[deflen];
va_list ap;
va_start(ap, cmd);
_vsnprintf_s(command, _TRUNCATE, cmd, ap);
va_end(ap);
strcpy_s(command, StringUtils::Trim(cmd).c_str());
COMMAND* found = cmdfindmain(command);
if(!found || !found->cbCommand)
return STATUS_ERROR;
if(found->debugonly && !DbgIsDebugging())
return STATUS_ERROR;
Command cmdParsed(command);
int argcount = cmdParsed.GetArgCount();
char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmddirectexec:argv");
argv[0] = command;
for(int i = 0; i < argcount; i++)
{
argv[i + 1] = (char*)emalloc(deflen, "cmddirectexec:argv[i+1]");
*argv[i + 1] = 0;
strcpy_s(argv[i + 1], deflen, cmdParsed.GetArg(i).c_str());
}
CMDRESULT res = found->cbCommand(argcount + 1, argv);
for(int i = 0; i < argcount; i++)
efree(argv[i + 1], "cmddirectexec:argv[i+1]");
efree(argv, "cmddirectexec:argv");
return res;
}

View File

@ -1,42 +1,42 @@
#ifndef _COMMAND_H
#define _COMMAND_H
#include "_global.h"
//typedefs
struct COMMAND;
enum CMDRESULT
{
STATUS_ERROR = false,
STATUS_CONTINUE = true,
STATUS_EXIT = 2,
STATUS_PAUSE = 3
};
typedef CMDRESULT(*CBCOMMAND)(int, char**);
typedef bool (*CBCOMMANDPROVIDER)(char*, int);
typedef COMMAND* (*CBCOMMANDFINDER)(char*);
struct COMMAND
{
char* name;
CBCOMMAND cbCommand;
bool debugonly;
COMMAND* next;
};
//functions
COMMAND* cmdinit();
void cmdfree();
COMMAND* cmdfind(const char* name, COMMAND** link);
bool cmdnew(const char* name, CBCOMMAND cbCommand, bool debugonly);
COMMAND* cmdget(const char* cmd);
CBCOMMAND cmdset(const char* name, CBCOMMAND cbCommand, bool debugonly);
bool cmddel(const char* name);
CMDRESULT cmdloop(CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal);
COMMAND* cmdfindmain(char* command);
CMDRESULT cmddirectexec(const char* cmd, ...);
#endif // _COMMAND_H
#ifndef _COMMAND_H
#define _COMMAND_H
#include "_global.h"
//typedefs
struct COMMAND;
enum CMDRESULT
{
STATUS_ERROR = false,
STATUS_CONTINUE = true,
STATUS_EXIT = 2,
STATUS_PAUSE = 3
};
typedef CMDRESULT(*CBCOMMAND)(int, char**);
typedef bool (*CBCOMMANDPROVIDER)(char*, int);
typedef COMMAND* (*CBCOMMANDFINDER)(char*);
struct COMMAND
{
char* name;
CBCOMMAND cbCommand;
bool debugonly;
COMMAND* next;
};
//functions
COMMAND* cmdinit();
void cmdfree();
COMMAND* cmdfind(const char* name, COMMAND** link);
bool cmdnew(const char* name, CBCOMMAND cbCommand, bool debugonly);
COMMAND* cmdget(const char* cmd);
CBCOMMAND cmdset(const char* name, CBCOMMAND cbCommand, bool debugonly);
bool cmddel(const char* name);
CMDRESULT cmdloop(CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal);
COMMAND* cmdfindmain(char* command);
CMDRESULT cmddirectexec(const char* cmd, ...);
#endif // _COMMAND_H

View File

@ -1,116 +1,116 @@
#include "commandparser.h"
Command::Command(const String & command)
{
ParseState state = Default;
int len = (int)command.length();
for(int i = 0; i < len; i++)
{
char ch = command[i];
switch(state)
{
case Default:
switch(ch)
{
case '\t':
case ' ':
if(!_tokens.size())
dataFinish();
break;
case ',':
dataFinish();
break;
case '\\':
state = Escaped;
break;
case '\"':
state = Text;
break;
default:
dataAppend(ch);
break;
}
break;
case Escaped:
switch(ch)
{
case '\t':
case ' ':
dataAppend(' ');
break;
case ',':
dataAppend(ch);
break;
case '\"':
dataAppend(ch);
break;
default:
dataAppend('\\');
dataAppend(ch);
break;
}
state = Default;
break;
case Text:
switch(ch)
{
case '\\':
state = TextEscaped;
break;
case '\"':
dataFinish();
state = Default;
break;
default:
dataAppend(ch);
break;
}
break;
case TextEscaped:
switch(ch)
{
case '\"':
dataAppend(ch);
break;
default:
dataAppend('\\');
dataAppend(ch);
break;
}
state = Text;
break;
}
}
if(state == Escaped || state == TextEscaped)
dataAppend('\\');
dataFinish();
}
const String Command::GetText()
{
return _tokens.size() ? _tokens[0] : String();
}
const int Command::GetArgCount()
{
return _tokens.size() ? (int)_tokens.size() - 1 : 0;
}
const String Command::GetArg(int argnum)
{
return (int)_tokens.size() < argnum + 1 ? String() : _tokens[argnum + 1];
}
void Command::dataAppend(const char ch)
{
_data += ch;
}
void Command::dataFinish()
{
if(_data.length())
{
_tokens.push_back(_data);
_data.clear();
}
}
#include "commandparser.h"
Command::Command(const String & command)
{
ParseState state = Default;
int len = (int)command.length();
for(int i = 0; i < len; i++)
{
char ch = command[i];
switch(state)
{
case Default:
switch(ch)
{
case '\t':
case ' ':
if(!_tokens.size())
dataFinish();
break;
case ',':
dataFinish();
break;
case '\\':
state = Escaped;
break;
case '\"':
state = Text;
break;
default:
dataAppend(ch);
break;
}
break;
case Escaped:
switch(ch)
{
case '\t':
case ' ':
dataAppend(' ');
break;
case ',':
dataAppend(ch);
break;
case '\"':
dataAppend(ch);
break;
default:
dataAppend('\\');
dataAppend(ch);
break;
}
state = Default;
break;
case Text:
switch(ch)
{
case '\\':
state = TextEscaped;
break;
case '\"':
dataFinish();
state = Default;
break;
default:
dataAppend(ch);
break;
}
break;
case TextEscaped:
switch(ch)
{
case '\"':
dataAppend(ch);
break;
default:
dataAppend('\\');
dataAppend(ch);
break;
}
state = Text;
break;
}
}
if(state == Escaped || state == TextEscaped)
dataAppend('\\');
dataFinish();
}
const String Command::GetText()
{
return _tokens.size() ? _tokens[0] : String();
}
const int Command::GetArgCount()
{
return _tokens.size() ? (int)_tokens.size() - 1 : 0;
}
const String Command::GetArg(int argnum)
{
return (int)_tokens.size() < argnum + 1 ? String() : _tokens[argnum + 1];
}
void Command::dataAppend(const char ch)
{
_data += ch;
}
void Command::dataFinish()
{
if(_data.length())
{
_tokens.push_back(_data);
_data.clear();
}
}

View File

@ -1,30 +1,30 @@
#ifndef _COMMANDPARSER_H
#define _COMMANDPARSER_H
#include "_global.h"
class Command
{
public:
Command(const String & command);
const String GetText();
const String GetArg(const int argnum);
const int GetArgCount();
private:
String _data;
std::vector<String> _tokens;
enum ParseState
{
Default,
Escaped,
Text,
TextEscaped
};
void dataFinish();
void dataAppend(const char ch);
};
#endif // _COMMANDPARSER_H
#ifndef _COMMANDPARSER_H
#define _COMMANDPARSER_H
#include "_global.h"
class Command
{
public:
Command(const String & command);
const String GetText();
const String GetArg(const int argnum);
const int GetArgCount();
private:
String _data;
std::vector<String> _tokens;
enum ParseState
{
Default,
Escaped,
Text,
TextEscaped
};
void dataFinish();
void dataAppend(const char ch);
};
#endif // _COMMANDPARSER_H

View File

@ -1,236 +1,236 @@
#include "comment.h"
#include "threading.h"
#include "module.h"
#include "memory.h"
std::unordered_map<duint, COMMENTSINFO> comments;
bool CommentSet(duint Address, const char* Text, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// A valid memory address must be supplied
if(!MemIsValidReadPtr(Address))
return false;
// Make sure the string is supplied, within bounds, and not a special delimiter
if(!Text || Text[0] == '\1' || strlen(Text) >= MAX_COMMENT_SIZE - 1)
return false;
// Delete the comment if no text was supplied
if(Text[0] == '\0')
return CommentDelete(Address);
// Fill out the structure
COMMENTSINFO comment;
strcpy_s(comment.text, Text);
ModNameFromAddr(Address, comment.mod, true);
comment.manual = Manual;
comment.addr = Address - ModBaseFromAddr(Address);
// Key generated from module hash
const duint key = ModHashFromAddr(Address);
EXCLUSIVE_ACQUIRE(LockComments);
// Insert if possible, otherwise replace
if(!comments.insert(std::make_pair(key, comment)).second)
comments[key] = comment;
return true;
}
bool CommentGet(duint Address, char* Text)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockComments);
// Get an existing comment and copy the string buffer
auto found = comments.find(ModHashFromAddr(Address));
// Was it found?
if(found == comments.end())
return false;
if(found->second.manual) //autocomment
strcpy_s(Text, MAX_COMMENT_SIZE, found->second.text);
else
sprintf_s(Text, MAX_COMMENT_SIZE, "\1%s", found->second.text);
return true;
}
bool CommentDelete(duint Address)
{
ASSERT_DEBUGGING("Export call");
EXCLUSIVE_ACQUIRE(LockComments);
return (comments.erase(ModHashFromAddr(Address)) > 0);
}
void CommentDelRange(duint Start, duint End)
{
ASSERT_DEBUGGING("Export call");
// Are all comments going to be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
{
CommentClear();
}
else
{
// Make sure 'Start' and 'End' reference the same module
duint moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
// Virtual -> relative offset
Start -= moduleBase;
End -= moduleBase;
EXCLUSIVE_ACQUIRE(LockComments);
for(auto itr = comments.begin(); itr != comments.end();)
{
const auto & currentComment = itr->second;
// Ignore manually set entries
if(currentComment.manual)
{
++itr;
continue;
}
// [Start, End)
if(currentComment.addr >= Start && currentComment.addr < End)
itr = comments.erase(itr);
else
++itr;
}
}
}
void CommentCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockComments);
const JSON jsonComments = json_array();
const JSON jsonAutoComments = json_array();
// Build the JSON array
for(auto & itr : comments)
{
JSON currentComment = json_object();
json_object_set_new(currentComment, "module", json_string(itr.second.mod));
json_object_set_new(currentComment, "address", json_hex(itr.second.addr));
json_object_set_new(currentComment, "text", json_string(itr.second.text));
if(itr.second.manual)
json_array_append_new(jsonComments, currentComment);
else
json_array_append_new(jsonAutoComments, currentComment);
}
// Save to the JSON root
if(json_array_size(jsonComments))
json_object_set(Root, "comments", jsonComments);
if(json_array_size(jsonAutoComments))
json_object_set(Root, "autocomments", jsonAutoComments);
json_decref(jsonComments);
json_decref(jsonAutoComments);
}
void CommentCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockComments);
// Inline lambda to parse each JSON entry
auto AddComments = [](const JSON Object, bool Manual)
{
size_t i;
JSON value;
json_array_foreach(Object, i, value)
{
COMMENTSINFO commentInfo;
memset(&commentInfo, 0, sizeof(COMMENTSINFO));
// Module
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(commentInfo.mod, mod);
// Address/Manual
commentInfo.addr = (duint)json_hex_value(json_object_get(value, "address"));
commentInfo.manual = Manual;
// String value
const char* text = json_string_value(json_object_get(value, "text"));
if(text)
strcpy_s(commentInfo.text, text);
else
{
// Skip blank comments
continue;
}
const duint key = ModHashFromName(commentInfo.mod) + commentInfo.addr;
comments.insert(std::make_pair(key, commentInfo));
}
};
// Remove existing entries
comments.clear();
const JSON jsonComments = json_object_get(Root, "comments");
const JSON jsonAutoComments = json_object_get(Root, "autocomments");
// Load user-set comments
if(jsonComments)
AddComments(jsonComments, true);
// Load auto-set comments
if(jsonAutoComments)
AddComments(jsonAutoComments, false);
}
bool CommentEnum(COMMENTSINFO* List, size_t* Size)
{
ASSERT_DEBUGGING("Command function call");
// At least 1 parameter must be supplied
ASSERT_FALSE(!List && !Size);
SHARED_ACQUIRE(LockComments);
// Check if the user requested size only
if(Size)
{
*Size = comments.size() * sizeof(COMMENTSINFO);
if(!List)
return true;
}
// Populate the returned array
for(auto & itr : comments)
{
*List = itr.second;
List->addr += ModBaseFromName(List->mod);
List++;
}
return true;
}
void CommentClear()
{
EXCLUSIVE_ACQUIRE(LockComments);
comments.clear();
#include "comment.h"
#include "threading.h"
#include "module.h"
#include "memory.h"
std::unordered_map<duint, COMMENTSINFO> comments;
bool CommentSet(duint Address, const char* Text, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// A valid memory address must be supplied
if(!MemIsValidReadPtr(Address))
return false;
// Make sure the string is supplied, within bounds, and not a special delimiter
if(!Text || Text[0] == '\1' || strlen(Text) >= MAX_COMMENT_SIZE - 1)
return false;
// Delete the comment if no text was supplied
if(Text[0] == '\0')
return CommentDelete(Address);
// Fill out the structure
COMMENTSINFO comment;
strcpy_s(comment.text, Text);
ModNameFromAddr(Address, comment.mod, true);
comment.manual = Manual;
comment.addr = Address - ModBaseFromAddr(Address);
// Key generated from module hash
const duint key = ModHashFromAddr(Address);
EXCLUSIVE_ACQUIRE(LockComments);
// Insert if possible, otherwise replace
if(!comments.insert(std::make_pair(key, comment)).second)
comments[key] = comment;
return true;
}
bool CommentGet(duint Address, char* Text)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockComments);
// Get an existing comment and copy the string buffer
auto found = comments.find(ModHashFromAddr(Address));
// Was it found?
if(found == comments.end())
return false;
if(found->second.manual) //autocomment
strcpy_s(Text, MAX_COMMENT_SIZE, found->second.text);
else
sprintf_s(Text, MAX_COMMENT_SIZE, "\1%s", found->second.text);
return true;
}
bool CommentDelete(duint Address)
{
ASSERT_DEBUGGING("Export call");
EXCLUSIVE_ACQUIRE(LockComments);
return (comments.erase(ModHashFromAddr(Address)) > 0);
}
void CommentDelRange(duint Start, duint End)
{
ASSERT_DEBUGGING("Export call");
// Are all comments going to be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
{
CommentClear();
}
else
{
// Make sure 'Start' and 'End' reference the same module
duint moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
// Virtual -> relative offset
Start -= moduleBase;
End -= moduleBase;
EXCLUSIVE_ACQUIRE(LockComments);
for(auto itr = comments.begin(); itr != comments.end();)
{
const auto & currentComment = itr->second;
// Ignore manually set entries
if(currentComment.manual)
{
++itr;
continue;
}
// [Start, End)
if(currentComment.addr >= Start && currentComment.addr < End)
itr = comments.erase(itr);
else
++itr;
}
}
}
void CommentCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockComments);
const JSON jsonComments = json_array();
const JSON jsonAutoComments = json_array();
// Build the JSON array
for(auto & itr : comments)
{
JSON currentComment = json_object();
json_object_set_new(currentComment, "module", json_string(itr.second.mod));
json_object_set_new(currentComment, "address", json_hex(itr.second.addr));
json_object_set_new(currentComment, "text", json_string(itr.second.text));
if(itr.second.manual)
json_array_append_new(jsonComments, currentComment);
else
json_array_append_new(jsonAutoComments, currentComment);
}
// Save to the JSON root
if(json_array_size(jsonComments))
json_object_set(Root, "comments", jsonComments);
if(json_array_size(jsonAutoComments))
json_object_set(Root, "autocomments", jsonAutoComments);
json_decref(jsonComments);
json_decref(jsonAutoComments);
}
void CommentCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockComments);
// Inline lambda to parse each JSON entry
auto AddComments = [](const JSON Object, bool Manual)
{
size_t i;
JSON value;
json_array_foreach(Object, i, value)
{
COMMENTSINFO commentInfo;
memset(&commentInfo, 0, sizeof(COMMENTSINFO));
// Module
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(commentInfo.mod, mod);
// Address/Manual
commentInfo.addr = (duint)json_hex_value(json_object_get(value, "address"));
commentInfo.manual = Manual;
// String value
const char* text = json_string_value(json_object_get(value, "text"));
if(text)
strcpy_s(commentInfo.text, text);
else
{
// Skip blank comments
continue;
}
const duint key = ModHashFromName(commentInfo.mod) + commentInfo.addr;
comments.insert(std::make_pair(key, commentInfo));
}
};
// Remove existing entries
comments.clear();
const JSON jsonComments = json_object_get(Root, "comments");
const JSON jsonAutoComments = json_object_get(Root, "autocomments");
// Load user-set comments
if(jsonComments)
AddComments(jsonComments, true);
// Load auto-set comments
if(jsonAutoComments)
AddComments(jsonAutoComments, false);
}
bool CommentEnum(COMMENTSINFO* List, size_t* Size)
{
ASSERT_DEBUGGING("Command function call");
// At least 1 parameter must be supplied
ASSERT_FALSE(!List && !Size);
SHARED_ACQUIRE(LockComments);
// Check if the user requested size only
if(Size)
{
*Size = comments.size() * sizeof(COMMENTSINFO);
if(!List)
return true;
}
// Populate the returned array
for(auto & itr : comments)
{
*List = itr.second;
List->addr += ModBaseFromName(List->mod);
List++;
}
return true;
}
void CommentClear()
{
EXCLUSIVE_ACQUIRE(LockComments);
comments.clear();
}

View File

@ -1,20 +1,20 @@
#pragma once
#include "_global.h"
struct COMMENTSINFO
{
char mod[MAX_MODULE_SIZE];
duint addr;
char text[MAX_COMMENT_SIZE];
bool manual;
};
bool CommentSet(duint Address, const char* Text, bool Manual);
bool CommentGet(duint Address, char* Text);
bool CommentDelete(duint Address);
void CommentDelRange(duint Start, duint End);
void CommentCacheSave(JSON Root);
void CommentCacheLoad(JSON Root);
bool CommentEnum(COMMENTSINFO* List, size_t* Size);
#pragma once
#include "_global.h"
struct COMMENTSINFO
{
char mod[MAX_MODULE_SIZE];
duint addr;
char text[MAX_COMMENT_SIZE];
bool manual;
};
bool CommentSet(duint Address, const char* Text, bool Manual);
bool CommentGet(duint Address, char* Text);
bool CommentDelete(duint Address);
void CommentDelRange(duint Start, duint End);
void CommentCacheSave(JSON Root);
void CommentCacheLoad(JSON Root);
bool CommentEnum(COMMENTSINFO* List, size_t* Size);
void CommentClear();

View File

@ -1,41 +1,41 @@
/**
\file console.cpp
\brief Implements the console class.
*/
#include "console.h"
/**
\brief Print a line with text, terminated with a newline to the console.
\param text The text to print.
*/
void dputs(const char* Text)
{
dprintf("%s\n", Text);
}
/**
\brief Print a formatted string to the console.
\param format The printf format to use (see documentation of printf for more information).
*/
void dprintf(const char* Format, ...)
{
va_list args;
va_start(args, Format);
dprintf_args(Format, args);
va_end(args);
}
/**
\brief Print a formatted string to the console.
\param format The printf format to use (see documentation of printf for more information).
\param Args The argument buffer passed to the string parser.
*/
void dprintf_args(const char* Format, va_list Args)
{
char buffer[16384];
vsnprintf_s(buffer, _TRUNCATE, Format, Args);
GuiAddLogMessage(buffer);
}
/**
\file console.cpp
\brief Implements the console class.
*/
#include "console.h"
/**
\brief Print a line with text, terminated with a newline to the console.
\param text The text to print.
*/
void dputs(const char* Text)
{
dprintf("%s\n", Text);
}
/**
\brief Print a formatted string to the console.
\param format The printf format to use (see documentation of printf for more information).
*/
void dprintf(const char* Format, ...)
{
va_list args;
va_start(args, Format);
dprintf_args(Format, args);
va_end(args);
}
/**
\brief Print a formatted string to the console.
\param format The printf format to use (see documentation of printf for more information).
\param Args The argument buffer passed to the string parser.
*/
void dprintf_args(const char* Format, va_list Args)
{
char buffer[16384];
vsnprintf_s(buffer, _TRUNCATE, Format, Args);
GuiAddLogMessage(buffer);
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "_global.h"
void dputs(const char* Text);
void dprintf(const char* Format, ...);
#pragma once
#include "_global.h"
void dputs(const char* Text);
void dprintf(const char* Format, ...);
void dprintf_args(const char* Format, va_list Args);

View File

@ -1,445 +1,445 @@
#include "controlflowanalysis.h"
#include "console.h"
#include "module.h"
#include "TitanEngine/TitanEngine.h"
#include "memory.h"
#include "function.h"
ControlFlowAnalysis::ControlFlowAnalysis(duint base, duint size, bool exceptionDirectory) : Analysis(base, size)
{
_functionInfoData = nullptr;
#ifdef _WIN64
// This will only be valid if the address range is within a loaded module
_moduleBase = ModBaseFromAddr(base);
if(exceptionDirectory && _moduleBase != 0)
{
char modulePath[MAX_PATH];
memset(modulePath, 0, sizeof(modulePath));
ModPathFromAddr(_moduleBase, modulePath, ARRAYSIZE(modulePath));
HANDLE fileHandle;
DWORD fileSize;
HANDLE fileMapHandle;
ULONG_PTR fileMapVa;
if(StaticFileLoadW(
StringUtils::Utf8ToUtf16(modulePath).c_str(),
UE_ACCESS_READ,
false,
&fileHandle,
&fileSize,
&fileMapHandle,
&fileMapVa))
{
// Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use
ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET);
_functionInfoSize = (duint)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE);
// Unload the file
StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa);
// Get a copy of the function table
if(virtualOffset)
{
// Read the table into a buffer
_functionInfoData = emalloc(_functionInfoSize);
if(_functionInfoData)
MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize);
}
}
}
#endif //_WIN64
}
ControlFlowAnalysis::~ControlFlowAnalysis()
{
if(_functionInfoData)
efree(_functionInfoData);
}
void ControlFlowAnalysis::Analyse()
{
dputs("Starting analysis...");
DWORD ticks = GetTickCount();
BasicBlockStarts();
dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
BasicBlocks();
dprintf("Basic blocks in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
Functions();
dprintf("Functions in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
FunctionRanges();
dprintf("Function ranges in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
dprintf("Analysis finished!\n");
}
void ControlFlowAnalysis::SetMarkers()
{
FunctionDelRange(_base, _base + _size);
auto size = _functionRanges.size();
for(size_t i = size - 1; i != -1; i--)
{
const auto & range = _functionRanges[i];
FunctionAdd(range.first, range.second, false);
}
/*dprintf("digraph ControlFlow {\n");
int i = 0;
std::map<duint, int> nodeMap;
for(const auto & it : _blocks)
{
const auto & block = it.second;
nodeMap.insert({ block.start, i });
dprintf(" node%u [label=\"s=%p, e=%p, f=%p\"];\n", i, block.start, block.end, block.function);
i++;
}
for(auto it : _blocks)
{
const auto & block = it.second;
int startNode = nodeMap[block.start];
if(block.left)
{
if(nodeMap.count(block.left))
dprintf(" node%u -> node%u;\n", startNode, nodeMap[block.left]);
}
else
{
dprintf(" node%u [shape=point];\n", i);
dprintf(" node%u -> node%u;\n", startNode, i);
i++;
}
if(block.right)
{
if(nodeMap.count(block.right))
dprintf(" node%u -> node%u;\n", startNode, nodeMap[block.right]);
}
else
{
dprintf(" node%u [shape=point];\n", i);
dprintf(" node%u -> node%u;\n", startNode, i);
i++;
}
}
dprintf("}\n");*/
}
void ControlFlowAnalysis::BasicBlockStarts()
{
_blockStarts.insert(_base);
bool bSkipFilling = false;
for(duint i = 0; i < _size;)
{
duint addr = _base + i;
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
{
if(bSkipFilling) //handle filling skip mode
{
if(!_cp.IsFilling()) //do nothing until the filling stopped
{
bSkipFilling = false;
_blockStarts.insert(addr);
}
}
else if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) //RET/INT3 break control flow
{
bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
}
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches
{
duint dest1 = GetReferenceOperand();
duint dest2 = 0;
if(_cp.GetId() != X86_INS_JMP) //unconditional jump
dest2 = addr + _cp.Size();
if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted)
bSkipFilling = true;
if(dest1)
_blockStarts.insert(dest1);
if(dest2)
_blockStarts.insert(dest2);
}
else if(_cp.InGroup(CS_GRP_CALL))
{
duint dest1 = GetReferenceOperand();
if(dest1)
{
_blockStarts.insert(dest1);
_functionStarts.insert(dest1);
}
}
else
{
duint dest1 = GetReferenceOperand();
if(dest1)
_blockStarts.insert(dest1);
}
i += _cp.Size();
}
else
i++;
}
}
void ControlFlowAnalysis::BasicBlocks()
{
for(auto i = _blockStarts.begin(); i != _blockStarts.end(); ++i)
{
duint start = *i;
if(!IsValidAddress(start))
continue;
duint nextStart = _base + _size;
auto next = std::next(i);
if(next != _blockStarts.end())
nextStart = *next;
for(duint addr = start, prevaddr = 0; addr < _base + _size;)
{
prevaddr = addr;
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
{
if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3)
{
insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block
break;
}
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())
{
duint dest1 = GetReferenceOperand();
duint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0;
insertBlock(BasicBlock(start, addr, dest1, dest2));
insertParent(dest1, start);
insertParent(dest2, start);
break;
}
addr += _cp.Size();
}
else
addr++;
if(addr == nextStart) //special case handling overlapping blocks
{
insertBlock(BasicBlock(start, prevaddr, 0, nextStart));
insertParent(nextStart, start);
break;
}
}
}
_blockStarts.clear();
#ifdef _WIN64
int count = 0;
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
{
const duint funcAddr = _moduleBase + Function->BeginAddress;
const duint funcEnd = _moduleBase + Function->EndAddress;
// If within limits...
if(funcAddr >= _base && funcAddr < _base + _size)
_functionStarts.insert(funcAddr);
count++;
return true;
});
dprintf("%u functions from the exception directory...\n", count);
#endif // _WIN64
dprintf("%u basic blocks, %u function starts detected...\n", _blocks.size(), _functionStarts.size());
}
void ControlFlowAnalysis::Functions()
{
typedef std::pair<BasicBlock*, UintSet*> DelayedBlock;
std::vector<DelayedBlock> delayedBlocks;
for(auto & it : _blocks)
{
BasicBlock* block = &it.second;
UintSet* parents = findParents(block->start);
if(!block->function)
{
if(!parents || _functionStarts.count(block->start)) //no parents = function start
{
duint functionStart = block->start;
block->function = functionStart;
UintSet functionBlocks;
functionBlocks.insert(functionStart);
_functions[functionStart] = functionBlocks;
}
else //in function
{
duint function = findFunctionStart(block, parents);
if(!function) //this happens with loops / unreferenced blocks sometimes
delayedBlocks.push_back(DelayedBlock(block, parents));
else
block->function = function;
}
}
else
DebugBreak(); //this should not happen
}
int delayedCount = (int)delayedBlocks.size();
dprintf("%u/%u delayed blocks...\n", delayedCount, _blocks.size());
int resolved = 0;
for(auto & delayedBlock : delayedBlocks)
{
BasicBlock* block = delayedBlock.first;
UintSet* parents = delayedBlock.second;
duint function = findFunctionStart(block, parents);
if(!function)
{
continue;
/*dprintf("unresolved block %s\n", blockToString(block).c_str());
if(parents)
{
dprintf("parents:\n");
for(auto parent : *parents)
dprintf(" %s\n", blockToString(findBlock(parent)).c_str());
}
else
dprintf("parents: null");
dprintf("left: %s\n", blockToString(findBlock(block->left)).c_str());
dprintf("right: %s\n", blockToString(findBlock(block->right)).c_str());
return;*/
}
block->function = function;
resolved++;
}
dprintf("%u/%u delayed blocks resolved (%u/%u still left, probably unreferenced functions)\n", resolved, delayedCount, delayedCount - resolved, _blocks.size());
int unreferencedCount = 0;
for(const auto & block : _blocks)
{
auto found = _functions.find(block.second.function);
if(found == _functions.end()) //unreferenced block
{
unreferencedCount++;
continue;
}
found->second.insert(block.second.start);
}
dprintf("%u/%u unreferenced blocks\n", unreferencedCount, _blocks.size());
dprintf("%u functions found!\n", _functions.size());
}
void ControlFlowAnalysis::FunctionRanges()
{
//iterate over the functions and then find the deepest block = function end
for(const auto & function : _functions)
{
duint start = function.first;
duint end = start;
for(auto blockstart : function.second)
{
BasicBlock* block = this->findBlock(blockstart);
if(!block)
DebugBreak(); //this shouldn't happen
if(block->end > end)
end = block->end;
}
_functionRanges.push_back({ start, end });
}
}
void ControlFlowAnalysis::insertBlock(BasicBlock block)
{
if(_blocks.find(block.start) != _blocks.end())
DebugBreak();
_blocks[block.start] = block;
}
ControlFlowAnalysis::BasicBlock* ControlFlowAnalysis::findBlock(duint start)
{
if(!start)
return nullptr;
auto found = _blocks.find(start);
return found != _blocks.end() ? &found->second : nullptr;
}
void ControlFlowAnalysis::insertParent(duint child, duint parent)
{
if(!child || !parent)
return;
auto found = _parentMap.find(child);
if(found == _parentMap.end())
{
UintSet parents;
parents.insert(parent);
_parentMap[child] = parents;
}
else
found->second.insert(parent);
}
ControlFlowAnalysis::UintSet* ControlFlowAnalysis::findParents(duint child)
{
if(!child)
return nullptr;
auto found = _parentMap.find(child);
return found != _parentMap.end() ? &found->second : nullptr;
}
duint ControlFlowAnalysis::findFunctionStart(BasicBlock* block, ControlFlowAnalysis::UintSet* parents)
{
if(!block)
return 0;
if(block->function)
return block->function;
BasicBlock* left = findBlock(block->left);
if(left && left->function)
return left->function;
BasicBlock* right = findBlock(block->right);
if(right && right->function)
return right->function;
for(auto start : *parents)
{
BasicBlock* parent = findBlock(start);
if(parent->function)
return parent->function;
}
return 0;
}
String ControlFlowAnalysis::blockToString(BasicBlock* block)
{
if(!block)
return String("null");
return block->toString();
}
duint ControlFlowAnalysis::GetReferenceOperand()
{
for(int i = 0; i < _cp.x86().op_count; i++)
{
const cs_x86_op & operand = _cp.x86().operands[i];
if(operand.type == X86_OP_IMM)
{
duint dest = (duint)operand.imm;
if(dest >= _base && dest < _base + _size)
return dest;
}
}
return 0;
}
#ifdef _WIN64
void ControlFlowAnalysis::EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback)
{
if(!_functionInfoData)
return;
// Get the table pointer and size
auto functionTable = (PRUNTIME_FUNCTION)_functionInfoData;
duint totalCount = (_functionInfoSize / sizeof(RUNTIME_FUNCTION));
// Enumerate each entry
for(ULONG i = 0; i < totalCount; i++)
{
if(!Callback(&functionTable[i]))
break;
}
}
#include "controlflowanalysis.h"
#include "console.h"
#include "module.h"
#include "TitanEngine/TitanEngine.h"
#include "memory.h"
#include "function.h"
ControlFlowAnalysis::ControlFlowAnalysis(duint base, duint size, bool exceptionDirectory) : Analysis(base, size)
{
_functionInfoData = nullptr;
#ifdef _WIN64
// This will only be valid if the address range is within a loaded module
_moduleBase = ModBaseFromAddr(base);
if(exceptionDirectory && _moduleBase != 0)
{
char modulePath[MAX_PATH];
memset(modulePath, 0, sizeof(modulePath));
ModPathFromAddr(_moduleBase, modulePath, ARRAYSIZE(modulePath));
HANDLE fileHandle;
DWORD fileSize;
HANDLE fileMapHandle;
ULONG_PTR fileMapVa;
if(StaticFileLoadW(
StringUtils::Utf8ToUtf16(modulePath).c_str(),
UE_ACCESS_READ,
false,
&fileHandle,
&fileSize,
&fileMapHandle,
&fileMapVa))
{
// Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use
ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET);
_functionInfoSize = (duint)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE);
// Unload the file
StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa);
// Get a copy of the function table
if(virtualOffset)
{
// Read the table into a buffer
_functionInfoData = emalloc(_functionInfoSize);
if(_functionInfoData)
MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize);
}
}
}
#endif //_WIN64
}
ControlFlowAnalysis::~ControlFlowAnalysis()
{
if(_functionInfoData)
efree(_functionInfoData);
}
void ControlFlowAnalysis::Analyse()
{
dputs("Starting analysis...");
DWORD ticks = GetTickCount();
BasicBlockStarts();
dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
BasicBlocks();
dprintf("Basic blocks in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
Functions();
dprintf("Functions in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
FunctionRanges();
dprintf("Function ranges in %ums!\n", GetTickCount() - ticks);
ticks = GetTickCount();
dprintf("Analysis finished!\n");
}
void ControlFlowAnalysis::SetMarkers()
{
FunctionDelRange(_base, _base + _size);
auto size = _functionRanges.size();
for(size_t i = size - 1; i != -1; i--)
{
const auto & range = _functionRanges[i];
FunctionAdd(range.first, range.second, false);
}
/*dprintf("digraph ControlFlow {\n");
int i = 0;
std::map<duint, int> nodeMap;
for(const auto & it : _blocks)
{
const auto & block = it.second;
nodeMap.insert({ block.start, i });
dprintf(" node%u [label=\"s=%p, e=%p, f=%p\"];\n", i, block.start, block.end, block.function);
i++;
}
for(auto it : _blocks)
{
const auto & block = it.second;
int startNode = nodeMap[block.start];
if(block.left)
{
if(nodeMap.count(block.left))
dprintf(" node%u -> node%u;\n", startNode, nodeMap[block.left]);
}
else
{
dprintf(" node%u [shape=point];\n", i);
dprintf(" node%u -> node%u;\n", startNode, i);
i++;
}
if(block.right)
{
if(nodeMap.count(block.right))
dprintf(" node%u -> node%u;\n", startNode, nodeMap[block.right]);
}
else
{
dprintf(" node%u [shape=point];\n", i);
dprintf(" node%u -> node%u;\n", startNode, i);
i++;
}
}
dprintf("}\n");*/
}
void ControlFlowAnalysis::BasicBlockStarts()
{
_blockStarts.insert(_base);
bool bSkipFilling = false;
for(duint i = 0; i < _size;)
{
duint addr = _base + i;
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
{
if(bSkipFilling) //handle filling skip mode
{
if(!_cp.IsFilling()) //do nothing until the filling stopped
{
bSkipFilling = false;
_blockStarts.insert(addr);
}
}
else if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) //RET/INT3 break control flow
{
bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
}
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches
{
duint dest1 = GetReferenceOperand();
duint dest2 = 0;
if(_cp.GetId() != X86_INS_JMP) //unconditional jump
dest2 = addr + _cp.Size();
if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted)
bSkipFilling = true;
if(dest1)
_blockStarts.insert(dest1);
if(dest2)
_blockStarts.insert(dest2);
}
else if(_cp.InGroup(CS_GRP_CALL))
{
duint dest1 = GetReferenceOperand();
if(dest1)
{
_blockStarts.insert(dest1);
_functionStarts.insert(dest1);
}
}
else
{
duint dest1 = GetReferenceOperand();
if(dest1)
_blockStarts.insert(dest1);
}
i += _cp.Size();
}
else
i++;
}
}
void ControlFlowAnalysis::BasicBlocks()
{
for(auto i = _blockStarts.begin(); i != _blockStarts.end(); ++i)
{
duint start = *i;
if(!IsValidAddress(start))
continue;
duint nextStart = _base + _size;
auto next = std::next(i);
if(next != _blockStarts.end())
nextStart = *next;
for(duint addr = start, prevaddr = 0; addr < _base + _size;)
{
prevaddr = addr;
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
{
if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3)
{
insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block
break;
}
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())
{
duint dest1 = GetReferenceOperand();
duint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0;
insertBlock(BasicBlock(start, addr, dest1, dest2));
insertParent(dest1, start);
insertParent(dest2, start);
break;
}
addr += _cp.Size();
}
else
addr++;
if(addr == nextStart) //special case handling overlapping blocks
{
insertBlock(BasicBlock(start, prevaddr, 0, nextStart));
insertParent(nextStart, start);
break;
}
}
}
_blockStarts.clear();
#ifdef _WIN64
int count = 0;
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
{
const duint funcAddr = _moduleBase + Function->BeginAddress;
const duint funcEnd = _moduleBase + Function->EndAddress;
// If within limits...
if(funcAddr >= _base && funcAddr < _base + _size)
_functionStarts.insert(funcAddr);
count++;
return true;
});
dprintf("%u functions from the exception directory...\n", count);
#endif // _WIN64
dprintf("%u basic blocks, %u function starts detected...\n", _blocks.size(), _functionStarts.size());
}
void ControlFlowAnalysis::Functions()
{
typedef std::pair<BasicBlock*, UintSet*> DelayedBlock;
std::vector<DelayedBlock> delayedBlocks;
for(auto & it : _blocks)
{
BasicBlock* block = &it.second;
UintSet* parents = findParents(block->start);
if(!block->function)
{
if(!parents || _functionStarts.count(block->start)) //no parents = function start
{
duint functionStart = block->start;
block->function = functionStart;
UintSet functionBlocks;
functionBlocks.insert(functionStart);
_functions[functionStart] = functionBlocks;
}
else //in function
{
duint function = findFunctionStart(block, parents);
if(!function) //this happens with loops / unreferenced blocks sometimes
delayedBlocks.push_back(DelayedBlock(block, parents));
else
block->function = function;
}
}
else
DebugBreak(); //this should not happen
}
int delayedCount = (int)delayedBlocks.size();
dprintf("%u/%u delayed blocks...\n", delayedCount, _blocks.size());
int resolved = 0;
for(auto & delayedBlock : delayedBlocks)
{
BasicBlock* block = delayedBlock.first;
UintSet* parents = delayedBlock.second;
duint function = findFunctionStart(block, parents);
if(!function)
{
continue;
/*dprintf("unresolved block %s\n", blockToString(block).c_str());
if(parents)
{
dprintf("parents:\n");
for(auto parent : *parents)
dprintf(" %s\n", blockToString(findBlock(parent)).c_str());
}
else
dprintf("parents: null");
dprintf("left: %s\n", blockToString(findBlock(block->left)).c_str());
dprintf("right: %s\n", blockToString(findBlock(block->right)).c_str());
return;*/
}
block->function = function;
resolved++;
}
dprintf("%u/%u delayed blocks resolved (%u/%u still left, probably unreferenced functions)\n", resolved, delayedCount, delayedCount - resolved, _blocks.size());
int unreferencedCount = 0;
for(const auto & block : _blocks)
{
auto found = _functions.find(block.second.function);
if(found == _functions.end()) //unreferenced block
{
unreferencedCount++;
continue;
}
found->second.insert(block.second.start);
}
dprintf("%u/%u unreferenced blocks\n", unreferencedCount, _blocks.size());
dprintf("%u functions found!\n", _functions.size());
}
void ControlFlowAnalysis::FunctionRanges()
{
//iterate over the functions and then find the deepest block = function end
for(const auto & function : _functions)
{
duint start = function.first;
duint end = start;
for(auto blockstart : function.second)
{
BasicBlock* block = this->findBlock(blockstart);
if(!block)
DebugBreak(); //this shouldn't happen
if(block->end > end)
end = block->end;
}
_functionRanges.push_back({ start, end });
}
}
void ControlFlowAnalysis::insertBlock(BasicBlock block)
{
if(_blocks.find(block.start) != _blocks.end())
DebugBreak();
_blocks[block.start] = block;
}
ControlFlowAnalysis::BasicBlock* ControlFlowAnalysis::findBlock(duint start)
{
if(!start)
return nullptr;
auto found = _blocks.find(start);
return found != _blocks.end() ? &found->second : nullptr;
}
void ControlFlowAnalysis::insertParent(duint child, duint parent)
{
if(!child || !parent)
return;
auto found = _parentMap.find(child);
if(found == _parentMap.end())
{
UintSet parents;
parents.insert(parent);
_parentMap[child] = parents;
}
else
found->second.insert(parent);
}
ControlFlowAnalysis::UintSet* ControlFlowAnalysis::findParents(duint child)
{
if(!child)
return nullptr;
auto found = _parentMap.find(child);
return found != _parentMap.end() ? &found->second : nullptr;
}
duint ControlFlowAnalysis::findFunctionStart(BasicBlock* block, ControlFlowAnalysis::UintSet* parents)
{
if(!block)
return 0;
if(block->function)
return block->function;
BasicBlock* left = findBlock(block->left);
if(left && left->function)
return left->function;
BasicBlock* right = findBlock(block->right);
if(right && right->function)
return right->function;
for(auto start : *parents)
{
BasicBlock* parent = findBlock(start);
if(parent->function)
return parent->function;
}
return 0;
}
String ControlFlowAnalysis::blockToString(BasicBlock* block)
{
if(!block)
return String("null");
return block->toString();
}
duint ControlFlowAnalysis::GetReferenceOperand()
{
for(int i = 0; i < _cp.x86().op_count; i++)
{
const cs_x86_op & operand = _cp.x86().operands[i];
if(operand.type == X86_OP_IMM)
{
duint dest = (duint)operand.imm;
if(dest >= _base && dest < _base + _size)
return dest;
}
}
return 0;
}
#ifdef _WIN64
void ControlFlowAnalysis::EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback)
{
if(!_functionInfoData)
return;
// Get the table pointer and size
auto functionTable = (PRUNTIME_FUNCTION)_functionInfoData;
duint totalCount = (_functionInfoSize / sizeof(RUNTIME_FUNCTION));
// Enumerate each entry
for(ULONG i = 0; i < totalCount; i++)
{
if(!Callback(&functionTable[i]))
break;
}
}
#endif // _WIN64

View File

@ -1,79 +1,79 @@
#ifndef _CONTROLFLOWANALYSIS_H
#define _CONTROLFLOWANALYSIS_H
#include "_global.h"
#include "analysis.h"
#include "addrinfo.h"
#include <functional>
class ControlFlowAnalysis : public Analysis
{
public:
explicit ControlFlowAnalysis(duint base, duint size, bool exceptionDirectory);
~ControlFlowAnalysis();
void Analyse() override;
void SetMarkers() override;
private:
struct BasicBlock
{
duint start;
duint end;
duint left;
duint right;
duint function;
BasicBlock()
{
this->start = 0;
this->end = 0;
this->left = 0;
this->right = 0;
this->function = 0;
}
BasicBlock(duint start, duint end, duint left, duint right)
{
this->start = start;
this->end = end;
this->left = min(left, right);
this->right = max(left, right);
this->function = 0;
}
String toString()
{
return StringUtils::sprintf("start:%p,end:%p,left:%p,right:%p,func:%p", start, end, left, right, function);
}
};
typedef std::set<duint> UintSet;
duint _moduleBase;
duint _functionInfoSize;
void* _functionInfoData;
UintSet _blockStarts;
UintSet _functionStarts;
std::map<duint, BasicBlock> _blocks; //start of block -> block
std::map<duint, UintSet> _parentMap; //start child -> parents
std::map<duint, UintSet> _functions; //function start -> function block starts
std::vector<Range> _functionRanges; //function start -> function range TODO: smarter stuff with overlapping ranges
void BasicBlockStarts();
void BasicBlocks();
void Functions();
void FunctionRanges();
void insertBlock(BasicBlock block);
BasicBlock* findBlock(duint start);
void insertParent(duint child, duint parent);
UintSet* findParents(duint child);
duint findFunctionStart(BasicBlock* block, UintSet* parents);
String blockToString(BasicBlock* block);
duint GetReferenceOperand();
#ifdef _WIN64
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
#endif // _WIN64
};
#ifndef _CONTROLFLOWANALYSIS_H
#define _CONTROLFLOWANALYSIS_H
#include "_global.h"
#include "analysis.h"
#include "addrinfo.h"
#include <functional>
class ControlFlowAnalysis : public Analysis
{
public:
explicit ControlFlowAnalysis(duint base, duint size, bool exceptionDirectory);
~ControlFlowAnalysis();
void Analyse() override;
void SetMarkers() override;
private:
struct BasicBlock
{
duint start;
duint end;
duint left;
duint right;
duint function;
BasicBlock()
{
this->start = 0;
this->end = 0;
this->left = 0;
this->right = 0;
this->function = 0;
}
BasicBlock(duint start, duint end, duint left, duint right)
{
this->start = start;
this->end = end;
this->left = min(left, right);
this->right = max(left, right);
this->function = 0;
}
String toString()
{
return StringUtils::sprintf("start:%p,end:%p,left:%p,right:%p,func:%p", start, end, left, right, function);
}
};
typedef std::set<duint> UintSet;
duint _moduleBase;
duint _functionInfoSize;
void* _functionInfoData;
UintSet _blockStarts;
UintSet _functionStarts;
std::map<duint, BasicBlock> _blocks; //start of block -> block
std::map<duint, UintSet> _parentMap; //start child -> parents
std::map<duint, UintSet> _functions; //function start -> function block starts
std::vector<Range> _functionRanges; //function start -> function range TODO: smarter stuff with overlapping ranges
void BasicBlockStarts();
void BasicBlocks();
void Functions();
void FunctionRanges();
void insertBlock(BasicBlock block);
BasicBlock* findBlock(duint start);
void insertParent(duint child, duint parent);
UintSet* findParents(duint child);
duint findFunctionStart(BasicBlock* block, UintSet* parents);
String blockToString(BasicBlock* block);
duint GetReferenceOperand();
#ifdef _WIN64
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
#endif // _WIN64
};
#endif //_CONTROLFLOWANALYSIS_H

View File

@ -1,235 +1,235 @@
/**
@file database.cpp
@brief Implements runtime database saving and loading.
*/
#include "lz4\lz4file.h"
#include "console.h"
#include "breakpoint.h"
#include "patches.h"
#include "comment.h"
#include "label.h"
#include "bookmark.h"
#include "function.h"
#include "loop.h"
/**
\brief Directory where program databases are stored (usually in \db). UTF-8 encoding.
*/
char dbbasepath[deflen];
/**
\brief Path of the current program database. UTF-8 encoding.
*/
char dbpath[deflen];
void DBSave()
{
dprintf("Saving database...");
DWORD ticks = GetTickCount();
JSON root = json_object();
CommentCacheSave(root);
LabelCacheSave(root);
BookmarkCacheSave(root);
FunctionCacheSave(root);
LoopCacheSave(root);
BpCacheSave(root);
//save notes
char* text = nullptr;
GuiGetDebuggeeNotes(&text);
if (text)
{
json_object_set_new(root, "notes", json_string(text));
BridgeFree(text);
}
GuiSetDebuggeeNotes("");
WString wdbpath = StringUtils::Utf8ToUtf16(dbpath);
if (json_object_size(root))
{
Handle hFile = CreateFileW(wdbpath.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (!hFile)
{
dputs("\nFailed to open database for writing!");
json_decref(root); //free root
return;
}
SetEndOfFile(hFile);
char* jsonText = json_dumps(root, JSON_INDENT(4));
DWORD written = 0;
if (!WriteFile(hFile, jsonText, (DWORD)strlen(jsonText), &written, 0))
{
json_free(jsonText);
dputs("\nFailed to write database file!");
json_decref(root); //free root
return;
}
hFile.Close();
json_free(jsonText);
if (!settingboolget("Engine", "DisableDatabaseCompression"))
LZ4_compress_fileW(wdbpath.c_str(), wdbpath.c_str());
}
else //remove database when nothing is in there
DeleteFileW(wdbpath.c_str());
dprintf("%ums\n", GetTickCount() - ticks);
json_decref(root); //free root
}
void DBLoad()
{
// If the file doesn't exist, there is no DB to load
if (!FileExists(dbpath))
return;
dprintf("Loading database...");
DWORD ticks = GetTickCount();
// Multi-byte (UTF8) file path converted to UTF16
WString databasePathW = StringUtils::Utf8ToUtf16(dbpath);
// Decompress the file if compression was enabled
bool useCompression = !settingboolget("Engine", "DisableDatabaseCompression");
LZ4_STATUS lzmaStatus = LZ4_INVALID_ARCHIVE;
{
lzmaStatus = LZ4_decompress_fileW(databasePathW.c_str(), databasePathW.c_str());
// Check return code
if (useCompression && lzmaStatus != LZ4_SUCCESS && lzmaStatus != LZ4_INVALID_ARCHIVE)
{
dputs("\nInvalid database file!");
return;
}
}
// Read the database file
Handle hFile = CreateFileW(databasePathW.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (!hFile)
{
dputs("\nFailed to open database file!");
return;
}
unsigned int jsonFileSize = GetFileSize(hFile, 0);
if (!jsonFileSize)
{
dputs("\nEmpty database file!");
return;
}
Memory<char*> jsonText(jsonFileSize + 1);
DWORD read = 0;
if (!ReadFile(hFile, jsonText(), jsonFileSize, &read, 0))
{
dputs("\nFailed to read database file!");
return;
}
hFile.Close();
// Deserialize JSON
JSON root = json_loads(jsonText(), 0, 0);
if (lzmaStatus != LZ4_INVALID_ARCHIVE && useCompression)
LZ4_compress_fileW(databasePathW.c_str(), databasePathW.c_str());
// Validate JSON load status
if (!root)
{
dputs("\nInvalid database file (JSON)!");
return;
}
// Finally load all structures
CommentCacheLoad(root);
LabelCacheLoad(root);
BookmarkCacheLoad(root);
FunctionCacheLoad(root);
LoopCacheLoad(root);
BpCacheLoad(root);
// Load notes
const char* text = json_string_value(json_object_get(root, "notes"));
GuiSetDebuggeeNotes(text);
// Free root
json_decref(root);
dprintf("%ums\n", GetTickCount() - ticks);
}
void DBClose()
{
DBSave();
CommentClear();
LabelClear();
BookmarkClear();
FunctionClear();
LoopClear();
BpClear();
PatchClear();
}
void DBSetPath(const char *Directory, const char *ModulePath)
{
// Initialize directory if it was only supplied
if (Directory)
{
ASSERT_TRUE(strlen(Directory) > 0);
// Copy to global
strcpy_s(dbbasepath, Directory);
// Create directory
if (!CreateDirectoryW(StringUtils::Utf8ToUtf16(Directory).c_str(), nullptr))
{
if (GetLastError() != ERROR_ALREADY_EXISTS)
dprintf("Warning: Failed to create database folder '%s'. Path may be read only.\n", Directory);
}
}
// The database file path may be relative (dbbasepath) or a full path
if (ModulePath)
{
ASSERT_TRUE(strlen(ModulePath) > 0);
#ifdef _WIN64
const char *dbType = "dd64";
#else
const char *dbType = "dd32";
#endif // _WIN64
// Get the module name and directory
char dbName[deflen];
char fileDir[deflen];
{
// Dir <- file path
strcpy_s(fileDir, ModulePath);
// Find the last instance of a path delimiter (slash)
char* fileStart = strrchr(fileDir, '\\');
if (fileStart)
{
strcpy_s(dbName, fileStart + 1);
fileStart[0] = '\0';
}
else
{
// Directory or file with no extension
strcpy_s(dbName, fileDir);
}
}
if (settingboolget("Engine", "SaveDatabaseInProgramDirectory"))
{
// Absolute path in the program directory
sprintf_s(dbpath, "%s\\%s.%s", fileDir, dbName, dbType);
}
else
{
// Relative path in debugger directory
sprintf_s(dbpath, "%s\\%s.%s", dbbasepath, dbName, dbType);
}
dprintf("Database file: %s\n", dbpath);
}
/**
@file database.cpp
@brief Implements runtime database saving and loading.
*/
#include "lz4\lz4file.h"
#include "console.h"
#include "breakpoint.h"
#include "patches.h"
#include "comment.h"
#include "label.h"
#include "bookmark.h"
#include "function.h"
#include "loop.h"
/**
\brief Directory where program databases are stored (usually in \db). UTF-8 encoding.
*/
char dbbasepath[deflen];
/**
\brief Path of the current program database. UTF-8 encoding.
*/
char dbpath[deflen];
void DBSave()
{
dprintf("Saving database...");
DWORD ticks = GetTickCount();
JSON root = json_object();
CommentCacheSave(root);
LabelCacheSave(root);
BookmarkCacheSave(root);
FunctionCacheSave(root);
LoopCacheSave(root);
BpCacheSave(root);
//save notes
char* text = nullptr;
GuiGetDebuggeeNotes(&text);
if (text)
{
json_object_set_new(root, "notes", json_string(text));
BridgeFree(text);
}
GuiSetDebuggeeNotes("");
WString wdbpath = StringUtils::Utf8ToUtf16(dbpath);
if (json_object_size(root))
{
Handle hFile = CreateFileW(wdbpath.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (!hFile)
{
dputs("\nFailed to open database for writing!");
json_decref(root); //free root
return;
}
SetEndOfFile(hFile);
char* jsonText = json_dumps(root, JSON_INDENT(4));
DWORD written = 0;
if (!WriteFile(hFile, jsonText, (DWORD)strlen(jsonText), &written, 0))
{
json_free(jsonText);
dputs("\nFailed to write database file!");
json_decref(root); //free root
return;
}
hFile.Close();
json_free(jsonText);
if (!settingboolget("Engine", "DisableDatabaseCompression"))
LZ4_compress_fileW(wdbpath.c_str(), wdbpath.c_str());
}
else //remove database when nothing is in there
DeleteFileW(wdbpath.c_str());
dprintf("%ums\n", GetTickCount() - ticks);
json_decref(root); //free root
}
void DBLoad()
{
// If the file doesn't exist, there is no DB to load
if (!FileExists(dbpath))
return;
dprintf("Loading database...");
DWORD ticks = GetTickCount();
// Multi-byte (UTF8) file path converted to UTF16
WString databasePathW = StringUtils::Utf8ToUtf16(dbpath);
// Decompress the file if compression was enabled
bool useCompression = !settingboolget("Engine", "DisableDatabaseCompression");
LZ4_STATUS lzmaStatus = LZ4_INVALID_ARCHIVE;
{
lzmaStatus = LZ4_decompress_fileW(databasePathW.c_str(), databasePathW.c_str());
// Check return code
if (useCompression && lzmaStatus != LZ4_SUCCESS && lzmaStatus != LZ4_INVALID_ARCHIVE)
{
dputs("\nInvalid database file!");
return;
}
}
// Read the database file
Handle hFile = CreateFileW(databasePathW.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (!hFile)
{
dputs("\nFailed to open database file!");
return;
}
unsigned int jsonFileSize = GetFileSize(hFile, 0);
if (!jsonFileSize)
{
dputs("\nEmpty database file!");
return;
}
Memory<char*> jsonText(jsonFileSize + 1);
DWORD read = 0;
if (!ReadFile(hFile, jsonText(), jsonFileSize, &read, 0))
{
dputs("\nFailed to read database file!");
return;
}
hFile.Close();
// Deserialize JSON
JSON root = json_loads(jsonText(), 0, 0);
if (lzmaStatus != LZ4_INVALID_ARCHIVE && useCompression)
LZ4_compress_fileW(databasePathW.c_str(), databasePathW.c_str());
// Validate JSON load status
if (!root)
{
dputs("\nInvalid database file (JSON)!");
return;
}
// Finally load all structures
CommentCacheLoad(root);
LabelCacheLoad(root);
BookmarkCacheLoad(root);
FunctionCacheLoad(root);
LoopCacheLoad(root);
BpCacheLoad(root);
// Load notes
const char* text = json_string_value(json_object_get(root, "notes"));
GuiSetDebuggeeNotes(text);
// Free root
json_decref(root);
dprintf("%ums\n", GetTickCount() - ticks);
}
void DBClose()
{
DBSave();
CommentClear();
LabelClear();
BookmarkClear();
FunctionClear();
LoopClear();
BpClear();
PatchClear();
}
void DBSetPath(const char *Directory, const char *ModulePath)
{
// Initialize directory if it was only supplied
if (Directory)
{
ASSERT_TRUE(strlen(Directory) > 0);
// Copy to global
strcpy_s(dbbasepath, Directory);
// Create directory
if (!CreateDirectoryW(StringUtils::Utf8ToUtf16(Directory).c_str(), nullptr))
{
if (GetLastError() != ERROR_ALREADY_EXISTS)
dprintf("Warning: Failed to create database folder '%s'. Path may be read only.\n", Directory);
}
}
// The database file path may be relative (dbbasepath) or a full path
if (ModulePath)
{
ASSERT_TRUE(strlen(ModulePath) > 0);
#ifdef _WIN64
const char *dbType = "dd64";
#else
const char *dbType = "dd32";
#endif // _WIN64
// Get the module name and directory
char dbName[deflen];
char fileDir[deflen];
{
// Dir <- file path
strcpy_s(fileDir, ModulePath);
// Find the last instance of a path delimiter (slash)
char* fileStart = strrchr(fileDir, '\\');
if (fileStart)
{
strcpy_s(dbName, fileStart + 1);
fileStart[0] = '\0';
}
else
{
// Directory or file with no extension
strcpy_s(dbName, fileDir);
}
}
if (settingboolget("Engine", "SaveDatabaseInProgramDirectory"))
{
// Absolute path in the program directory
sprintf_s(dbpath, "%s\\%s.%s", fileDir, dbName, dbType);
}
else
{
// Relative path in debugger directory
sprintf_s(dbpath, "%s\\%s.%s", dbbasepath, dbName, dbType);
}
dprintf("Database file: %s\n", dbpath);
}
}

View File

@ -1,8 +1,8 @@
#pragma once
#include "_global.h"
void DBSave();
void DBLoad();
void DBClose();
#pragma once
#include "_global.h"
void DBSave();
void DBLoad();
void DBClose();
void DBSetPath(const char *Directory, const char *ModulePath);

File diff suppressed because it is too large Load Diff

View File

@ -1,159 +1,159 @@
#include "_global.h"
#include "dbghelp_safe.h"
#include "threading.h"
DWORD
SafeUnDecorateSymbolName(
__in PCSTR name,
__out_ecount(maxStringLength) PSTR outputString,
__in DWORD maxStringLength,
__in DWORD flags
)
{
// NOTE: Disabled because of potential recursive deadlocks
// EXCLUSIVE_ACQUIRE(LockSym);
return UnDecorateSymbolName(name, outputString, maxStringLength, flags);
}
BOOL
SafeSymUnloadModule64(
__in HANDLE hProcess,
__in DWORD64 BaseOfDll
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymUnloadModule64(hProcess, BaseOfDll);
}
BOOL
SafeSymSetSearchPathW(
__in HANDLE hProcess,
__in_opt PCWSTR SearchPath
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymSetSearchPathW(hProcess, SearchPath);
}
DWORD
SafeSymSetOptions(
__in DWORD SymOptions
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymSetOptions(SymOptions);
}
BOOL
SafeSymInitializeW(
__in HANDLE hProcess,
__in_opt PCWSTR UserSearchPath,
__in BOOL fInvadeProcess
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymInitializeW(hProcess, UserSearchPath, fInvadeProcess);
}
BOOL
SafeSymRegisterCallback64(
__in HANDLE hProcess,
__in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
__in ULONG64 UserContext
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymRegisterCallback64(hProcess, CallbackFunction, UserContext);
}
DWORD64
SafeSymLoadModuleEx(
__in HANDLE hProcess,
__in_opt HANDLE hFile,
__in_opt PCSTR ImageName,
__in_opt PCSTR ModuleName,
__in DWORD64 BaseOfDll,
__in DWORD DllSize,
__in_opt PMODLOAD_DATA Data,
__in_opt DWORD Flags
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, DllSize, Data, Flags);
}
BOOL
SafeSymGetModuleInfo64(
__in HANDLE hProcess,
__in DWORD64 qwAddr,
__out PIMAGEHLP_MODULE64 ModuleInfo
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymGetModuleInfo64(hProcess, qwAddr, ModuleInfo);
}
BOOL
SafeSymGetSearchPathW(
__in HANDLE hProcess,
__out_ecount(SearchPathLength) PWSTR SearchPath,
__in DWORD SearchPathLength
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymGetSearchPathW(hProcess, SearchPath, SearchPathLength);
}
BOOL
SafeSymEnumSymbols(
__in HANDLE hProcess,
__in ULONG64 BaseOfDll,
__in_opt PCSTR Mask,
__in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
__in_opt PVOID UserContext
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymEnumSymbols(hProcess, BaseOfDll, Mask, EnumSymbolsCallback, UserContext);
}
BOOL
SafeSymEnumerateModules64(
__in HANDLE hProcess,
__in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
__in_opt PVOID UserContext
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymEnumerateModules64(hProcess, EnumModulesCallback, UserContext);
}
BOOL
SafeSymGetLineFromAddr64(
__in HANDLE hProcess,
__in DWORD64 qwAddr,
__out PDWORD pdwDisplacement,
__out PIMAGEHLP_LINE64 Line64
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymGetLineFromAddr64(hProcess, qwAddr, pdwDisplacement, Line64);
}
BOOL
SafeSymFromName(
__in HANDLE hProcess,
__in PCSTR Name,
__inout PSYMBOL_INFO Symbol
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymFromName(hProcess, Name, Symbol);
}
BOOL
SafeSymFromAddr(
__in HANDLE hProcess,
__in DWORD64 Address,
__out_opt PDWORD64 Displacement,
__inout PSYMBOL_INFO Symbol
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymFromAddr(hProcess, Address, Displacement, Symbol);
}
BOOL
SafeSymCleanup(
__in HANDLE hProcess
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymCleanup(hProcess);
#include "_global.h"
#include "dbghelp_safe.h"
#include "threading.h"
DWORD
SafeUnDecorateSymbolName(
__in PCSTR name,
__out_ecount(maxStringLength) PSTR outputString,
__in DWORD maxStringLength,
__in DWORD flags
)
{
// NOTE: Disabled because of potential recursive deadlocks
// EXCLUSIVE_ACQUIRE(LockSym);
return UnDecorateSymbolName(name, outputString, maxStringLength, flags);
}
BOOL
SafeSymUnloadModule64(
__in HANDLE hProcess,
__in DWORD64 BaseOfDll
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymUnloadModule64(hProcess, BaseOfDll);
}
BOOL
SafeSymSetSearchPathW(
__in HANDLE hProcess,
__in_opt PCWSTR SearchPath
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymSetSearchPathW(hProcess, SearchPath);
}
DWORD
SafeSymSetOptions(
__in DWORD SymOptions
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymSetOptions(SymOptions);
}
BOOL
SafeSymInitializeW(
__in HANDLE hProcess,
__in_opt PCWSTR UserSearchPath,
__in BOOL fInvadeProcess
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymInitializeW(hProcess, UserSearchPath, fInvadeProcess);
}
BOOL
SafeSymRegisterCallback64(
__in HANDLE hProcess,
__in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
__in ULONG64 UserContext
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymRegisterCallback64(hProcess, CallbackFunction, UserContext);
}
DWORD64
SafeSymLoadModuleEx(
__in HANDLE hProcess,
__in_opt HANDLE hFile,
__in_opt PCSTR ImageName,
__in_opt PCSTR ModuleName,
__in DWORD64 BaseOfDll,
__in DWORD DllSize,
__in_opt PMODLOAD_DATA Data,
__in_opt DWORD Flags
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, DllSize, Data, Flags);
}
BOOL
SafeSymGetModuleInfo64(
__in HANDLE hProcess,
__in DWORD64 qwAddr,
__out PIMAGEHLP_MODULE64 ModuleInfo
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymGetModuleInfo64(hProcess, qwAddr, ModuleInfo);
}
BOOL
SafeSymGetSearchPathW(
__in HANDLE hProcess,
__out_ecount(SearchPathLength) PWSTR SearchPath,
__in DWORD SearchPathLength
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymGetSearchPathW(hProcess, SearchPath, SearchPathLength);
}
BOOL
SafeSymEnumSymbols(
__in HANDLE hProcess,
__in ULONG64 BaseOfDll,
__in_opt PCSTR Mask,
__in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
__in_opt PVOID UserContext
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymEnumSymbols(hProcess, BaseOfDll, Mask, EnumSymbolsCallback, UserContext);
}
BOOL
SafeSymEnumerateModules64(
__in HANDLE hProcess,
__in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
__in_opt PVOID UserContext
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymEnumerateModules64(hProcess, EnumModulesCallback, UserContext);
}
BOOL
SafeSymGetLineFromAddr64(
__in HANDLE hProcess,
__in DWORD64 qwAddr,
__out PDWORD pdwDisplacement,
__out PIMAGEHLP_LINE64 Line64
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymGetLineFromAddr64(hProcess, qwAddr, pdwDisplacement, Line64);
}
BOOL
SafeSymFromName(
__in HANDLE hProcess,
__in PCSTR Name,
__inout PSYMBOL_INFO Symbol
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymFromName(hProcess, Name, Symbol);
}
BOOL
SafeSymFromAddr(
__in HANDLE hProcess,
__in DWORD64 Address,
__out_opt PDWORD64 Displacement,
__inout PSYMBOL_INFO Symbol
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymFromAddr(hProcess, Address, Displacement, Symbol);
}
BOOL
SafeSymCleanup(
__in HANDLE hProcess
)
{
EXCLUSIVE_ACQUIRE(LockSym);
return SymCleanup(hProcess);
}

View File

@ -1,105 +1,105 @@
#ifndef _DBGHELP_SAFE_H
#define _DBGHELP_SAFE_H
#ifdef __GNUC__
#include "dbghelp\dbghelp.h"
#else
#include <dbghelp.h>
#endif //__GNUC__
DWORD
SafeUnDecorateSymbolName(
__in PCSTR name,
__out_ecount(maxStringLength) PSTR outputString,
__in DWORD maxStringLength,
__in DWORD flags
);
BOOL
SafeSymUnloadModule64(
__in HANDLE hProcess,
__in DWORD64 BaseOfDll
);
BOOL
SafeSymSetSearchPathW(
__in HANDLE hProcess,
__in_opt PCWSTR SearchPath
);
DWORD
SafeSymSetOptions(
__in DWORD SymOptions
);
BOOL
SafeSymInitializeW(
__in HANDLE hProcess,
__in_opt PCWSTR UserSearchPath,
__in BOOL fInvadeProcess
);
BOOL
SafeSymRegisterCallback64(
__in HANDLE hProcess,
__in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
__in ULONG64 UserContext
);
DWORD64
SafeSymLoadModuleEx(
__in HANDLE hProcess,
__in_opt HANDLE hFile,
__in_opt PCSTR ImageName,
__in_opt PCSTR ModuleName,
__in DWORD64 BaseOfDll,
__in DWORD DllSize,
__in_opt PMODLOAD_DATA Data,
__in_opt DWORD Flags
);
BOOL
SafeSymGetModuleInfo64(
__in HANDLE hProcess,
__in DWORD64 qwAddr,
__out PIMAGEHLP_MODULE64 ModuleInfo
);
BOOL
SafeSymGetSearchPathW(
__in HANDLE hProcess,
__out_ecount(SearchPathLength) PWSTR SearchPath,
__in DWORD SearchPathLength
);
BOOL
SafeSymEnumSymbols(
__in HANDLE hProcess,
__in ULONG64 BaseOfDll,
__in_opt PCSTR Mask,
__in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
__in_opt PVOID UserContext
);
BOOL
SafeSymEnumerateModules64(
__in HANDLE hProcess,
__in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
__in_opt PVOID UserContext
);
BOOL
SafeSymGetLineFromAddr64(
__in HANDLE hProcess,
__in DWORD64 qwAddr,
__out PDWORD pdwDisplacement,
__out PIMAGEHLP_LINE64 Line64
);
BOOL
SafeSymFromName(
__in HANDLE hProcess,
__in PCSTR Name,
__inout PSYMBOL_INFO Symbol
);
BOOL
SafeSymFromAddr(
__in HANDLE hProcess,
__in DWORD64 Address,
__out_opt PDWORD64 Displacement,
__inout PSYMBOL_INFO Symbol
);
BOOL
SafeSymCleanup(
__in HANDLE hProcess
);
#ifndef _DBGHELP_SAFE_H
#define _DBGHELP_SAFE_H
#ifdef __GNUC__
#include "dbghelp\dbghelp.h"
#else
#include <dbghelp.h>
#endif //__GNUC__
DWORD
SafeUnDecorateSymbolName(
__in PCSTR name,
__out_ecount(maxStringLength) PSTR outputString,
__in DWORD maxStringLength,
__in DWORD flags
);
BOOL
SafeSymUnloadModule64(
__in HANDLE hProcess,
__in DWORD64 BaseOfDll
);
BOOL
SafeSymSetSearchPathW(
__in HANDLE hProcess,
__in_opt PCWSTR SearchPath
);
DWORD
SafeSymSetOptions(
__in DWORD SymOptions
);
BOOL
SafeSymInitializeW(
__in HANDLE hProcess,
__in_opt PCWSTR UserSearchPath,
__in BOOL fInvadeProcess
);
BOOL
SafeSymRegisterCallback64(
__in HANDLE hProcess,
__in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
__in ULONG64 UserContext
);
DWORD64
SafeSymLoadModuleEx(
__in HANDLE hProcess,
__in_opt HANDLE hFile,
__in_opt PCSTR ImageName,
__in_opt PCSTR ModuleName,
__in DWORD64 BaseOfDll,
__in DWORD DllSize,
__in_opt PMODLOAD_DATA Data,
__in_opt DWORD Flags
);
BOOL
SafeSymGetModuleInfo64(
__in HANDLE hProcess,
__in DWORD64 qwAddr,
__out PIMAGEHLP_MODULE64 ModuleInfo
);
BOOL
SafeSymGetSearchPathW(
__in HANDLE hProcess,
__out_ecount(SearchPathLength) PWSTR SearchPath,
__in DWORD SearchPathLength
);
BOOL
SafeSymEnumSymbols(
__in HANDLE hProcess,
__in ULONG64 BaseOfDll,
__in_opt PCSTR Mask,
__in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
__in_opt PVOID UserContext
);
BOOL
SafeSymEnumerateModules64(
__in HANDLE hProcess,
__in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
__in_opt PVOID UserContext
);
BOOL
SafeSymGetLineFromAddr64(
__in HANDLE hProcess,
__in DWORD64 qwAddr,
__out PDWORD pdwDisplacement,
__out PIMAGEHLP_LINE64 Line64
);
BOOL
SafeSymFromName(
__in HANDLE hProcess,
__in PCSTR Name,
__inout PSYMBOL_INFO Symbol
);
BOOL
SafeSymFromAddr(
__in HANDLE hProcess,
__in DWORD64 Address,
__out_opt PDWORD64 Displacement,
__inout PSYMBOL_INFO Symbol
);
BOOL
SafeSymCleanup(
__in HANDLE hProcess
);
#endif //_DBGHELP_SAFE_H

File diff suppressed because it is too large Load Diff

View File

@ -1,120 +1,120 @@
#ifndef _DEBUGGER_H
#define _DEBUGGER_H
#include "_global.h"
#include "TitanEngine\TitanEngine.h"
#include "command.h"
#include "breakpoint.h"
#include "undocumented.h"
#include "value.h"
#include "_plugins.h"
#define MS_VC_EXCEPTION 0x406D1388
//structures
struct INIT_STRUCT
{
char* exe;
char* commandline;
char* currentfolder;
};
typedef enum
{
CMDL_ERR_READ_PEBBASE = 0,
CMDL_ERR_READ_PROCPARM_PTR,
CMDL_ERR_READ_PROCPARM_CMDLINE,
CMDL_ERR_CONVERTUNICODE,
CMDL_ERR_ALLOC,
CMDL_ERR_GET_PEB,
CMDL_ERR_READ_GETCOMMANDLINEBASE,
CMDL_ERR_CHECK_GETCOMMANDLINESTORED,
CMDL_ERR_WRITE_GETCOMMANDLINESTORED,
CMDL_ERR_GET_GETCOMMANDLINE,
CMDL_ERR_ALLOC_UNICODEANSI_COMMANDLINE,
CMDL_ERR_WRITE_ANSI_COMMANDLINE,
CMDL_ERR_WRITE_UNICODE_COMMANDLINE,
CMDL_ERR_WRITE_PEBUNICODE_COMMANDLINE
} cmdline_error_type_t;
typedef struct
{
cmdline_error_type_t type;
duint addr;
} cmdline_error_t;
struct ExceptionRange
{
unsigned int start;
unsigned int end;
};
#pragma pack(push,8)
typedef struct _THREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
//functions
void dbginit();
void dbgstop();
duint dbgdebuggedbase();
duint dbggettimewastedcounter();
bool dbgisrunning();
bool dbgisdll();
void dbgsetattachevent(HANDLE handle);
void DebugUpdateGui(duint disasm_addr, bool stack);
void DebugUpdateStack(duint dumpAddr, duint csp, bool forceDump = false);
void dbgsetskipexceptions(bool skip);
void dbgsetstepping(bool stepping);
void dbgsetispausedbyuser(bool b);
void dbgsetisdetachedbyuser(bool b);
void dbgsetfreezestack(bool freeze);
void dbgclearignoredexceptions();
void dbgaddignoredexception(ExceptionRange range);
bool dbgisignoredexception(unsigned int exception);
bool dbgcmdnew(const char* name, CBCOMMAND cbCommand, bool debugonly);
bool dbgcmddel(const char* name);
bool dbglistprocesses(std::vector<PROCESSENTRY32>* list);
bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error);
bool dbggetcmdline(char** cmd_line, cmdline_error_t* cmd_line_error);
void dbgstartscriptthread(CBPLUGINSCRIPT cbScript);
duint dbggetdebuggedbase();
void cbStep();
void cbRtrStep();
void cbSystemBreakpoint(void* ExceptionData);
void cbMemoryBreakpoint(void* ExceptionAddress);
void cbHardwareBreakpoint(void* ExceptionAddress);
void cbUserBreakpoint();
void cbDebugLoadLibBPX();
void cbLibrarianBreakpoint(void* lpData);
DWORD WINAPI threadDebugLoop(void* lpParameter);
bool cbDeleteAllBreakpoints(const BREAKPOINT* bp);
bool cbEnableAllBreakpoints(const BREAKPOINT* bp);
bool cbDisableAllBreakpoints(const BREAKPOINT* bp);
bool cbEnableAllHardwareBreakpoints(const BREAKPOINT* bp);
bool cbDisableAllHardwareBreakpoints(const BREAKPOINT* bp);
bool cbEnableAllMemoryBreakpoints(const BREAKPOINT* bp);
bool cbDisableAllMemoryBreakpoints(const BREAKPOINT* bp);
bool cbBreakpointList(const BREAKPOINT* bp);
bool cbDeleteAllMemoryBreakpoints(const BREAKPOINT* bp);
bool cbDeleteAllHardwareBreakpoints(const BREAKPOINT* bp);
DWORD WINAPI threadAttachLoop(void* lpParameter);
void cbDetach();
bool cbSetModuleBreakpoints(const BREAKPOINT* bp);
//variables
extern PROCESS_INFORMATION* fdProcessInfo;
extern HANDLE hActiveThread;
extern char szFileName[MAX_PATH];
extern char szSymbolCachePath[MAX_PATH];
extern bool bUndecorateSymbolNames;
extern bool bEnableSourceDebugging;
#endif // _DEBUGGER_H
#ifndef _DEBUGGER_H
#define _DEBUGGER_H
#include "_global.h"
#include "TitanEngine\TitanEngine.h"
#include "command.h"
#include "breakpoint.h"
#include "undocumented.h"
#include "value.h"
#include "_plugins.h"
#define MS_VC_EXCEPTION 0x406D1388
//structures
struct INIT_STRUCT
{
char* exe;
char* commandline;
char* currentfolder;
};
typedef enum
{
CMDL_ERR_READ_PEBBASE = 0,
CMDL_ERR_READ_PROCPARM_PTR,
CMDL_ERR_READ_PROCPARM_CMDLINE,
CMDL_ERR_CONVERTUNICODE,
CMDL_ERR_ALLOC,
CMDL_ERR_GET_PEB,
CMDL_ERR_READ_GETCOMMANDLINEBASE,
CMDL_ERR_CHECK_GETCOMMANDLINESTORED,
CMDL_ERR_WRITE_GETCOMMANDLINESTORED,
CMDL_ERR_GET_GETCOMMANDLINE,
CMDL_ERR_ALLOC_UNICODEANSI_COMMANDLINE,
CMDL_ERR_WRITE_ANSI_COMMANDLINE,
CMDL_ERR_WRITE_UNICODE_COMMANDLINE,
CMDL_ERR_WRITE_PEBUNICODE_COMMANDLINE
} cmdline_error_type_t;
typedef struct
{
cmdline_error_type_t type;
duint addr;
} cmdline_error_t;
struct ExceptionRange
{
unsigned int start;
unsigned int end;
};
#pragma pack(push,8)
typedef struct _THREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
//functions
void dbginit();
void dbgstop();
duint dbgdebuggedbase();
duint dbggettimewastedcounter();
bool dbgisrunning();
bool dbgisdll();
void dbgsetattachevent(HANDLE handle);
void DebugUpdateGui(duint disasm_addr, bool stack);
void DebugUpdateStack(duint dumpAddr, duint csp, bool forceDump = false);
void dbgsetskipexceptions(bool skip);
void dbgsetstepping(bool stepping);
void dbgsetispausedbyuser(bool b);
void dbgsetisdetachedbyuser(bool b);
void dbgsetfreezestack(bool freeze);
void dbgclearignoredexceptions();
void dbgaddignoredexception(ExceptionRange range);
bool dbgisignoredexception(unsigned int exception);
bool dbgcmdnew(const char* name, CBCOMMAND cbCommand, bool debugonly);
bool dbgcmddel(const char* name);
bool dbglistprocesses(std::vector<PROCESSENTRY32>* list);
bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error);
bool dbggetcmdline(char** cmd_line, cmdline_error_t* cmd_line_error);
void dbgstartscriptthread(CBPLUGINSCRIPT cbScript);
duint dbggetdebuggedbase();
void cbStep();
void cbRtrStep();
void cbSystemBreakpoint(void* ExceptionData);
void cbMemoryBreakpoint(void* ExceptionAddress);
void cbHardwareBreakpoint(void* ExceptionAddress);
void cbUserBreakpoint();
void cbDebugLoadLibBPX();
void cbLibrarianBreakpoint(void* lpData);
DWORD WINAPI threadDebugLoop(void* lpParameter);
bool cbDeleteAllBreakpoints(const BREAKPOINT* bp);
bool cbEnableAllBreakpoints(const BREAKPOINT* bp);
bool cbDisableAllBreakpoints(const BREAKPOINT* bp);
bool cbEnableAllHardwareBreakpoints(const BREAKPOINT* bp);
bool cbDisableAllHardwareBreakpoints(const BREAKPOINT* bp);
bool cbEnableAllMemoryBreakpoints(const BREAKPOINT* bp);
bool cbDisableAllMemoryBreakpoints(const BREAKPOINT* bp);
bool cbBreakpointList(const BREAKPOINT* bp);
bool cbDeleteAllMemoryBreakpoints(const BREAKPOINT* bp);
bool cbDeleteAllHardwareBreakpoints(const BREAKPOINT* bp);
DWORD WINAPI threadAttachLoop(void* lpParameter);
void cbDetach();
bool cbSetModuleBreakpoints(const BREAKPOINT* bp);
//variables
extern PROCESS_INFORMATION* fdProcessInfo;
extern HANDLE hActiveThread;
extern char szFileName[MAX_PATH];
extern char szSymbolCachePath[MAX_PATH];
extern bool bUndecorateSymbolNames;
extern bool bEnableSourceDebugging;
#endif // _DEBUGGER_H

File diff suppressed because it is too large Load Diff

View File

@ -1,72 +1,72 @@
#ifndef _DEBUGGER_COMMANDS_H
#define _DEBUGGER_COMMANDS_H
#include "command.h"
#include "debugger.h"
//command callbacks
CMDRESULT cbDebugInit(int argc, char* argv[]);
CMDRESULT cbDebugStop(int argc, char* argv[]);
CMDRESULT cbDebugRun(int argc, char* argv[]);
CMDRESULT cbDebugErun(int argc, char* argv[]);
CMDRESULT cbDebugSetBPXOptions(int argc, char* argv[]);
CMDRESULT cbDebugSetBPX(int argc, char* argv[]);
CMDRESULT cbDebugDeleteBPX(int argc, char* argv[]);
CMDRESULT cbDebugEnableBPX(int argc, char* argv[]);
CMDRESULT cbDebugDisableBPX(int argc, char* argv[]);
CMDRESULT cbDebugBplist(int argc, char* argv[]);
CMDRESULT cbDebugStepInto(int argc, char* argv[]);
CMDRESULT cbDebugeStepInto(int argc, char* argv[]);
CMDRESULT cbDebugStepOver(int argc, char* argv[]);
CMDRESULT cbDebugeStepOver(int argc, char* argv[]);
CMDRESULT cbDebugSingleStep(int argc, char* argv[]);
CMDRESULT cbDebugeSingleStep(int argc, char* argv[]);
CMDRESULT cbDebugHide(int argc, char* argv[]);
CMDRESULT cbDebugDisasm(int argc, char* argv[]);
CMDRESULT cbDebugSetMemoryBpx(int argc, char* argv[]);
CMDRESULT cbDebugRtr(int argc, char* argv[]);
CMDRESULT cbDebugeRtr(int argc, char* argv[]);
CMDRESULT cbDebugSetHardwareBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugAlloc(int argc, char* argv[]);
CMDRESULT cbDebugFree(int argc, char* argv[]);
CMDRESULT cbDebugMemset(int argc, char* argv[]);
CMDRESULT cbDebugBenchmark(int argc, char* argv[]);
CMDRESULT cbDebugPause(int argc, char* argv[]);
CMDRESULT cbDebugStartScylla(int argc, char* argv[]);
CMDRESULT cbDebugDeleteHardwareBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugDeleteMemoryBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugAttach(int argc, char* argv[]);
CMDRESULT cbDebugDetach(int argc, char* argv[]);
CMDRESULT cbDebugDump(int argc, char* argv[]);
CMDRESULT cbDebugStackDump(int argc, char* argv[]);
CMDRESULT cbDebugContinue(int argc, char* argv[]);
CMDRESULT cbDebugBpDll(int argc, char* argv[]);
CMDRESULT cbDebugBcDll(int argc, char* argv[]);
CMDRESULT cbDebugSwitchthread(int argc, char* argv[]);
CMDRESULT cbDebugResumethread(int argc, char* argv[]);
CMDRESULT cbDebugSetJIT(int argc, char* argv[]);
CMDRESULT cbDebugGetJIT(int argc, char* argv[]);
CMDRESULT cbDebugGetJITAuto(int argc, char* argv[]);
CMDRESULT cbDebugSetJITAuto(int argc, char* argv[]);
CMDRESULT cbDebugSuspendthread(int argc, char* argv[]);
CMDRESULT cbDebugKillthread(int argc, char* argv[]);
CMDRESULT cbDebugSuspendAllThreads(int argc, char* argv[]);
CMDRESULT cbDebugResumeAllThreads(int argc, char* argv[]);
CMDRESULT cbDebugSetPriority(int argc, char* argv[]);
CMDRESULT cbDebugGetCmdline(int argc, char* argv[]);
CMDRESULT cbDebugSetCmdline(int argc, char* argv[]);
CMDRESULT cbDebugLoadLib(int argc, char* argv[]);
CMDRESULT cbDebugEnableHardwareBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugDisableHardwareBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugEnableMemoryBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugDisableMemoryBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugDownloadSymbol(int argc, char* argv[]);
CMDRESULT cbDebugGetPageRights(int argc, char* argv[]);
CMDRESULT cbDebugSetPageRights(int argc, char* argv[]);
CMDRESULT cbDebugSkip(int argc, char* argv[]);
CMDRESULT cbDebugSetfreezestack(int argc, char* argv[]);
//misc
void showcommandlineerror(cmdline_error_t* cmdline_error);
#ifndef _DEBUGGER_COMMANDS_H
#define _DEBUGGER_COMMANDS_H
#include "command.h"
#include "debugger.h"
//command callbacks
CMDRESULT cbDebugInit(int argc, char* argv[]);
CMDRESULT cbDebugStop(int argc, char* argv[]);
CMDRESULT cbDebugRun(int argc, char* argv[]);
CMDRESULT cbDebugErun(int argc, char* argv[]);
CMDRESULT cbDebugSetBPXOptions(int argc, char* argv[]);
CMDRESULT cbDebugSetBPX(int argc, char* argv[]);
CMDRESULT cbDebugDeleteBPX(int argc, char* argv[]);
CMDRESULT cbDebugEnableBPX(int argc, char* argv[]);
CMDRESULT cbDebugDisableBPX(int argc, char* argv[]);
CMDRESULT cbDebugBplist(int argc, char* argv[]);
CMDRESULT cbDebugStepInto(int argc, char* argv[]);
CMDRESULT cbDebugeStepInto(int argc, char* argv[]);
CMDRESULT cbDebugStepOver(int argc, char* argv[]);
CMDRESULT cbDebugeStepOver(int argc, char* argv[]);
CMDRESULT cbDebugSingleStep(int argc, char* argv[]);
CMDRESULT cbDebugeSingleStep(int argc, char* argv[]);
CMDRESULT cbDebugHide(int argc, char* argv[]);
CMDRESULT cbDebugDisasm(int argc, char* argv[]);
CMDRESULT cbDebugSetMemoryBpx(int argc, char* argv[]);
CMDRESULT cbDebugRtr(int argc, char* argv[]);
CMDRESULT cbDebugeRtr(int argc, char* argv[]);
CMDRESULT cbDebugSetHardwareBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugAlloc(int argc, char* argv[]);
CMDRESULT cbDebugFree(int argc, char* argv[]);
CMDRESULT cbDebugMemset(int argc, char* argv[]);
CMDRESULT cbDebugBenchmark(int argc, char* argv[]);
CMDRESULT cbDebugPause(int argc, char* argv[]);
CMDRESULT cbDebugStartScylla(int argc, char* argv[]);
CMDRESULT cbDebugDeleteHardwareBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugDeleteMemoryBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugAttach(int argc, char* argv[]);
CMDRESULT cbDebugDetach(int argc, char* argv[]);
CMDRESULT cbDebugDump(int argc, char* argv[]);
CMDRESULT cbDebugStackDump(int argc, char* argv[]);
CMDRESULT cbDebugContinue(int argc, char* argv[]);
CMDRESULT cbDebugBpDll(int argc, char* argv[]);
CMDRESULT cbDebugBcDll(int argc, char* argv[]);
CMDRESULT cbDebugSwitchthread(int argc, char* argv[]);
CMDRESULT cbDebugResumethread(int argc, char* argv[]);
CMDRESULT cbDebugSetJIT(int argc, char* argv[]);
CMDRESULT cbDebugGetJIT(int argc, char* argv[]);
CMDRESULT cbDebugGetJITAuto(int argc, char* argv[]);
CMDRESULT cbDebugSetJITAuto(int argc, char* argv[]);
CMDRESULT cbDebugSuspendthread(int argc, char* argv[]);
CMDRESULT cbDebugKillthread(int argc, char* argv[]);
CMDRESULT cbDebugSuspendAllThreads(int argc, char* argv[]);
CMDRESULT cbDebugResumeAllThreads(int argc, char* argv[]);
CMDRESULT cbDebugSetPriority(int argc, char* argv[]);
CMDRESULT cbDebugGetCmdline(int argc, char* argv[]);
CMDRESULT cbDebugSetCmdline(int argc, char* argv[]);
CMDRESULT cbDebugLoadLib(int argc, char* argv[]);
CMDRESULT cbDebugEnableHardwareBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugDisableHardwareBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugEnableMemoryBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugDisableMemoryBreakpoint(int argc, char* argv[]);
CMDRESULT cbDebugDownloadSymbol(int argc, char* argv[]);
CMDRESULT cbDebugGetPageRights(int argc, char* argv[]);
CMDRESULT cbDebugSetPageRights(int argc, char* argv[]);
CMDRESULT cbDebugSkip(int argc, char* argv[]);
CMDRESULT cbDebugSetfreezestack(int argc, char* argv[]);
//misc
void showcommandlineerror(cmdline_error_t* cmdline_error);
#endif //_DEBUGGER_COMMANDS_H

View File

@ -1,109 +1,109 @@
/**
@file disasm_fast.cpp
@brief Implements the disasm fast class.
*/
#include "disasm_fast.h"
#include "memory.h"
static MEMORY_SIZE argsize2memsize(int argsize)
{
switch(argsize)
{
case 8:
return size_byte;
case 16:
return size_word;
case 32:
return size_dword;
case 64:
return size_qword;
}
return size_byte;
}
void fillbasicinfo(Capstone* cp, BASIC_INSTRUCTION_INFO* basicinfo)
{
//zero basicinfo
memset(basicinfo, 0, sizeof(BASIC_INSTRUCTION_INFO));
//copy instruction text
strcpy_s(basicinfo->instruction, cp->InstructionText().c_str());
//instruction size
basicinfo->size = cp->Size();
//branch/call info
if(cp->InGroup(CS_GRP_CALL))
{
basicinfo->branch = true;
basicinfo->call = true;
}
else if(cp->InGroup(CS_GRP_JUMP) || cp->IsLoop())
{
basicinfo->branch = true;
}
//handle operands
for(int i = 0; i < cp->x86().op_count; i++)
{
const cs_x86_op & op = cp->x86().operands[i];
switch(op.type)
{
case CS_OP_IMM:
{
if(basicinfo->branch)
{
basicinfo->type |= TYPE_ADDR;
basicinfo->addr = (duint)op.imm;
basicinfo->value.value = (duint)op.imm + basicinfo->size;
}
else
{
basicinfo->type |= TYPE_VALUE;
basicinfo->value.size = (VALUE_SIZE)op.size;
basicinfo->value.value = (duint)op.imm;
}
}
break;
case CS_OP_MEM:
{
const x86_op_mem & mem = op.mem;
strcpy_s(basicinfo->memory.mnemonic, cp->OperandText(i).c_str());
basicinfo->memory.size = (MEMORY_SIZE)op.size;
if(op.mem.base == X86_REG_RIP) //rip-relative
{
basicinfo->memory.value = (ULONG_PTR)(cp->GetInstr()->address + op.mem.disp + basicinfo->size);
basicinfo->type |= TYPE_MEMORY;
}
else if(mem.disp)
{
basicinfo->type |= TYPE_MEMORY;
basicinfo->memory.value = (ULONG_PTR)mem.disp;
}
}
break;
}
}
}
bool disasmfast(unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* basicinfo)
{
if(!data || !basicinfo)
return false;
Capstone cp;
if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER))
{
strcpy_s(basicinfo->instruction, "???");
basicinfo->size = 1;
return false;
}
fillbasicinfo(&cp, basicinfo);
return true;
}
bool disasmfast(duint addr, BASIC_INSTRUCTION_INFO* basicinfo)
{
unsigned int data[16];
if(!MemRead(addr, data, sizeof(data)))
return false;
return disasmfast((unsigned char*)data, addr, basicinfo);
/**
@file disasm_fast.cpp
@brief Implements the disasm fast class.
*/
#include "disasm_fast.h"
#include "memory.h"
static MEMORY_SIZE argsize2memsize(int argsize)
{
switch(argsize)
{
case 8:
return size_byte;
case 16:
return size_word;
case 32:
return size_dword;
case 64:
return size_qword;
}
return size_byte;
}
void fillbasicinfo(Capstone* cp, BASIC_INSTRUCTION_INFO* basicinfo)
{
//zero basicinfo
memset(basicinfo, 0, sizeof(BASIC_INSTRUCTION_INFO));
//copy instruction text
strcpy_s(basicinfo->instruction, cp->InstructionText().c_str());
//instruction size
basicinfo->size = cp->Size();
//branch/call info
if(cp->InGroup(CS_GRP_CALL))
{
basicinfo->branch = true;
basicinfo->call = true;
}
else if(cp->InGroup(CS_GRP_JUMP) || cp->IsLoop())
{
basicinfo->branch = true;
}
//handle operands
for(int i = 0; i < cp->x86().op_count; i++)
{
const cs_x86_op & op = cp->x86().operands[i];
switch(op.type)
{
case CS_OP_IMM:
{
if(basicinfo->branch)
{
basicinfo->type |= TYPE_ADDR;
basicinfo->addr = (duint)op.imm;
basicinfo->value.value = (duint)op.imm + basicinfo->size;
}
else
{
basicinfo->type |= TYPE_VALUE;
basicinfo->value.size = (VALUE_SIZE)op.size;
basicinfo->value.value = (duint)op.imm;
}
}
break;
case CS_OP_MEM:
{
const x86_op_mem & mem = op.mem;
strcpy_s(basicinfo->memory.mnemonic, cp->OperandText(i).c_str());
basicinfo->memory.size = (MEMORY_SIZE)op.size;
if(op.mem.base == X86_REG_RIP) //rip-relative
{
basicinfo->memory.value = (ULONG_PTR)(cp->GetInstr()->address + op.mem.disp + basicinfo->size);
basicinfo->type |= TYPE_MEMORY;
}
else if(mem.disp)
{
basicinfo->type |= TYPE_MEMORY;
basicinfo->memory.value = (ULONG_PTR)mem.disp;
}
}
break;
}
}
}
bool disasmfast(unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* basicinfo)
{
if(!data || !basicinfo)
return false;
Capstone cp;
if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER))
{
strcpy_s(basicinfo->instruction, "???");
basicinfo->size = 1;
return false;
}
fillbasicinfo(&cp, basicinfo);
return true;
}
bool disasmfast(duint addr, BASIC_INSTRUCTION_INFO* basicinfo)
{
unsigned int data[16];
if(!MemRead(addr, data, sizeof(data)))
return false;
return disasmfast((unsigned char*)data, addr, basicinfo);
}

View File

@ -1,11 +1,11 @@
#ifndef _DISASM_FAST_H
#define _DISASM_FAST_H
#include "_global.h"
#include <capstone_wrapper.h>
void fillbasicinfo(Capstone* disasm, BASIC_INSTRUCTION_INFO* basicinfo);
bool disasmfast(duint addr, BASIC_INSTRUCTION_INFO* basicinfo);
bool disasmfast(unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* basicinfo);
#endif //_DISASM_FAST_H
#ifndef _DISASM_FAST_H
#define _DISASM_FAST_H
#include "_global.h"
#include <capstone_wrapper.h>
void fillbasicinfo(Capstone* disasm, BASIC_INSTRUCTION_INFO* basicinfo);
bool disasmfast(duint addr, BASIC_INSTRUCTION_INFO* basicinfo);
bool disasmfast(unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* basicinfo);
#endif //_DISASM_FAST_H

View File

@ -1,357 +1,357 @@
/**
@file disasm_helper.cpp
@brief Implements the disasm helper class.
*/
#include "disasm_helper.h"
#include "value.h"
#include "console.h"
#include "memory.h"
#include <capstone_wrapper.h>
duint disasmback(unsigned char* data, duint base, duint size, duint ip, int n)
{
int i;
duint abuf[131], addr, back, cmdsize;
unsigned char* pdata;
// Reset Disasm Structure
Capstone cp;
// Check if the pointer is not null
if(data == NULL)
return 0;
// Round the number of back instructions to 127
if(n < 0)
n = 0;
else if(n > 127)
n = 127;
// Check if the instruction pointer ip is not outside the memory range
if(ip >= size)
ip = size - 1;
// Obvious answer
if(n == 0)
return ip;
if(ip < (duint)n)
return ip;
back = MAX_DISASM_BUFFER * (n + 3); // Instruction length limited to 16
if(ip < back)
back = ip;
addr = ip - back;
pdata = data + addr;
for(i = 0; addr < ip; i++)
{
abuf[i % 128] = addr;
if(!cp.Disassemble(0, pdata, (int)size))
cmdsize = 1;
else
cmdsize = cp.Size();
pdata += cmdsize;
addr += cmdsize;
back -= cmdsize;
size -= cmdsize;
}
if(i < n)
return abuf[0];
else
return abuf[(i - n + 128) % 128];
}
duint disasmnext(unsigned char* data, duint base, duint size, duint ip, int n)
{
int i;
duint cmdsize;
unsigned char* pdata;
// Reset Disasm Structure
Capstone cp;
if(data == NULL)
return 0;
if(ip >= size)
ip = size - 1;
if(n <= 0)
return ip;
pdata = data + ip;
size -= ip;
for(i = 0; i < n && size > 0; i++)
{
if(!cp.Disassemble(0, pdata, (int)size))
cmdsize = 1;
else
cmdsize = cp.Size();
pdata += cmdsize;
ip += cmdsize;
size -= cmdsize;
}
return ip;
}
const char* disasmtext(duint addr)
{
unsigned char buffer[MAX_DISASM_BUFFER] = "";
DbgMemRead(addr, buffer, sizeof(buffer));
Capstone cp;
static char instruction[64] = "";
if(!cp.Disassemble(addr, buffer))
strcpy_s(instruction, "???");
else
sprintf_s(instruction, "%s %s", cp.GetInstr()->mnemonic, cp.GetInstr()->op_str);
return instruction;
}
static void HandleCapstoneOperand(Capstone & cp, int opindex, DISASM_ARG* arg)
{
const cs_x86 & x86 = cp.x86();
const cs_x86_op & op = x86.operands[opindex];
arg->segment = SEG_DEFAULT;
strcpy_s(arg->mnemonic, cp.OperandText(opindex).c_str());
switch(op.type)
{
case X86_OP_REG:
{
const char* regname = cp.RegName((x86_reg)op.reg);
arg->type = arg_normal;
duint value;
if(!valfromstring(regname, &value, true, true))
value = 0;
arg->constant = arg->value = value;
}
break;
case X86_OP_IMM:
{
arg->type = arg_normal;
arg->constant = arg->value = (duint)op.imm;
}
break;
case X86_OP_MEM:
{
arg->type = arg_memory;
const x86_op_mem & mem = op.mem;
if(mem.base == X86_REG_RIP) //rip-relative
arg->constant = cp.Address() + (duint)mem.disp + cp.Size();
else
arg->constant = (duint)mem.disp;
duint value;
if(!valfromstring(arg->mnemonic, &value, true, true))
return;
arg->value = value;
if(DbgMemIsValidReadPtr(value))
{
switch(op.size)
{
case 1:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 1);
break;
case 2:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 2);
break;
case 4:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 4);
break;
case 8:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 8);
break;
}
}
}
break;
}
}
void disasmget(unsigned char* buffer, duint addr, DISASM_INSTR* instr)
{
if(!DbgIsDebugging())
{
if(instr)
instr->argcount = 0;
return;
}
memset(instr, 0, sizeof(DISASM_INSTR));
Capstone cp;
if(!cp.Disassemble(addr, buffer, MAX_DISASM_BUFFER))
{
strcpy_s(instr->instruction, "???");
instr->instr_size = 1;
instr->type = instr_normal;
instr->argcount = 0;
return;
}
const cs_insn* cpInstr = cp.GetInstr();
sprintf_s(instr->instruction, "%s %s", cpInstr->mnemonic, cpInstr->op_str);
instr->instr_size = cpInstr->size;
if(cp.InGroup(CS_GRP_JUMP) || cp.IsLoop() || cp.InGroup(CS_GRP_RET) || cp.InGroup(CS_GRP_CALL))
instr->type = instr_branch;
else if(strstr(cpInstr->op_str, "sp") || strstr(cpInstr->op_str, "bp"))
instr->type = instr_stack;
else
instr->type = instr_normal;
instr->argcount = cp.x86().op_count <= 3 ? cp.x86().op_count : 3;
for(int i = 0; i < instr->argcount; i++)
HandleCapstoneOperand(cp, i, &instr->arg[i]);
}
void disasmget(duint addr, DISASM_INSTR* instr)
{
if(!DbgIsDebugging())
{
if(instr)
instr->argcount = 0;
return;
}
unsigned char buffer[MAX_DISASM_BUFFER] = "";
DbgMemRead(addr, buffer, sizeof(buffer));
disasmget(buffer, addr, instr);
}
void disasmprint(duint addr)
{
DISASM_INSTR instr;
memset(&instr, 0, sizeof(instr));
disasmget(addr, &instr);
dprintf(">%d:\"%s\":\n", instr.type, instr.instruction);
for(int i = 0; i < instr.argcount; i++)
dprintf(" %d:%d:%" fext "X:%" fext "X:%" fext "X\n", i, instr.arg[i].type, instr.arg[i].constant, instr.arg[i].value, instr.arg[i].memvalue);
}
static bool isasciistring(const unsigned char* data, int maxlen)
{
int len = 0;
for(char* p = (char*)data; *p; len++, p++)
{
if(len >= maxlen)
break;
}
if(len < 2 || len + 1 >= maxlen)
return false;
for(int i = 0; i < len; i++)
if(!isprint(data[i]) && !isspace(data[i]))
return false;
return true;
}
static bool isunicodestring(const unsigned char* data, int maxlen)
{
int len = 0;
for(wchar_t* p = (wchar_t*)data; *p; len++, p++)
{
if(len >= maxlen)
break;
}
if(len < 2 || len + 1 >= maxlen)
return false;
for(int i = 0; i < len * 2; i += 2)
{
if(data[i + 1]) //Extended ASCII only
return false;
if(!isprint(data[i]) && !isspace(data[i]))
return false;
}
return true;
}
bool disasmispossiblestring(duint addr)
{
unsigned char data[11];
memset(data, 0, sizeof(data));
if(!MemRead(addr, data, sizeof(data) - 3))
return false;
duint test = 0;
memcpy(&test, data, sizeof(duint));
if(isasciistring(data, sizeof(data)) || isunicodestring(data, _countof(data)))
return true;
return false;
}
bool disasmgetstringat(duint addr, STRING_TYPE* type, char* ascii, char* unicode, int maxlen)
{
if(type)
*type = str_none;
if(!disasmispossiblestring(addr))
return false;
Memory<unsigned char*> data((maxlen + 1) * 2, "disasmgetstringat:data");
if(!MemRead(addr, data(), (maxlen + 1) * 2))
return false;
// Save a few pointer casts
auto asciiData = (char*)data();
auto unicodeData = (wchar_t*)data();
// First check if this was an ASCII only string
if(isasciistring(data(), maxlen))
{
if(type)
*type = str_ascii;
// Escape the string
String escaped = StringUtils::Escape(asciiData);
// Copy data back to outgoing parameter
strncpy_s(ascii, min(int(escaped.length()) + 1, maxlen), escaped.c_str(), _TRUNCATE);
return true;
}
if(isunicodestring(data(), maxlen))
{
if(type)
*type = str_unicode;
// Determine string length only once, limited to output buffer size
int unicodeLength = min(int(wcslen(unicodeData)), maxlen);
// Truncate each wchar_t to char
for(int i = 0; i < unicodeLength; i++)
asciiData[i] = char(unicodeData[i] & 0xFF);
// Fix the null terminator (data len = maxlen + 1)
asciiData[unicodeLength] = '\0';
// Escape the string
String escaped = StringUtils::Escape(asciiData);
// Copy data back to outgoing parameter
strncpy_s(unicode, min(int(escaped.length()) + 1, maxlen), escaped.c_str(), _TRUNCATE);
return true;
}
return false;
}
int disasmgetsize(duint addr, unsigned char* data)
{
Capstone cp;
if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER))
return 1;
return cp.Size();
}
int disasmgetsize(duint addr)
{
char data[MAX_DISASM_BUFFER];
if(!MemRead(addr, data, sizeof(data)))
return 1;
return disasmgetsize(addr, (unsigned char*)data);
/**
@file disasm_helper.cpp
@brief Implements the disasm helper class.
*/
#include "disasm_helper.h"
#include "value.h"
#include "console.h"
#include "memory.h"
#include <capstone_wrapper.h>
duint disasmback(unsigned char* data, duint base, duint size, duint ip, int n)
{
int i;
duint abuf[131], addr, back, cmdsize;
unsigned char* pdata;
// Reset Disasm Structure
Capstone cp;
// Check if the pointer is not null
if(data == NULL)
return 0;
// Round the number of back instructions to 127
if(n < 0)
n = 0;
else if(n > 127)
n = 127;
// Check if the instruction pointer ip is not outside the memory range
if(ip >= size)
ip = size - 1;
// Obvious answer
if(n == 0)
return ip;
if(ip < (duint)n)
return ip;
back = MAX_DISASM_BUFFER * (n + 3); // Instruction length limited to 16
if(ip < back)
back = ip;
addr = ip - back;
pdata = data + addr;
for(i = 0; addr < ip; i++)
{
abuf[i % 128] = addr;
if(!cp.Disassemble(0, pdata, (int)size))
cmdsize = 1;
else
cmdsize = cp.Size();
pdata += cmdsize;
addr += cmdsize;
back -= cmdsize;
size -= cmdsize;
}
if(i < n)
return abuf[0];
else
return abuf[(i - n + 128) % 128];
}
duint disasmnext(unsigned char* data, duint base, duint size, duint ip, int n)
{
int i;
duint cmdsize;
unsigned char* pdata;
// Reset Disasm Structure
Capstone cp;
if(data == NULL)
return 0;
if(ip >= size)
ip = size - 1;
if(n <= 0)
return ip;
pdata = data + ip;
size -= ip;
for(i = 0; i < n && size > 0; i++)
{
if(!cp.Disassemble(0, pdata, (int)size))
cmdsize = 1;
else
cmdsize = cp.Size();
pdata += cmdsize;
ip += cmdsize;
size -= cmdsize;
}
return ip;
}
const char* disasmtext(duint addr)
{
unsigned char buffer[MAX_DISASM_BUFFER] = "";
DbgMemRead(addr, buffer, sizeof(buffer));
Capstone cp;
static char instruction[64] = "";
if(!cp.Disassemble(addr, buffer))
strcpy_s(instruction, "???");
else
sprintf_s(instruction, "%s %s", cp.GetInstr()->mnemonic, cp.GetInstr()->op_str);
return instruction;
}
static void HandleCapstoneOperand(Capstone & cp, int opindex, DISASM_ARG* arg)
{
const cs_x86 & x86 = cp.x86();
const cs_x86_op & op = x86.operands[opindex];
arg->segment = SEG_DEFAULT;
strcpy_s(arg->mnemonic, cp.OperandText(opindex).c_str());
switch(op.type)
{
case X86_OP_REG:
{
const char* regname = cp.RegName((x86_reg)op.reg);
arg->type = arg_normal;
duint value;
if(!valfromstring(regname, &value, true, true))
value = 0;
arg->constant = arg->value = value;
}
break;
case X86_OP_IMM:
{
arg->type = arg_normal;
arg->constant = arg->value = (duint)op.imm;
}
break;
case X86_OP_MEM:
{
arg->type = arg_memory;
const x86_op_mem & mem = op.mem;
if(mem.base == X86_REG_RIP) //rip-relative
arg->constant = cp.Address() + (duint)mem.disp + cp.Size();
else
arg->constant = (duint)mem.disp;
duint value;
if(!valfromstring(arg->mnemonic, &value, true, true))
return;
arg->value = value;
if(DbgMemIsValidReadPtr(value))
{
switch(op.size)
{
case 1:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 1);
break;
case 2:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 2);
break;
case 4:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 4);
break;
case 8:
DbgMemRead(value, (unsigned char*)&arg->memvalue, 8);
break;
}
}
}
break;
}
}
void disasmget(unsigned char* buffer, duint addr, DISASM_INSTR* instr)
{
if(!DbgIsDebugging())
{
if(instr)
instr->argcount = 0;
return;
}
memset(instr, 0, sizeof(DISASM_INSTR));
Capstone cp;
if(!cp.Disassemble(addr, buffer, MAX_DISASM_BUFFER))
{
strcpy_s(instr->instruction, "???");
instr->instr_size = 1;
instr->type = instr_normal;
instr->argcount = 0;
return;
}
const cs_insn* cpInstr = cp.GetInstr();
sprintf_s(instr->instruction, "%s %s", cpInstr->mnemonic, cpInstr->op_str);
instr->instr_size = cpInstr->size;
if(cp.InGroup(CS_GRP_JUMP) || cp.IsLoop() || cp.InGroup(CS_GRP_RET) || cp.InGroup(CS_GRP_CALL))
instr->type = instr_branch;
else if(strstr(cpInstr->op_str, "sp") || strstr(cpInstr->op_str, "bp"))
instr->type = instr_stack;
else
instr->type = instr_normal;
instr->argcount = cp.x86().op_count <= 3 ? cp.x86().op_count : 3;
for(int i = 0; i < instr->argcount; i++)
HandleCapstoneOperand(cp, i, &instr->arg[i]);
}
void disasmget(duint addr, DISASM_INSTR* instr)
{
if(!DbgIsDebugging())
{
if(instr)
instr->argcount = 0;
return;
}
unsigned char buffer[MAX_DISASM_BUFFER] = "";
DbgMemRead(addr, buffer, sizeof(buffer));
disasmget(buffer, addr, instr);
}
void disasmprint(duint addr)
{
DISASM_INSTR instr;
memset(&instr, 0, sizeof(instr));
disasmget(addr, &instr);
dprintf(">%d:\"%s\":\n", instr.type, instr.instruction);
for(int i = 0; i < instr.argcount; i++)
dprintf(" %d:%d:%" fext "X:%" fext "X:%" fext "X\n", i, instr.arg[i].type, instr.arg[i].constant, instr.arg[i].value, instr.arg[i].memvalue);
}
static bool isasciistring(const unsigned char* data, int maxlen)
{
int len = 0;
for(char* p = (char*)data; *p; len++, p++)
{
if(len >= maxlen)
break;
}
if(len < 2 || len + 1 >= maxlen)
return false;
for(int i = 0; i < len; i++)
if(!isprint(data[i]) && !isspace(data[i]))
return false;
return true;
}
static bool isunicodestring(const unsigned char* data, int maxlen)
{
int len = 0;
for(wchar_t* p = (wchar_t*)data; *p; len++, p++)
{
if(len >= maxlen)
break;
}
if(len < 2 || len + 1 >= maxlen)
return false;
for(int i = 0; i < len * 2; i += 2)
{
if(data[i + 1]) //Extended ASCII only
return false;
if(!isprint(data[i]) && !isspace(data[i]))
return false;
}
return true;
}
bool disasmispossiblestring(duint addr)
{
unsigned char data[11];
memset(data, 0, sizeof(data));
if(!MemRead(addr, data, sizeof(data) - 3))
return false;
duint test = 0;
memcpy(&test, data, sizeof(duint));
if(isasciistring(data, sizeof(data)) || isunicodestring(data, _countof(data)))
return true;
return false;
}
bool disasmgetstringat(duint addr, STRING_TYPE* type, char* ascii, char* unicode, int maxlen)
{
if(type)
*type = str_none;
if(!disasmispossiblestring(addr))
return false;
Memory<unsigned char*> data((maxlen + 1) * 2, "disasmgetstringat:data");
if(!MemRead(addr, data(), (maxlen + 1) * 2))
return false;
// Save a few pointer casts
auto asciiData = (char*)data();
auto unicodeData = (wchar_t*)data();
// First check if this was an ASCII only string
if(isasciistring(data(), maxlen))
{
if(type)
*type = str_ascii;
// Escape the string
String escaped = StringUtils::Escape(asciiData);
// Copy data back to outgoing parameter
strncpy_s(ascii, min(int(escaped.length()) + 1, maxlen), escaped.c_str(), _TRUNCATE);
return true;
}
if(isunicodestring(data(), maxlen))
{
if(type)
*type = str_unicode;
// Determine string length only once, limited to output buffer size
int unicodeLength = min(int(wcslen(unicodeData)), maxlen);
// Truncate each wchar_t to char
for(int i = 0; i < unicodeLength; i++)
asciiData[i] = char(unicodeData[i] & 0xFF);
// Fix the null terminator (data len = maxlen + 1)
asciiData[unicodeLength] = '\0';
// Escape the string
String escaped = StringUtils::Escape(asciiData);
// Copy data back to outgoing parameter
strncpy_s(unicode, min(int(escaped.length()) + 1, maxlen), escaped.c_str(), _TRUNCATE);
return true;
}
return false;
}
int disasmgetsize(duint addr, unsigned char* data)
{
Capstone cp;
if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER))
return 1;
return cp.Size();
}
int disasmgetsize(duint addr)
{
char data[MAX_DISASM_BUFFER];
if(!MemRead(addr, data, sizeof(data)))
return 1;
return disasmgetsize(addr, (unsigned char*)data);
}

View File

@ -1,18 +1,18 @@
#ifndef _DISASM_HELPER_H
#define _DISASM_HELPER_H
#include "_global.h"
//functions
duint disasmback(unsigned char* data, duint base, duint size, duint ip, int n);
duint disasmnext(unsigned char* data, duint base, duint size, duint ip, int n);
const char* disasmtext(duint addr);
void disasmprint(duint addr);
void disasmget(unsigned char* buffer, duint addr, DISASM_INSTR* instr);
void disasmget(duint addr, DISASM_INSTR* instr);
bool disasmispossiblestring(duint addr);
bool disasmgetstringat(duint addr, STRING_TYPE* type, char* ascii, char* unicode, int maxlen);
int disasmgetsize(duint addr, unsigned char* data);
int disasmgetsize(duint addr);
#endif // _DISASM_HELPER_H
#ifndef _DISASM_HELPER_H
#define _DISASM_HELPER_H
#include "_global.h"
//functions
duint disasmback(unsigned char* data, duint base, duint size, duint ip, int n);
duint disasmnext(unsigned char* data, duint base, duint size, duint ip, int n);
const char* disasmtext(duint addr);
void disasmprint(duint addr);
void disasmget(unsigned char* buffer, duint addr, DISASM_INSTR* instr);
void disasmget(duint addr, DISASM_INSTR* instr);
bool disasmispossiblestring(duint addr);
bool disasmgetstringat(duint addr, STRING_TYPE* type, char* ascii, char* unicode, int maxlen);
int disasmgetsize(duint addr, unsigned char* data);
int disasmgetsize(duint addr);
#endif // _DISASM_HELPER_H

View File

@ -1,56 +1,56 @@
#pragma once
template<typename T>
class Memory
{
public:
//
// This class guarantees that the returned allocated memory
// will always be zeroed
//
explicit Memory(const char* Reason = "Memory:???")
{
m_Ptr = nullptr;
m_Size = 0;
m_Reason = Reason;
}
explicit Memory(size_t Size, const char* Reason = "Memory:???")
{
m_Ptr = reinterpret_cast<T>(emalloc(Size));
m_Size = Size;
m_Reason = Reason;
memset(m_Ptr, 0, Size);
}
~Memory()
{
if(m_Ptr)
efree(m_Ptr);
}
T realloc(size_t Size, const char* Reason = "Memory:???")
{
m_Ptr = reinterpret_cast<T>(erealloc(m_Ptr, Size));
m_Size = Size;
m_Reason = Reason;
return (T)memset(m_Ptr, 0, m_Size);
}
size_t size()
{
return m_Size;
}
T operator()()
{
return m_Ptr;
}
private:
T m_Ptr;
size_t m_Size;
const char* m_Reason;
#pragma once
template<typename T>
class Memory
{
public:
//
// This class guarantees that the returned allocated memory
// will always be zeroed
//
explicit Memory(const char* Reason = "Memory:???")
{
m_Ptr = nullptr;
m_Size = 0;
m_Reason = Reason;
}
explicit Memory(size_t Size, const char* Reason = "Memory:???")
{
m_Ptr = reinterpret_cast<T>(emalloc(Size));
m_Size = Size;
m_Reason = Reason;
memset(m_Ptr, 0, Size);
}
~Memory()
{
if(m_Ptr)
efree(m_Ptr);
}
T realloc(size_t Size, const char* Reason = "Memory:???")
{
m_Ptr = reinterpret_cast<T>(erealloc(m_Ptr, Size));
m_Size = Size;
m_Reason = Reason;
return (T)memset(m_Ptr, 0, m_Size);
}
size_t size()
{
return m_Size;
}
T operator()()
{
return m_Ptr;
}
private:
T m_Ptr;
size_t m_Size;
const char* m_Reason;
};

View File

@ -1,149 +1,149 @@
#pragma once
#include "memory.h"
template<typename T, bool ReadOnly = false, bool BreakOnFail = false>
class RemotePtr;
template<typename T, typename U>
RemotePtr<U> RemoteMemberPtr(duint Address, U T::*Member)
{
// Calculate the offset from the member to the class base
duint offset = ((char*) & ((T*)nullptr->*Member) - (char*)nullptr);
return RemotePtr<U>(Address + offset);
}
template<typename T, bool ReadOnly, bool BreakOnFail>
class RemotePtr
{
// Special template part of this class, everything here
// should not be touched
template<bool Condition, typename U>
using enableIf = typename std::enable_if<Condition, U>::type;
template<typename U>
using makePtrRemote = RemotePtr<U, ReadOnly, BreakOnFail>;
template<typename U>
struct isClass : std::integral_constant < bool, std::is_class<std::remove_pointer<U>>::value ||
std::is_class<std::remove_reference<U>>::value > {};
template<typename U>
struct isPtrClass : std::integral_constant < bool, !std::is_arithmetic<U>::value &&
isClass<U>::value > {};
public:
explicit RemotePtr(duint Address)
{
Init(Address);
}
explicit RemotePtr(PVOID Address)
{
Init((duint)Address);
}
~RemotePtr()
{
if(!ReadOnly && m_Modified)
Sync();
}
T get()
{
// Read the external program data; no user edits
Update();
return m_InternalData;
}
template<typename A, typename B, typename C = typename std::remove_pointer<A>::type>
enableIf<isPtrClass<A>::value, makePtrRemote<C>> next(A B::*Member)
{
// First the pointer is read
auto ptr = RemotePtr<PVOID, ReadOnly, BreakOnFail>(m_InternalAddr + memberOffset(Member));
// Now return the real data structure
return makePtrRemote<C>(ptr.get());
}
template<typename A, typename B>
enableIf<std::is_arithmetic<A>::value, makePtrRemote<A>> next(A B::*Member)
{
// Return direct value with adjusted offset
return makePtrRemote<A>(m_InternalAddr + memberOffset(Member));
}
template<typename A, typename B = T>
enableIf<isClass<T>::value, duint> memberOffset(A B::*Member)
{
return (char*) & ((typename std::remove_pointer<T>::type*)nullptr->*Member) - (char*)nullptr;
}
T* operator->()
{
// The user could modify our internal structure after
// return
m_Modified = true;
// Read the external program data; return a pointer
Update();
return &m_InternalData;
}
T operator=(const T & rhs)
{
// This operation is only allowed with ReadOnly==false
if(!ReadOnly)
{
// Otherwise sync it with the external program.
// The external program can be messing with data at the same time.
m_InternalData = rhs;
Sync();
// Re-read data and then send it to the user
return get();
}
if(BreakOnFail)
__debugbreak();
return rhs;
}
T operator()()
{
return get();
}
private:
inline void Update()
{
MemRead(m_InternalAddr, &m_InternalData, sizeof(T));
}
inline void Sync()
{
if(BreakOnFail)
{
if(ReadOnly)
__debugbreak();
if(!MemWrite(m_InternalAddr, &m_InternalData, sizeof(T)))
__debugbreak();
}
m_Modified = false;
}
inline void Init(duint Address)
{
m_Modified = false;
m_InternalAddr = Address;
memset(&m_InternalData, 0, sizeof(T));
}
bool m_Modified;
duint m_InternalAddr;
T m_InternalData;
#pragma once
#include "memory.h"
template<typename T, bool ReadOnly = false, bool BreakOnFail = false>
class RemotePtr;
template<typename T, typename U>
RemotePtr<U> RemoteMemberPtr(duint Address, U T::*Member)
{
// Calculate the offset from the member to the class base
duint offset = ((char*) & ((T*)nullptr->*Member) - (char*)nullptr);
return RemotePtr<U>(Address + offset);
}
template<typename T, bool ReadOnly, bool BreakOnFail>
class RemotePtr
{
// Special template part of this class, everything here
// should not be touched
template<bool Condition, typename U>
using enableIf = typename std::enable_if<Condition, U>::type;
template<typename U>
using makePtrRemote = RemotePtr<U, ReadOnly, BreakOnFail>;
template<typename U>
struct isClass : std::integral_constant < bool, std::is_class<std::remove_pointer<U>>::value ||
std::is_class<std::remove_reference<U>>::value > {};
template<typename U>
struct isPtrClass : std::integral_constant < bool, !std::is_arithmetic<U>::value &&
isClass<U>::value > {};
public:
explicit RemotePtr(duint Address)
{
Init(Address);
}
explicit RemotePtr(PVOID Address)
{
Init((duint)Address);
}
~RemotePtr()
{
if(!ReadOnly && m_Modified)
Sync();
}
T get()
{
// Read the external program data; no user edits
Update();
return m_InternalData;
}
template<typename A, typename B, typename C = typename std::remove_pointer<A>::type>
enableIf<isPtrClass<A>::value, makePtrRemote<C>> next(A B::*Member)
{
// First the pointer is read
auto ptr = RemotePtr<PVOID, ReadOnly, BreakOnFail>(m_InternalAddr + memberOffset(Member));
// Now return the real data structure
return makePtrRemote<C>(ptr.get());
}
template<typename A, typename B>
enableIf<std::is_arithmetic<A>::value, makePtrRemote<A>> next(A B::*Member)
{
// Return direct value with adjusted offset
return makePtrRemote<A>(m_InternalAddr + memberOffset(Member));
}
template<typename A, typename B = T>
enableIf<isClass<T>::value, duint> memberOffset(A B::*Member)
{
return (char*) & ((typename std::remove_pointer<T>::type*)nullptr->*Member) - (char*)nullptr;
}
T* operator->()
{
// The user could modify our internal structure after
// return
m_Modified = true;
// Read the external program data; return a pointer
Update();
return &m_InternalData;
}
T operator=(const T & rhs)
{
// This operation is only allowed with ReadOnly==false
if(!ReadOnly)
{
// Otherwise sync it with the external program.
// The external program can be messing with data at the same time.
m_InternalData = rhs;
Sync();
// Re-read data and then send it to the user
return get();
}
if(BreakOnFail)
__debugbreak();
return rhs;
}
T operator()()
{
return get();
}
private:
inline void Update()
{
MemRead(m_InternalAddr, &m_InternalData, sizeof(T));
}
inline void Sync()
{
if(BreakOnFail)
{
if(ReadOnly)
__debugbreak();
if(!MemWrite(m_InternalAddr, &m_InternalData, sizeof(T)))
__debugbreak();
}
m_Modified = false;
}
inline void Init(duint Address)
{
m_Modified = false;
m_InternalAddr = Address;
memset(&m_InternalData, 0, sizeof(T));
}
bool m_Modified;
duint m_InternalAddr;
T m_InternalData;
};

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More