PROJECT: fixed line endings (hopefully for good now)
This commit is contained in:
parent
6508104c81
commit
1731e1dee5
Binary file not shown.
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
2028
src/dbg/_exports.cpp
2028
src/dbg/_exports.cpp
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||