PROJECT: RESTRUCTURE
This commit is contained in:
		
							parent
							
								
									cb173d28a1
								
							
						
					
					
						commit
						2297a92935
					
				
							
								
								
									
										
											BIN
										
									
								
								AStyle.dll
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								AStyle.dll
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								AStyleWhore.exe
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								AStyleWhore.exe
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -1,2 +0,0 @@ | |||
| # this file is only for the people who have serious mental issues (USE WITH CAUTION, THIS DOESN'T WORK) | ||||
| /\s*([\^+\-*=&|<>\/%!]|<<|>>)?\s*=\s*/ -> / \1= / | ||||
|  | @ -4,13 +4,13 @@ | |||
| # | ||||
| 
 | ||||
| #check if the formatter is present | ||||
| if [ ! -f ./AStyleWhore.exe ]; then | ||||
| if [ ! -f ./hooks/AStyleWhore.exe ]; then | ||||
|     echo "AStyleWhore not found!" | ||||
|     exit 0 | ||||
| fi | ||||
| 
 | ||||
| #format the code | ||||
| "./AStyleWhore.exe" Silent | ||||
| "./hooks/AStyleWhore.exe" Silent | ||||
| 
 | ||||
| #exit when nothing needs to be done | ||||
| if [ $? == 0 ]; then | ||||
|  | @ -28,6 +28,6 @@ fi | |||
| #cancel commit if the changes were undone by the formatting | ||||
| gitFiles=$(git diff-index --name-only --cached HEAD) | ||||
| if [ -z "$gitFiles" ]; then | ||||
|     "./AStyleWhore.exe" "After formatting, no files were staged..." | ||||
|     "./hooks/AStyleWhore.exe" "After formatting, no files were staged..." | ||||
|     exit 1 | ||||
| fi | ||||
|  |  | |||
|  | @ -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>$(SolutionDir)bin\x32\</OutDir> | ||||
|     <IntDir>$(Platform)\$(Configuration)\</IntDir> | ||||
|     <TargetName>x32bridge</TargetName> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | ||||
|     <LinkIncremental>false</LinkIncremental> | ||||
|     <OutDir>$(SolutionDir)bin\x32\</OutDir> | ||||
|     <IntDir>$(Platform)\$(Configuration)\</IntDir> | ||||
|     <TargetName>x32bridge</TargetName> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | ||||
|     <LinkIncremental>false</LinkIncremental> | ||||
|     <OutDir>$(SolutionDir)bin\x64\</OutDir> | ||||
|     <TargetName>x64bridge</TargetName> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | ||||
|     <LinkIncremental>false</LinkIncremental> | ||||
|     <OutDir>$(SolutionDir)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>..\..\bin\x32\</OutDir> | ||||
|     <IntDir>$(Platform)\$(Configuration)\</IntDir> | ||||
|     <TargetName>x32bridge</TargetName> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | ||||
|     <LinkIncremental>false</LinkIncremental> | ||||
|     <OutDir>..\..\bin\x32\</OutDir> | ||||
|     <IntDir>$(Platform)\$(Configuration)\</IntDir> | ||||
|     <TargetName>x32bridge</TargetName> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | ||||
|     <LinkIncremental>false</LinkIncremental> | ||||
|     <OutDir>..\..\bin\x64\</OutDir> | ||||
|     <TargetName>x64bridge</TargetName> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | ||||
|     <LinkIncremental>false</LinkIncremental> | ||||
|     <OutDir>..\..\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,35 +1,35 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
|   <ItemGroup> | ||||
|     <Filter Include="Source Files"> | ||||
|       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | ||||
|       <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | ||||
|     </Filter> | ||||
|     <Filter Include="Header Files"> | ||||
|       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> | ||||
|       <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> | ||||
|     </Filter> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClCompile Include="_global.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="bridgemain.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="_global.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="bridgemain.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="Utf8Ini.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="bridgelist.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|   </ItemGroup> | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
|   <ItemGroup> | ||||
|     <Filter Include="Source Files"> | ||||
|       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | ||||
|       <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | ||||
|     </Filter> | ||||
|     <Filter Include="Header Files"> | ||||
|       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> | ||||
|       <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> | ||||
|     </Filter> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClCompile Include="_global.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="bridgemain.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="_global.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="bridgemain.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="Utf8Ini.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="bridgelist.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB | 
| Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB | 
|  | @ -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
 | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												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 "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)) | ||||
|     { | ||||
|         uint rva = addr - (uint)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() | ||||
| { | ||||
|     dbggetprivateusage(fdProcessInfo->hProcess, true); | ||||
|     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 "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)) | ||||
|     { | ||||
|         uint rva = addr - (uint)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() | ||||
| { | ||||
|     dbggetprivateusage(fdProcessInfo->hProcess, true); | ||||
|     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
 | ||||
										
											
												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 uint _dbg_getbranchdestination(uint addr); | ||||
| DLL_EXPORT bool _dbg_functionoverlaps(uint start, uint end); | ||||
| DLL_EXPORT uint _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 uint _dbg_getbranchdestination(uint addr); | ||||
| DLL_EXPORT bool _dbg_functionoverlaps(uint start, uint end); | ||||
| DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* param2); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif // _EXPORTS_H
 | ||||
|  | @ -1,364 +1,364 @@ | |||
| /**
 | ||||
| \file _global.cpp | ||||
| \brief Implements the global class. | ||||
| */ | ||||
| 
 | ||||
| #include "_global.h" | ||||
| #include <objbase.h> | ||||
| #include <shlobj.h> | ||||
| 
 | ||||
| /**
 | ||||
| \brief x64dbg library instance. | ||||
| */ | ||||
| HINSTANCE hInst; | ||||
| 
 | ||||
| /**
 | ||||
| \brief Directory where program databases are stored (usually in \db). UTF-8 encoding. | ||||
| */ | ||||
| char dbbasepath[deflen] = ""; | ||||
| 
 | ||||
| /**
 | ||||
| \brief Path of the current program database. UTF-8 encoding. | ||||
| */ | ||||
| char dbpath[3 * deflen] = ""; | ||||
| 
 | ||||
| /**
 | ||||
| \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) | ||||
| { | ||||
|     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) | ||||
| { | ||||
|     if(!ptr) | ||||
|         return emalloc(size, reason); | ||||
|     unsigned char* a = (unsigned char*)GlobalReAlloc(ptr, size, GMEM_ZEROINIT | GMEM_MOVEABLE); | ||||
|     if(!a) | ||||
|     { | ||||
|         MessageBoxA(0, "Could not reallocate memory", "Error", MB_ICONERROR); | ||||
|         ExitProcess(1); | ||||
|     } | ||||
|     memset(a, 0, size); | ||||
|     /*
 | ||||
|     FILE* file = fopen(alloctrace, "a+"); | ||||
|     fprintf(file, "DBG%.5d:realloc:" fhex ":%s:" fhex "\n", emalloc_count, a, reason, size); | ||||
|     fclose(file); | ||||
|     */ | ||||
|     return a; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \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) | ||||
| { | ||||
|     uint 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 Directory where program databases are stored (usually in \db). UTF-8 encoding. | ||||
| */ | ||||
| char dbbasepath[deflen] = ""; | ||||
| 
 | ||||
| /**
 | ||||
| \brief Path of the current program database. UTF-8 encoding. | ||||
| */ | ||||
| char dbpath[3 * deflen] = ""; | ||||
| 
 | ||||
| /**
 | ||||
| \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) | ||||
| { | ||||
|     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) | ||||
| { | ||||
|     if(!ptr) | ||||
|         return emalloc(size, reason); | ||||
|     unsigned char* a = (unsigned char*)GlobalReAlloc(ptr, size, GMEM_ZEROINIT | GMEM_MOVEABLE); | ||||
|     if(!a) | ||||
|     { | ||||
|         MessageBoxA(0, "Could not reallocate memory", "Error", MB_ICONERROR); | ||||
|         ExitProcess(1); | ||||
|     } | ||||
|     memset(a, 0, size); | ||||
|     /*
 | ||||
|     FILE* file = fopen(alloctrace, "a+"); | ||||
|     fprintf(file, "DBG%.5d:realloc:" fhex ":%s:" fhex "\n", emalloc_count, a, reason, size); | ||||
|     fclose(file); | ||||
|     */ | ||||
|     return a; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \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) | ||||
| { | ||||
|     uint 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,88 +1,88 @@ | |||
| #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 "..\x64_dbg_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" | ||||
| typedef unsigned long long uint; | ||||
| typedef long long sint; | ||||
| #else | ||||
| #define fhex "%.8X" | ||||
| #define fext "" | ||||
| typedef unsigned long uint; | ||||
| typedef long sint; | ||||
| #endif // _WIN64
 | ||||
| 
 | ||||
| enum arch | ||||
| { | ||||
|     notfound, | ||||
|     invalid, | ||||
|     x32, | ||||
|     x64 | ||||
| }; | ||||
| 
 | ||||
| //superglobal variables
 | ||||
| extern HINSTANCE hInst; | ||||
| extern char dbbasepath[deflen]; | ||||
| extern char dbpath[3 * deflen]; | ||||
| 
 | ||||
| //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 "..\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" | ||||
| typedef unsigned long long uint; | ||||
| typedef long long sint; | ||||
| #else | ||||
| #define fhex "%.8X" | ||||
| #define fext "" | ||||
| typedef unsigned long uint; | ||||
| typedef long sint; | ||||
| #endif // _WIN64
 | ||||
| 
 | ||||
| enum arch | ||||
| { | ||||
|     notfound, | ||||
|     invalid, | ||||
|     x32, | ||||
|     x64 | ||||
| }; | ||||
| 
 | ||||
| //superglobal variables
 | ||||
| extern HINSTANCE hInst; | ||||
| extern char dbbasepath[deflen]; | ||||
| extern char dbpath[3 * deflen]; | ||||
| 
 | ||||
| //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,89 +1,89 @@ | |||
| #include "_scriptapi_memory.h" | ||||
| #include "memory.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::Read(duint addr, void* data, duint size, duint* sizeRead) | ||||
| { | ||||
|     return MemRead(addr, data, size, sizeRead); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::Write(duint addr, const void* data, duint size, duint* sizeWritten) | ||||
| { | ||||
|     return MemWrite(addr, (void*)data, size, sizeWritten); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::IsValidPtr(duint addr) | ||||
| { | ||||
|     return MemIsValidReadPtr(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Memory::RemoteAlloc(duint addr, duint size) | ||||
| { | ||||
|     return (duint)MemAllocRemote(addr, size); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::RemoteFree(duint addr) | ||||
| { | ||||
|     return MemFreeRemote(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned char Script::Memory::ReadByte(duint addr) | ||||
| { | ||||
|     unsigned char data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WriteByte(duint addr, unsigned char data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned short Script::Memory::ReadWord(duint addr) | ||||
| { | ||||
|     unsigned short data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WriteWord(duint addr, unsigned short data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned int Script::Memory::ReadDword(duint addr) | ||||
| { | ||||
|     unsigned int data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WriteDword(duint addr, unsigned int data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| SCRIPT_EXPORT unsigned long long Script::Memory::ReadQword(duint addr) | ||||
| { | ||||
|     unsigned long long data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WriteQword(duint addr, unsigned long long data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
| #endif //_WIN64
 | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Memory::ReadPtr(duint addr) | ||||
| { | ||||
|     duint data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WritePtr(duint addr, duint data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| #include "_scriptapi_memory.h" | ||||
| #include "memory.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::Read(duint addr, void* data, duint size, duint* sizeRead) | ||||
| { | ||||
|     return MemRead(addr, data, size, sizeRead); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::Write(duint addr, const void* data, duint size, duint* sizeWritten) | ||||
| { | ||||
|     return MemWrite(addr, (void*)data, size, sizeWritten); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::IsValidPtr(duint addr) | ||||
| { | ||||
|     return MemIsValidReadPtr(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Memory::RemoteAlloc(duint addr, duint size) | ||||
| { | ||||
|     return (duint)MemAllocRemote(addr, size); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::RemoteFree(duint addr) | ||||
| { | ||||
|     return MemFreeRemote(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned char Script::Memory::ReadByte(duint addr) | ||||
| { | ||||
|     unsigned char data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WriteByte(duint addr, unsigned char data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned short Script::Memory::ReadWord(duint addr) | ||||
| { | ||||
|     unsigned short data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WriteWord(duint addr, unsigned short data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned int Script::Memory::ReadDword(duint addr) | ||||
| { | ||||
|     unsigned int data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WriteDword(duint addr, unsigned int data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| SCRIPT_EXPORT unsigned long long Script::Memory::ReadQword(duint addr) | ||||
| { | ||||
|     unsigned long long data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WriteQword(duint addr, unsigned long long data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
| #endif //_WIN64
 | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Memory::ReadPtr(duint addr) | ||||
| { | ||||
|     duint data; | ||||
|     Read(addr, &data, sizeof(data), nullptr); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Memory::WritePtr(duint addr, duint data) | ||||
| { | ||||
|     return Write(addr, &data, sizeof(data), nullptr); | ||||
| } | ||||
|  | @ -1,31 +1,31 @@ | |||
| #ifndef _SCRIPTAPI_MEMORY_H | ||||
| #define _SCRIPTAPI_MEMORY_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Memory | ||||
| { | ||||
| SCRIPT_EXPORT bool Read(duint addr, void* data, duint size, duint* sizeRead); | ||||
| SCRIPT_EXPORT bool Write(duint addr, const void* data, duint size, duint* sizeWritten); | ||||
| SCRIPT_EXPORT bool IsValidPtr(duint addr); | ||||
| SCRIPT_EXPORT duint RemoteAlloc(duint addr, duint size); | ||||
| SCRIPT_EXPORT bool RemoteFree(duint addr); | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned char ReadByte(duint addr); | ||||
| SCRIPT_EXPORT bool WriteByte(duint addr, unsigned char data); | ||||
| SCRIPT_EXPORT unsigned short ReadWord(duint addr); | ||||
| SCRIPT_EXPORT bool WriteWord(duint addr, unsigned short data); | ||||
| SCRIPT_EXPORT unsigned int ReadDword(duint addr); | ||||
| SCRIPT_EXPORT bool WriteDword(duint addr, unsigned int data); | ||||
| #ifdef _WIN64 | ||||
| SCRIPT_EXPORT unsigned long long ReadQword(duint addr); | ||||
| SCRIPT_EXPORT bool WriteQword(duint addr, unsigned long long data); | ||||
| #endif //_WIN64
 | ||||
| SCRIPT_EXPORT duint ReadPtr(duint addr); | ||||
| SCRIPT_EXPORT bool WritePtr(duint addr, duint data); | ||||
| }; //Memory
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #ifndef _SCRIPTAPI_MEMORY_H | ||||
| #define _SCRIPTAPI_MEMORY_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Memory | ||||
| { | ||||
| SCRIPT_EXPORT bool Read(duint addr, void* data, duint size, duint* sizeRead); | ||||
| SCRIPT_EXPORT bool Write(duint addr, const void* data, duint size, duint* sizeWritten); | ||||
| SCRIPT_EXPORT bool IsValidPtr(duint addr); | ||||
| SCRIPT_EXPORT duint RemoteAlloc(duint addr, duint size); | ||||
| SCRIPT_EXPORT bool RemoteFree(duint addr); | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned char ReadByte(duint addr); | ||||
| SCRIPT_EXPORT bool WriteByte(duint addr, unsigned char data); | ||||
| SCRIPT_EXPORT unsigned short ReadWord(duint addr); | ||||
| SCRIPT_EXPORT bool WriteWord(duint addr, unsigned short data); | ||||
| SCRIPT_EXPORT unsigned int ReadDword(duint addr); | ||||
| SCRIPT_EXPORT bool WriteDword(duint addr, unsigned int data); | ||||
| #ifdef _WIN64 | ||||
| SCRIPT_EXPORT unsigned long long ReadQword(duint addr); | ||||
| SCRIPT_EXPORT bool WriteQword(duint addr, unsigned long long data); | ||||
| #endif //_WIN64
 | ||||
| SCRIPT_EXPORT duint ReadPtr(duint addr); | ||||
| SCRIPT_EXPORT bool WritePtr(duint addr, duint data); | ||||
| }; //Memory
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #endif //_SCRIPTAPI_MEMORY_H
 | ||||
|  | @ -1,33 +1,33 @@ | |||
| #include "_scriptapi_misc.h" | ||||
| #include "value.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Misc::ParseExpression(const char* expression, duint* value) | ||||
| { | ||||
|     return valfromstring(expression, value); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Misc::RemoteGetProcAddress(const char* module, const char* api) | ||||
| { | ||||
|     duint value; | ||||
|     if(!ParseExpression(StringUtils::sprintf("%s:%s", module, api).c_str(), &value)) | ||||
|         return 0; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Misc::ResolveLabel(const char* label) | ||||
| { | ||||
|     duint value; | ||||
|     if(!ParseExpression(label, &value)) | ||||
|         return 0; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT void* Script::Misc::Alloc(duint size) | ||||
| { | ||||
|     return BridgeAlloc(size); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT void Script::Misc::Free(void* ptr) | ||||
| { | ||||
|     return BridgeFree(ptr); | ||||
| #include "_scriptapi_misc.h" | ||||
| #include "value.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Misc::ParseExpression(const char* expression, duint* value) | ||||
| { | ||||
|     return valfromstring(expression, value); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Misc::RemoteGetProcAddress(const char* module, const char* api) | ||||
| { | ||||
|     duint value; | ||||
|     if(!ParseExpression(StringUtils::sprintf("%s:%s", module, api).c_str(), &value)) | ||||
|         return 0; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Misc::ResolveLabel(const char* label) | ||||
| { | ||||
|     duint value; | ||||
|     if(!ParseExpression(label, &value)) | ||||
|         return 0; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT void* Script::Misc::Alloc(duint size) | ||||
| { | ||||
|     return BridgeAlloc(size); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT void Script::Misc::Free(void* ptr) | ||||
| { | ||||
|     return BridgeFree(ptr); | ||||
| } | ||||
|  | @ -1,18 +1,18 @@ | |||
| #ifndef _SCRIPTAPI_MISC_H | ||||
| #define _SCRIPTAPI_MISC_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Misc | ||||
| { | ||||
| SCRIPT_EXPORT bool ParseExpression(const char* expression, duint* value); | ||||
| SCRIPT_EXPORT duint RemoteGetProcAddress(const char* module, const char* api); | ||||
| SCRIPT_EXPORT duint ResolveLabel(const char* label); | ||||
| SCRIPT_EXPORT void* Alloc(duint size); | ||||
| SCRIPT_EXPORT void Free(void* ptr); | ||||
| }; //Misc
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #ifndef _SCRIPTAPI_MISC_H | ||||
| #define _SCRIPTAPI_MISC_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Misc | ||||
| { | ||||
| SCRIPT_EXPORT bool ParseExpression(const char* expression, duint* value); | ||||
| SCRIPT_EXPORT duint RemoteGetProcAddress(const char* module, const char* api); | ||||
| SCRIPT_EXPORT duint ResolveLabel(const char* label); | ||||
| SCRIPT_EXPORT void* Alloc(duint size); | ||||
| SCRIPT_EXPORT void Free(void* ptr); | ||||
| }; //Misc
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #endif //_SCRIPTAPI_MISC_H
 | ||||
|  | @ -1,185 +1,185 @@ | |||
| #include "_scriptapi_module.h" | ||||
| #include "threading.h" | ||||
| #include "module.h" | ||||
| #include "debugger.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::InfoFromAddr(duint addr, Script::Module::ModuleInfo* info) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockModules); | ||||
|     MODINFO* modInfo = ModInfoFromAddr(addr); | ||||
|     if(!info || !modInfo) | ||||
|         return false; | ||||
|     info->base = modInfo->base; | ||||
|     info->size = modInfo->size; | ||||
|     info->entry = modInfo->entry; | ||||
|     info->sectionCount = int(modInfo->sections.size()); | ||||
|     strcpy_s(info->name, modInfo->name); | ||||
|     strcat_s(info->name, modInfo->extension); | ||||
|     strcpy_s(info->path, modInfo->path); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::InfoFromName(const char* name, Script::Module::ModuleInfo* info) | ||||
| { | ||||
|     return Module::InfoFromAddr(Module::BaseFromName(name), info); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::BaseFromAddr(duint addr) | ||||
| { | ||||
|     return ModBaseFromAddr(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::BaseFromName(const char* name) | ||||
| { | ||||
|     return ModBaseFromName(name); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::SizeFromAddr(duint addr) | ||||
| { | ||||
|     return ModSizeFromAddr(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::SizeFromName(const char* name) | ||||
| { | ||||
|     return Module::SizeFromAddr(Module::BaseFromName(name)); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::NameFromAddr(duint addr, char* name) | ||||
| { | ||||
|     return ModNameFromAddr(addr, name, true); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::PathFromAddr(duint addr, char* path) | ||||
| { | ||||
|     return !!ModPathFromAddr(addr, path, MAX_PATH); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::PathFromName(const char* name, char* path) | ||||
| { | ||||
|     return Module::PathFromAddr(Module::BaseFromName(name), path); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::EntryFromAddr(duint addr) | ||||
| { | ||||
|     return ModEntryFromAddr(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::EntryFromName(const char* name) | ||||
| { | ||||
|     return Module::EntryFromAddr(Module::BaseFromName(name)); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT int Script::Module::SectionCountFromAddr(duint addr) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockModules); | ||||
|     MODINFO* modInfo = ModInfoFromAddr(addr); | ||||
|     return modInfo ? int(modInfo->sections.size()) : 0; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT int Script::Module::SectionCountFromName(const char* name) | ||||
| { | ||||
|     return Module::SectionCountFromAddr(Module::BaseFromName(name)); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::SectionFromAddr(duint addr, int number, ModuleSectionInfo* section) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockModules); | ||||
|     MODINFO* modInfo = ModInfoFromAddr(addr); | ||||
|     if(!section || !modInfo || number < 0 || number >= int(modInfo->sections.size())) | ||||
|         return false; | ||||
|     const MODSECTIONINFO & secInfo = modInfo->sections.at(number); | ||||
|     section->addr = secInfo.addr; | ||||
|     section->size = secInfo.size; | ||||
|     strcpy_s(section->name, secInfo.name); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::SectionFromName(const char* name, int number, ModuleSectionInfo* section) | ||||
| { | ||||
|     return Module::SectionFromAddr(Module::BaseFromName(name), number, section); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::SectionListFromAddr(duint addr, ListOf(ModuleSectionInfo) listInfo) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockModules); | ||||
|     MODINFO* modInfo = ModInfoFromAddr(addr); | ||||
|     if(!modInfo) | ||||
|         return false; | ||||
|     std::vector<ModuleSectionInfo> scriptSectionList; | ||||
|     scriptSectionList.reserve(modInfo->sections.size()); | ||||
|     for(const auto & section : modInfo->sections) | ||||
|     { | ||||
|         ModuleSectionInfo scriptSection; | ||||
|         scriptSection.addr = section.addr; | ||||
|         scriptSection.size = section.size; | ||||
|         strcpy_s(scriptSection.name, section.name); | ||||
|         scriptSectionList.push_back(scriptSection); | ||||
|     } | ||||
|     return List<ModuleSectionInfo>::CopyData(listInfo, scriptSectionList); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::SectionListFromName(const char* name, ListOf(ModuleSectionInfo) listInfo) | ||||
| { | ||||
|     return Module::SectionListFromAddr(Module::BaseFromName(name), listInfo); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetMainModuleInfo(ModuleInfo* info) | ||||
| { | ||||
|     return Module::InfoFromAddr(Module::GetMainModuleBase(), info); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::GetMainModuleBase() | ||||
| { | ||||
|     return dbggetdebuggedbase(); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::GetMainModuleSize() | ||||
| { | ||||
|     return Module::SizeFromAddr(Module::GetMainModuleBase()); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::GetMainModuleEntry() | ||||
| { | ||||
|     return Module::EntryFromAddr(Module::GetMainModuleBase()); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT int Script::Module::GetMainModuleSectionCount() | ||||
| { | ||||
|     return Module::SectionCountFromAddr(Module::GetMainModuleBase()); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetMainModuleName(char* name) | ||||
| { | ||||
|     return Module::NameFromAddr(Module::GetMainModuleBase(), name); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetMainModulePath(char* path) | ||||
| { | ||||
|     return Module::PathFromAddr(Module::GetMainModuleBase(), path); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetMainModuleSectionList(ListOf(ModuleSectionInfo) listInfo) | ||||
| { | ||||
|     return Module::SectionListFromAddr(Module::GetMainModuleBase(), listInfo); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetList(ListOf(ModuleInfo) listInfo) | ||||
| { | ||||
|     std::vector<MODINFO> modList; | ||||
|     ModGetList(modList); | ||||
|     std::vector<ModuleInfo> modScriptList; | ||||
|     modScriptList.reserve(modList.size()); | ||||
|     for(const auto & mod : modList) | ||||
|     { | ||||
|         ModuleInfo scriptMod; | ||||
|         scriptMod.base = mod.base; | ||||
|         scriptMod.size = mod.size; | ||||
|         scriptMod.entry = mod.entry; | ||||
|         scriptMod.sectionCount = int(mod.sections.size()); | ||||
|         strcpy_s(scriptMod.name, mod.name); | ||||
|         strcat_s(scriptMod.name, mod.extension); | ||||
|         strcpy_s(scriptMod.path, mod.path); | ||||
|         modScriptList.push_back(scriptMod); | ||||
|     } | ||||
|     return List<ModuleInfo>::CopyData(listInfo, modScriptList); | ||||
| #include "_scriptapi_module.h" | ||||
| #include "threading.h" | ||||
| #include "module.h" | ||||
| #include "debugger.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::InfoFromAddr(duint addr, Script::Module::ModuleInfo* info) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockModules); | ||||
|     MODINFO* modInfo = ModInfoFromAddr(addr); | ||||
|     if(!info || !modInfo) | ||||
|         return false; | ||||
|     info->base = modInfo->base; | ||||
|     info->size = modInfo->size; | ||||
|     info->entry = modInfo->entry; | ||||
|     info->sectionCount = int(modInfo->sections.size()); | ||||
|     strcpy_s(info->name, modInfo->name); | ||||
|     strcat_s(info->name, modInfo->extension); | ||||
|     strcpy_s(info->path, modInfo->path); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::InfoFromName(const char* name, Script::Module::ModuleInfo* info) | ||||
| { | ||||
|     return Module::InfoFromAddr(Module::BaseFromName(name), info); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::BaseFromAddr(duint addr) | ||||
| { | ||||
|     return ModBaseFromAddr(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::BaseFromName(const char* name) | ||||
| { | ||||
|     return ModBaseFromName(name); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::SizeFromAddr(duint addr) | ||||
| { | ||||
|     return ModSizeFromAddr(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::SizeFromName(const char* name) | ||||
| { | ||||
|     return Module::SizeFromAddr(Module::BaseFromName(name)); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::NameFromAddr(duint addr, char* name) | ||||
| { | ||||
|     return ModNameFromAddr(addr, name, true); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::PathFromAddr(duint addr, char* path) | ||||
| { | ||||
|     return !!ModPathFromAddr(addr, path, MAX_PATH); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::PathFromName(const char* name, char* path) | ||||
| { | ||||
|     return Module::PathFromAddr(Module::BaseFromName(name), path); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::EntryFromAddr(duint addr) | ||||
| { | ||||
|     return ModEntryFromAddr(addr); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::EntryFromName(const char* name) | ||||
| { | ||||
|     return Module::EntryFromAddr(Module::BaseFromName(name)); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT int Script::Module::SectionCountFromAddr(duint addr) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockModules); | ||||
|     MODINFO* modInfo = ModInfoFromAddr(addr); | ||||
|     return modInfo ? int(modInfo->sections.size()) : 0; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT int Script::Module::SectionCountFromName(const char* name) | ||||
| { | ||||
|     return Module::SectionCountFromAddr(Module::BaseFromName(name)); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::SectionFromAddr(duint addr, int number, ModuleSectionInfo* section) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockModules); | ||||
|     MODINFO* modInfo = ModInfoFromAddr(addr); | ||||
|     if(!section || !modInfo || number < 0 || number >= int(modInfo->sections.size())) | ||||
|         return false; | ||||
|     const MODSECTIONINFO & secInfo = modInfo->sections.at(number); | ||||
|     section->addr = secInfo.addr; | ||||
|     section->size = secInfo.size; | ||||
|     strcpy_s(section->name, secInfo.name); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::SectionFromName(const char* name, int number, ModuleSectionInfo* section) | ||||
| { | ||||
|     return Module::SectionFromAddr(Module::BaseFromName(name), number, section); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::SectionListFromAddr(duint addr, ListOf(ModuleSectionInfo) listInfo) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockModules); | ||||
|     MODINFO* modInfo = ModInfoFromAddr(addr); | ||||
|     if(!modInfo) | ||||
|         return false; | ||||
|     std::vector<ModuleSectionInfo> scriptSectionList; | ||||
|     scriptSectionList.reserve(modInfo->sections.size()); | ||||
|     for(const auto & section : modInfo->sections) | ||||
|     { | ||||
|         ModuleSectionInfo scriptSection; | ||||
|         scriptSection.addr = section.addr; | ||||
|         scriptSection.size = section.size; | ||||
|         strcpy_s(scriptSection.name, section.name); | ||||
|         scriptSectionList.push_back(scriptSection); | ||||
|     } | ||||
|     return List<ModuleSectionInfo>::CopyData(listInfo, scriptSectionList); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::SectionListFromName(const char* name, ListOf(ModuleSectionInfo) listInfo) | ||||
| { | ||||
|     return Module::SectionListFromAddr(Module::BaseFromName(name), listInfo); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetMainModuleInfo(ModuleInfo* info) | ||||
| { | ||||
|     return Module::InfoFromAddr(Module::GetMainModuleBase(), info); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::GetMainModuleBase() | ||||
| { | ||||
|     return dbggetdebuggedbase(); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::GetMainModuleSize() | ||||
| { | ||||
|     return Module::SizeFromAddr(Module::GetMainModuleBase()); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Module::GetMainModuleEntry() | ||||
| { | ||||
|     return Module::EntryFromAddr(Module::GetMainModuleBase()); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT int Script::Module::GetMainModuleSectionCount() | ||||
| { | ||||
|     return Module::SectionCountFromAddr(Module::GetMainModuleBase()); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetMainModuleName(char* name) | ||||
| { | ||||
|     return Module::NameFromAddr(Module::GetMainModuleBase(), name); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetMainModulePath(char* path) | ||||
| { | ||||
|     return Module::PathFromAddr(Module::GetMainModuleBase(), path); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetMainModuleSectionList(ListOf(ModuleSectionInfo) listInfo) | ||||
| { | ||||
|     return Module::SectionListFromAddr(Module::GetMainModuleBase(), listInfo); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Module::GetList(ListOf(ModuleInfo) listInfo) | ||||
| { | ||||
|     std::vector<MODINFO> modList; | ||||
|     ModGetList(modList); | ||||
|     std::vector<ModuleInfo> modScriptList; | ||||
|     modScriptList.reserve(modList.size()); | ||||
|     for(const auto & mod : modList) | ||||
|     { | ||||
|         ModuleInfo scriptMod; | ||||
|         scriptMod.base = mod.base; | ||||
|         scriptMod.size = mod.size; | ||||
|         scriptMod.entry = mod.entry; | ||||
|         scriptMod.sectionCount = int(mod.sections.size()); | ||||
|         strcpy_s(scriptMod.name, mod.name); | ||||
|         strcat_s(scriptMod.name, mod.extension); | ||||
|         strcpy_s(scriptMod.path, mod.path); | ||||
|         modScriptList.push_back(scriptMod); | ||||
|     } | ||||
|     return List<ModuleInfo>::CopyData(listInfo, modScriptList); | ||||
| } | ||||
|  | @ -1,56 +1,56 @@ | |||
| #ifndef _SCRIPTAPI_MODULE_H | ||||
| #define _SCRIPTAPI_MODULE_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Module | ||||
| { | ||||
| struct ModuleInfo | ||||
| { | ||||
|     duint base; | ||||
|     duint size; | ||||
|     duint entry; | ||||
|     int sectionCount; | ||||
|     char name[MAX_MODULE_SIZE]; | ||||
|     char path[MAX_PATH]; | ||||
| }; | ||||
| 
 | ||||
| struct ModuleSectionInfo | ||||
| { | ||||
|     duint addr; | ||||
|     duint size; | ||||
|     char name[MAX_SECTION_SIZE * 5]; | ||||
| }; | ||||
| 
 | ||||
| SCRIPT_EXPORT bool InfoFromAddr(duint addr, ModuleInfo* info); | ||||
| SCRIPT_EXPORT bool InfoFromName(const char* name, ModuleInfo* info); | ||||
| SCRIPT_EXPORT duint BaseFromAddr(duint addr); | ||||
| SCRIPT_EXPORT duint BaseFromName(const char* name); | ||||
| SCRIPT_EXPORT duint SizeFromAddr(duint addr); | ||||
| SCRIPT_EXPORT duint SizeFromName(const char* name); | ||||
| SCRIPT_EXPORT bool NameFromAddr(duint addr, char* name); //name[MAX_MODULE_SIZE]
 | ||||
| SCRIPT_EXPORT bool PathFromAddr(duint addr, char* path); //path[MAX_MODULE_PATH_SIZE]
 | ||||
| SCRIPT_EXPORT bool PathFromName(const char* name, char* path); //path[MAX_PATH]
 | ||||
| SCRIPT_EXPORT duint EntryFromAddr(duint addr); | ||||
| SCRIPT_EXPORT duint EntryFromName(const char* name); | ||||
| SCRIPT_EXPORT int SectionCountFromAddr(duint addr); | ||||
| SCRIPT_EXPORT int SectionCountFromName(const char* name); | ||||
| SCRIPT_EXPORT bool SectionFromAddr(duint addr, int number, ModuleSectionInfo* section); | ||||
| SCRIPT_EXPORT bool SectionFromName(const char* name, int number, ModuleSectionInfo* section); | ||||
| SCRIPT_EXPORT bool SectionListFromAddr(duint addr, ListOf(ModuleSectionInfo) listInfo); | ||||
| SCRIPT_EXPORT bool SectionListFromName(const char* name, ListOf(ModuleSectionInfo) listInfo); | ||||
| SCRIPT_EXPORT bool GetMainModuleInfo(ModuleInfo* info); | ||||
| SCRIPT_EXPORT duint GetMainModuleBase(); | ||||
| SCRIPT_EXPORT duint GetMainModuleSize(); | ||||
| SCRIPT_EXPORT duint GetMainModuleEntry(); | ||||
| SCRIPT_EXPORT int GetMainModuleSectionCount(); | ||||
| SCRIPT_EXPORT bool GetMainModuleName(char* name); //name[MAX_MODULE_SIZE]
 | ||||
| SCRIPT_EXPORT bool GetMainModulePath(char* path); //path[MAX_PATH]
 | ||||
| SCRIPT_EXPORT bool GetMainModuleSectionList(ListOf(ModuleSectionInfo) listInfo); //caller has the responsibility to free the list
 | ||||
| SCRIPT_EXPORT bool GetList(ListOf(ModuleInfo) listInfo); //caller has the responsibility to free the list
 | ||||
| }; //Module
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #ifndef _SCRIPTAPI_MODULE_H | ||||
| #define _SCRIPTAPI_MODULE_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Module | ||||
| { | ||||
| struct ModuleInfo | ||||
| { | ||||
|     duint base; | ||||
|     duint size; | ||||
|     duint entry; | ||||
|     int sectionCount; | ||||
|     char name[MAX_MODULE_SIZE]; | ||||
|     char path[MAX_PATH]; | ||||
| }; | ||||
| 
 | ||||
| struct ModuleSectionInfo | ||||
| { | ||||
|     duint addr; | ||||
|     duint size; | ||||
|     char name[MAX_SECTION_SIZE * 5]; | ||||
| }; | ||||
| 
 | ||||
| SCRIPT_EXPORT bool InfoFromAddr(duint addr, ModuleInfo* info); | ||||
| SCRIPT_EXPORT bool InfoFromName(const char* name, ModuleInfo* info); | ||||
| SCRIPT_EXPORT duint BaseFromAddr(duint addr); | ||||
| SCRIPT_EXPORT duint BaseFromName(const char* name); | ||||
| SCRIPT_EXPORT duint SizeFromAddr(duint addr); | ||||
| SCRIPT_EXPORT duint SizeFromName(const char* name); | ||||
| SCRIPT_EXPORT bool NameFromAddr(duint addr, char* name); //name[MAX_MODULE_SIZE]
 | ||||
| SCRIPT_EXPORT bool PathFromAddr(duint addr, char* path); //path[MAX_MODULE_PATH_SIZE]
 | ||||
| SCRIPT_EXPORT bool PathFromName(const char* name, char* path); //path[MAX_PATH]
 | ||||
| SCRIPT_EXPORT duint EntryFromAddr(duint addr); | ||||
| SCRIPT_EXPORT duint EntryFromName(const char* name); | ||||
| SCRIPT_EXPORT int SectionCountFromAddr(duint addr); | ||||
| SCRIPT_EXPORT int SectionCountFromName(const char* name); | ||||
| SCRIPT_EXPORT bool SectionFromAddr(duint addr, int number, ModuleSectionInfo* section); | ||||
| SCRIPT_EXPORT bool SectionFromName(const char* name, int number, ModuleSectionInfo* section); | ||||
| SCRIPT_EXPORT bool SectionListFromAddr(duint addr, ListOf(ModuleSectionInfo) listInfo); | ||||
| SCRIPT_EXPORT bool SectionListFromName(const char* name, ListOf(ModuleSectionInfo) listInfo); | ||||
| SCRIPT_EXPORT bool GetMainModuleInfo(ModuleInfo* info); | ||||
| SCRIPT_EXPORT duint GetMainModuleBase(); | ||||
| SCRIPT_EXPORT duint GetMainModuleSize(); | ||||
| SCRIPT_EXPORT duint GetMainModuleEntry(); | ||||
| SCRIPT_EXPORT int GetMainModuleSectionCount(); | ||||
| SCRIPT_EXPORT bool GetMainModuleName(char* name); //name[MAX_MODULE_SIZE]
 | ||||
| SCRIPT_EXPORT bool GetMainModulePath(char* path); //path[MAX_PATH]
 | ||||
| SCRIPT_EXPORT bool GetMainModuleSectionList(ListOf(ModuleSectionInfo) listInfo); //caller has the responsibility to free the list
 | ||||
| SCRIPT_EXPORT bool GetList(ListOf(ModuleInfo) listInfo); //caller has the responsibility to free the list
 | ||||
| }; //Module
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #endif //_SCRIPTAPI_MODULE_H
 | ||||
|  | @ -1,48 +1,48 @@ | |||
| #include "_scriptapi_pattern.h" | ||||
| #include "patternfind.h" | ||||
| #include "memory.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Pattern::Find(unsigned char* data, duint datasize, const char* pattern) | ||||
| { | ||||
|     return patternfind(data, datasize, pattern); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Pattern::FindMem(duint start, duint size, const char* pattern) | ||||
| { | ||||
|     Memory<unsigned char*> data(size, "Script::Pattern::FindMem::data"); | ||||
|     if(!MemRead(start, data(), size)) | ||||
|         return -1; | ||||
|     return Pattern::Find(data(), data.size(), pattern) + start; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT void Script::Pattern::Write(unsigned char* data, duint datasize, const char* pattern) | ||||
| { | ||||
|     patternwrite(data, datasize, pattern); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT void Script::Pattern::WriteMem(duint start, duint size, const char* pattern) | ||||
| { | ||||
|     Memory<unsigned char*> data(size, "Script::Pattern::WriteMem::data"); | ||||
|     if(!MemRead(start, data(), data.size())) | ||||
|         return; | ||||
|     patternwrite(data(), data.size(), pattern); | ||||
|     MemWrite(start, data(), data.size()); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Pattern::SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern) | ||||
| { | ||||
|     return patternsnr(data, datasize, searchpattern, replacepattern); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Pattern::SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern) | ||||
| { | ||||
|     Memory<unsigned char*> data(size, "Script::Pattern::SearchAndReplaceMem::data"); | ||||
|     if(!MemRead(start, data(), size)) | ||||
|         return false; | ||||
|     duint found = patternfind(data(), data.size(), searchpattern); | ||||
|     if(found == -1) | ||||
|         return false; | ||||
|     patternwrite(data() + found, data.size() - found, replacepattern); | ||||
|     MemWrite((start + found), data() + found, data.size() - found); | ||||
|     return true; | ||||
| #include "_scriptapi_pattern.h" | ||||
| #include "patternfind.h" | ||||
| #include "memory.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Pattern::Find(unsigned char* data, duint datasize, const char* pattern) | ||||
| { | ||||
|     return patternfind(data, datasize, pattern); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Pattern::FindMem(duint start, duint size, const char* pattern) | ||||
| { | ||||
|     Memory<unsigned char*> data(size, "Script::Pattern::FindMem::data"); | ||||
|     if(!MemRead(start, data(), size)) | ||||
|         return -1; | ||||
|     return Pattern::Find(data(), data.size(), pattern) + start; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT void Script::Pattern::Write(unsigned char* data, duint datasize, const char* pattern) | ||||
| { | ||||
|     patternwrite(data, datasize, pattern); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT void Script::Pattern::WriteMem(duint start, duint size, const char* pattern) | ||||
| { | ||||
|     Memory<unsigned char*> data(size, "Script::Pattern::WriteMem::data"); | ||||
|     if(!MemRead(start, data(), data.size())) | ||||
|         return; | ||||
|     patternwrite(data(), data.size(), pattern); | ||||
|     MemWrite(start, data(), data.size()); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Pattern::SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern) | ||||
| { | ||||
|     return patternsnr(data, datasize, searchpattern, replacepattern); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT bool Script::Pattern::SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern) | ||||
| { | ||||
|     Memory<unsigned char*> data(size, "Script::Pattern::SearchAndReplaceMem::data"); | ||||
|     if(!MemRead(start, data(), size)) | ||||
|         return false; | ||||
|     duint found = patternfind(data(), data.size(), searchpattern); | ||||
|     if(found == -1) | ||||
|         return false; | ||||
|     patternwrite(data() + found, data.size() - found, replacepattern); | ||||
|     MemWrite((start + found), data() + found, data.size() - found); | ||||
|     return true; | ||||
| } | ||||
|  | @ -1,19 +1,19 @@ | |||
| #ifndef _SCRIPTAPI_PATTERN_H | ||||
| #define _SCRIPTAPI_PATTERN_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Pattern | ||||
| { | ||||
| SCRIPT_EXPORT duint Find(unsigned char* data, duint datasize, const char* pattern); | ||||
| SCRIPT_EXPORT duint FindMem(duint start, duint size, const char* pattern); | ||||
| SCRIPT_EXPORT void Write(unsigned char* data, duint datasize, const char* pattern); | ||||
| SCRIPT_EXPORT void WriteMem(duint start, duint size, const char* pattern); | ||||
| SCRIPT_EXPORT bool SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern); | ||||
| SCRIPT_EXPORT bool SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern); | ||||
| }; | ||||
| }; | ||||
| 
 | ||||
| #ifndef _SCRIPTAPI_PATTERN_H | ||||
| #define _SCRIPTAPI_PATTERN_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Pattern | ||||
| { | ||||
| SCRIPT_EXPORT duint Find(unsigned char* data, duint datasize, const char* pattern); | ||||
| SCRIPT_EXPORT duint FindMem(duint start, duint size, const char* pattern); | ||||
| SCRIPT_EXPORT void Write(unsigned char* data, duint datasize, const char* pattern); | ||||
| SCRIPT_EXPORT void WriteMem(duint start, duint size, const char* pattern); | ||||
| SCRIPT_EXPORT bool SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern); | ||||
| SCRIPT_EXPORT bool SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern); | ||||
| }; | ||||
| }; | ||||
| 
 | ||||
| #endif //_SCRIPTAPI_FIND_H
 | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -1,265 +1,265 @@ | |||
| #ifndef _SCRIPTAPI_REGISTER_H | ||||
| #define _SCRIPTAPI_REGISTER_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Register | ||||
| { | ||||
| enum RegisterEnum | ||||
| { | ||||
|     DR0, | ||||
|     DR1, | ||||
|     DR2, | ||||
|     DR3, | ||||
|     DR6, | ||||
|     DR7, | ||||
| 
 | ||||
|     EAX, | ||||
|     AX, | ||||
|     AH, | ||||
|     AL, | ||||
|     EBX, | ||||
|     BX, | ||||
|     BH, | ||||
|     BL, | ||||
|     ECX, | ||||
|     CX, | ||||
|     CH, | ||||
|     CL, | ||||
|     EDX, | ||||
|     DX, | ||||
|     DH, | ||||
|     DL, | ||||
|     EDI, | ||||
|     DI, | ||||
|     ESI, | ||||
|     SI, | ||||
|     EBP, | ||||
|     BP, | ||||
|     ESP, | ||||
|     SP, | ||||
|     EIP, | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
|     RAX, | ||||
|     RBX, | ||||
|     RCX, | ||||
|     RDX, | ||||
|     RSI, | ||||
|     SIL, | ||||
|     RDI, | ||||
|     DIL, | ||||
|     RBP, | ||||
|     BPL, | ||||
|     RSP, | ||||
|     SPL, | ||||
|     RIP, | ||||
|     R8, | ||||
|     R8D, | ||||
|     R8W, | ||||
|     R8B, | ||||
|     R9, | ||||
|     R9D, | ||||
|     R9W, | ||||
|     R9B, | ||||
|     R10, | ||||
|     R10D, | ||||
|     R10W, | ||||
|     R10B, | ||||
|     R11, | ||||
|     R11D, | ||||
|     R11W, | ||||
|     R11B, | ||||
|     R12, | ||||
|     R12D, | ||||
|     R12W, | ||||
|     R12B, | ||||
|     R13, | ||||
|     R13D, | ||||
|     R13W, | ||||
|     R13B, | ||||
|     R14, | ||||
|     R14D, | ||||
|     R14W, | ||||
|     R14B, | ||||
|     R15, | ||||
|     R15D, | ||||
|     R15W, | ||||
|     R15B, | ||||
| #endif //_WIN64
 | ||||
| 
 | ||||
|     CIP, | ||||
|     CSP, | ||||
| }; //RegisterEnum
 | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Get(RegisterEnum reg); | ||||
| SCRIPT_EXPORT bool Set(RegisterEnum reg, duint value); | ||||
| SCRIPT_EXPORT int Size(); //gets architecture register size in bytes
 | ||||
| 
 | ||||
| SCRIPT_EXPORT duint GetDR0(); | ||||
| SCRIPT_EXPORT bool SetDR0(duint value); | ||||
| SCRIPT_EXPORT duint GetDR1(); | ||||
| SCRIPT_EXPORT bool SetDR1(duint value); | ||||
| SCRIPT_EXPORT duint GetDR2(); | ||||
| SCRIPT_EXPORT bool SetDR2(duint value); | ||||
| SCRIPT_EXPORT duint GetDR3(); | ||||
| SCRIPT_EXPORT bool SetDR3(duint value); | ||||
| SCRIPT_EXPORT duint GetDR6(); | ||||
| SCRIPT_EXPORT bool SetDR6(duint value); | ||||
| SCRIPT_EXPORT duint GetDR7(); | ||||
| SCRIPT_EXPORT bool SetDR7(duint value); | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned int GetEAX(); | ||||
| SCRIPT_EXPORT bool SetEAX(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetAX(); | ||||
| SCRIPT_EXPORT bool SetAX(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetAH(); | ||||
| SCRIPT_EXPORT bool SetAH(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned char GetAL(); | ||||
| SCRIPT_EXPORT bool SetAL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned int GetEBX(); | ||||
| SCRIPT_EXPORT bool SetEBX(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetBX(); | ||||
| SCRIPT_EXPORT bool SetBX(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetBH(); | ||||
| SCRIPT_EXPORT bool SetBH(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned char GetBL(); | ||||
| SCRIPT_EXPORT bool SetBL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned int GetECX(); | ||||
| SCRIPT_EXPORT bool SetECX(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetCX(); | ||||
| SCRIPT_EXPORT bool SetCX(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetCH(); | ||||
| SCRIPT_EXPORT bool SetCH(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned char GetCL(); | ||||
| SCRIPT_EXPORT bool SetCL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned int GetEDX(); | ||||
| SCRIPT_EXPORT bool SetEDX(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetDX(); | ||||
| SCRIPT_EXPORT bool SetDX(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetDH(); | ||||
| SCRIPT_EXPORT bool SetDH(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned char GetDL(); | ||||
| SCRIPT_EXPORT bool SetDL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned int GetEDI(); | ||||
| SCRIPT_EXPORT bool SetEDI(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetDI(); | ||||
| SCRIPT_EXPORT bool SetDI(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned int GetESI(); | ||||
| SCRIPT_EXPORT bool SetESI(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetSI(); | ||||
| SCRIPT_EXPORT bool SetSI(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned int GetEBP(); | ||||
| SCRIPT_EXPORT bool SetEBP(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetBP(); | ||||
| SCRIPT_EXPORT bool SetBP(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned int GetESP(); | ||||
| SCRIPT_EXPORT bool SetESP(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetSP(); | ||||
| SCRIPT_EXPORT bool SetSP(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned int GetEIP(); | ||||
| SCRIPT_EXPORT bool SetEIP(unsigned int value); | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| SCRIPT_EXPORT unsigned long long GetRAX(); | ||||
| SCRIPT_EXPORT bool SetRAX(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetRBX(); | ||||
| SCRIPT_EXPORT bool SetRBX(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetRCX(); | ||||
| SCRIPT_EXPORT bool SetRCX(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetRDX(); | ||||
| SCRIPT_EXPORT bool SetRDX(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetRSI(); | ||||
| SCRIPT_EXPORT bool SetRSI(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned char GetSIL(); | ||||
| SCRIPT_EXPORT bool SetSIL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetRDI(); | ||||
| SCRIPT_EXPORT bool SetRDI(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned char GetDIL(); | ||||
| SCRIPT_EXPORT bool SetDIL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetRBP(); | ||||
| SCRIPT_EXPORT bool SetRBP(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned char GetBPL(); | ||||
| SCRIPT_EXPORT bool SetBPL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetRSP(); | ||||
| SCRIPT_EXPORT bool SetRSP(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned char GetSPL(); | ||||
| SCRIPT_EXPORT bool SetSPL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetRIP(); | ||||
| SCRIPT_EXPORT bool SetRIP(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetR8(); | ||||
| SCRIPT_EXPORT bool SetR8(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR8D(); | ||||
| SCRIPT_EXPORT bool SetR8D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR8W(); | ||||
| SCRIPT_EXPORT bool SetR8W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR8B(); | ||||
| SCRIPT_EXPORT bool SetR8B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR9(); | ||||
| SCRIPT_EXPORT bool SetR9(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR9D(); | ||||
| SCRIPT_EXPORT bool SetR9D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR9W(); | ||||
| SCRIPT_EXPORT bool SetR9W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR9B(); | ||||
| SCRIPT_EXPORT bool SetR9B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR10(); | ||||
| SCRIPT_EXPORT bool SetR10(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR10D(); | ||||
| SCRIPT_EXPORT bool SetR10D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR10W(); | ||||
| SCRIPT_EXPORT bool SetR10W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR10B(); | ||||
| SCRIPT_EXPORT bool SetR10B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR11(); | ||||
| SCRIPT_EXPORT bool SetR11(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR11D(); | ||||
| SCRIPT_EXPORT bool SetR11D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR11W(); | ||||
| SCRIPT_EXPORT bool SetR11W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR11B(); | ||||
| SCRIPT_EXPORT bool SetR11B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR12(); | ||||
| SCRIPT_EXPORT bool SetR12(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR12D(); | ||||
| SCRIPT_EXPORT bool SetR12D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR12W(); | ||||
| SCRIPT_EXPORT bool SetR12W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR12B(); | ||||
| SCRIPT_EXPORT bool SetR12B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR13(); | ||||
| SCRIPT_EXPORT bool SetR13(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR13D(); | ||||
| SCRIPT_EXPORT bool SetR13D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR13W(); | ||||
| SCRIPT_EXPORT bool SetR13W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR13B(); | ||||
| SCRIPT_EXPORT bool SetR13B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR14(); | ||||
| SCRIPT_EXPORT bool SetR14(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR14D(); | ||||
| SCRIPT_EXPORT bool SetR14D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR14W(); | ||||
| SCRIPT_EXPORT bool SetR14W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR14B(); | ||||
| SCRIPT_EXPORT bool SetR14B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR15(); | ||||
| SCRIPT_EXPORT bool SetR15(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR15D(); | ||||
| SCRIPT_EXPORT bool SetR15D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR15W(); | ||||
| SCRIPT_EXPORT bool SetR15W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR15B(); | ||||
| SCRIPT_EXPORT bool SetR15B(unsigned char value); | ||||
| #endif //_WIN64
 | ||||
| 
 | ||||
| SCRIPT_EXPORT duint GetCIP(); | ||||
| SCRIPT_EXPORT bool SetCIP(duint value); | ||||
| SCRIPT_EXPORT duint GetCSP(); | ||||
| SCRIPT_EXPORT bool SetCSP(duint value); | ||||
| }; //Register
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #ifndef _SCRIPTAPI_REGISTER_H | ||||
| #define _SCRIPTAPI_REGISTER_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Register | ||||
| { | ||||
| enum RegisterEnum | ||||
| { | ||||
|     DR0, | ||||
|     DR1, | ||||
|     DR2, | ||||
|     DR3, | ||||
|     DR6, | ||||
|     DR7, | ||||
| 
 | ||||
|     EAX, | ||||
|     AX, | ||||
|     AH, | ||||
|     AL, | ||||
|     EBX, | ||||
|     BX, | ||||
|     BH, | ||||
|     BL, | ||||
|     ECX, | ||||
|     CX, | ||||
|     CH, | ||||
|     CL, | ||||
|     EDX, | ||||
|     DX, | ||||
|     DH, | ||||
|     DL, | ||||
|     EDI, | ||||
|     DI, | ||||
|     ESI, | ||||
|     SI, | ||||
|     EBP, | ||||
|     BP, | ||||
|     ESP, | ||||
|     SP, | ||||
|     EIP, | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
|     RAX, | ||||
|     RBX, | ||||
|     RCX, | ||||
|     RDX, | ||||
|     RSI, | ||||
|     SIL, | ||||
|     RDI, | ||||
|     DIL, | ||||
|     RBP, | ||||
|     BPL, | ||||
|     RSP, | ||||
|     SPL, | ||||
|     RIP, | ||||
|     R8, | ||||
|     R8D, | ||||
|     R8W, | ||||
|     R8B, | ||||
|     R9, | ||||
|     R9D, | ||||
|     R9W, | ||||
|     R9B, | ||||
|     R10, | ||||
|     R10D, | ||||
|     R10W, | ||||
|     R10B, | ||||
|     R11, | ||||
|     R11D, | ||||
|     R11W, | ||||
|     R11B, | ||||
|     R12, | ||||
|     R12D, | ||||
|     R12W, | ||||
|     R12B, | ||||
|     R13, | ||||
|     R13D, | ||||
|     R13W, | ||||
|     R13B, | ||||
|     R14, | ||||
|     R14D, | ||||
|     R14W, | ||||
|     R14B, | ||||
|     R15, | ||||
|     R15D, | ||||
|     R15W, | ||||
|     R15B, | ||||
| #endif //_WIN64
 | ||||
| 
 | ||||
|     CIP, | ||||
|     CSP, | ||||
| }; //RegisterEnum
 | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Get(RegisterEnum reg); | ||||
| SCRIPT_EXPORT bool Set(RegisterEnum reg, duint value); | ||||
| SCRIPT_EXPORT int Size(); //gets architecture register size in bytes
 | ||||
| 
 | ||||
| SCRIPT_EXPORT duint GetDR0(); | ||||
| SCRIPT_EXPORT bool SetDR0(duint value); | ||||
| SCRIPT_EXPORT duint GetDR1(); | ||||
| SCRIPT_EXPORT bool SetDR1(duint value); | ||||
| SCRIPT_EXPORT duint GetDR2(); | ||||
| SCRIPT_EXPORT bool SetDR2(duint value); | ||||
| SCRIPT_EXPORT duint GetDR3(); | ||||
| SCRIPT_EXPORT bool SetDR3(duint value); | ||||
| SCRIPT_EXPORT duint GetDR6(); | ||||
| SCRIPT_EXPORT bool SetDR6(duint value); | ||||
| SCRIPT_EXPORT duint GetDR7(); | ||||
| SCRIPT_EXPORT bool SetDR7(duint value); | ||||
| 
 | ||||
| SCRIPT_EXPORT unsigned int GetEAX(); | ||||
| SCRIPT_EXPORT bool SetEAX(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetAX(); | ||||
| SCRIPT_EXPORT bool SetAX(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetAH(); | ||||
| SCRIPT_EXPORT bool SetAH(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned char GetAL(); | ||||
| SCRIPT_EXPORT bool SetAL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned int GetEBX(); | ||||
| SCRIPT_EXPORT bool SetEBX(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetBX(); | ||||
| SCRIPT_EXPORT bool SetBX(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetBH(); | ||||
| SCRIPT_EXPORT bool SetBH(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned char GetBL(); | ||||
| SCRIPT_EXPORT bool SetBL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned int GetECX(); | ||||
| SCRIPT_EXPORT bool SetECX(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetCX(); | ||||
| SCRIPT_EXPORT bool SetCX(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetCH(); | ||||
| SCRIPT_EXPORT bool SetCH(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned char GetCL(); | ||||
| SCRIPT_EXPORT bool SetCL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned int GetEDX(); | ||||
| SCRIPT_EXPORT bool SetEDX(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetDX(); | ||||
| SCRIPT_EXPORT bool SetDX(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetDH(); | ||||
| SCRIPT_EXPORT bool SetDH(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned char GetDL(); | ||||
| SCRIPT_EXPORT bool SetDL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned int GetEDI(); | ||||
| SCRIPT_EXPORT bool SetEDI(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetDI(); | ||||
| SCRIPT_EXPORT bool SetDI(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned int GetESI(); | ||||
| SCRIPT_EXPORT bool SetESI(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetSI(); | ||||
| SCRIPT_EXPORT bool SetSI(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned int GetEBP(); | ||||
| SCRIPT_EXPORT bool SetEBP(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetBP(); | ||||
| SCRIPT_EXPORT bool SetBP(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned int GetESP(); | ||||
| SCRIPT_EXPORT bool SetESP(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetSP(); | ||||
| SCRIPT_EXPORT bool SetSP(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned int GetEIP(); | ||||
| SCRIPT_EXPORT bool SetEIP(unsigned int value); | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| SCRIPT_EXPORT unsigned long long GetRAX(); | ||||
| SCRIPT_EXPORT bool SetRAX(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetRBX(); | ||||
| SCRIPT_EXPORT bool SetRBX(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetRCX(); | ||||
| SCRIPT_EXPORT bool SetRCX(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetRDX(); | ||||
| SCRIPT_EXPORT bool SetRDX(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetRSI(); | ||||
| SCRIPT_EXPORT bool SetRSI(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned char GetSIL(); | ||||
| SCRIPT_EXPORT bool SetSIL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetRDI(); | ||||
| SCRIPT_EXPORT bool SetRDI(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned char GetDIL(); | ||||
| SCRIPT_EXPORT bool SetDIL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetRBP(); | ||||
| SCRIPT_EXPORT bool SetRBP(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned char GetBPL(); | ||||
| SCRIPT_EXPORT bool SetBPL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetRSP(); | ||||
| SCRIPT_EXPORT bool SetRSP(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned char GetSPL(); | ||||
| SCRIPT_EXPORT bool SetSPL(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetRIP(); | ||||
| SCRIPT_EXPORT bool SetRIP(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned long long GetR8(); | ||||
| SCRIPT_EXPORT bool SetR8(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR8D(); | ||||
| SCRIPT_EXPORT bool SetR8D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR8W(); | ||||
| SCRIPT_EXPORT bool SetR8W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR8B(); | ||||
| SCRIPT_EXPORT bool SetR8B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR9(); | ||||
| SCRIPT_EXPORT bool SetR9(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR9D(); | ||||
| SCRIPT_EXPORT bool SetR9D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR9W(); | ||||
| SCRIPT_EXPORT bool SetR9W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR9B(); | ||||
| SCRIPT_EXPORT bool SetR9B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR10(); | ||||
| SCRIPT_EXPORT bool SetR10(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR10D(); | ||||
| SCRIPT_EXPORT bool SetR10D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR10W(); | ||||
| SCRIPT_EXPORT bool SetR10W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR10B(); | ||||
| SCRIPT_EXPORT bool SetR10B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR11(); | ||||
| SCRIPT_EXPORT bool SetR11(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR11D(); | ||||
| SCRIPT_EXPORT bool SetR11D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR11W(); | ||||
| SCRIPT_EXPORT bool SetR11W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR11B(); | ||||
| SCRIPT_EXPORT bool SetR11B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR12(); | ||||
| SCRIPT_EXPORT bool SetR12(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR12D(); | ||||
| SCRIPT_EXPORT bool SetR12D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR12W(); | ||||
| SCRIPT_EXPORT bool SetR12W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR12B(); | ||||
| SCRIPT_EXPORT bool SetR12B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR13(); | ||||
| SCRIPT_EXPORT bool SetR13(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR13D(); | ||||
| SCRIPT_EXPORT bool SetR13D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR13W(); | ||||
| SCRIPT_EXPORT bool SetR13W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR13B(); | ||||
| SCRIPT_EXPORT bool SetR13B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR14(); | ||||
| SCRIPT_EXPORT bool SetR14(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR14D(); | ||||
| SCRIPT_EXPORT bool SetR14D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR14W(); | ||||
| SCRIPT_EXPORT bool SetR14W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR14B(); | ||||
| SCRIPT_EXPORT bool SetR14B(unsigned char value); | ||||
| SCRIPT_EXPORT unsigned long long GetR15(); | ||||
| SCRIPT_EXPORT bool SetR15(unsigned long long value); | ||||
| SCRIPT_EXPORT unsigned int GetR15D(); | ||||
| SCRIPT_EXPORT bool SetR15D(unsigned int value); | ||||
| SCRIPT_EXPORT unsigned short GetR15W(); | ||||
| SCRIPT_EXPORT bool SetR15W(unsigned short value); | ||||
| SCRIPT_EXPORT unsigned char GetR15B(); | ||||
| SCRIPT_EXPORT bool SetR15B(unsigned char value); | ||||
| #endif //_WIN64
 | ||||
| 
 | ||||
| SCRIPT_EXPORT duint GetCIP(); | ||||
| SCRIPT_EXPORT bool SetCIP(duint value); | ||||
| SCRIPT_EXPORT duint GetCSP(); | ||||
| SCRIPT_EXPORT bool SetCSP(duint value); | ||||
| }; //Register
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #endif //_SCRIPTAPI_REGISTER_H
 | ||||
|  | @ -1,24 +1,24 @@ | |||
| #include "_scriptapi_stack.h" | ||||
| #include "_scriptapi_memory.h" | ||||
| #include "_scriptapi_register.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Stack::Pop() | ||||
| { | ||||
|     duint csp = Register::GetCSP(); | ||||
|     duint top = Memory::ReadPtr(csp); | ||||
|     Register::SetCSP(csp + sizeof(duint)); | ||||
|     return top; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Stack::Push(duint value) | ||||
| { | ||||
|     duint csp = Register::GetCSP(); | ||||
|     Register::SetCSP(csp - sizeof(duint)); | ||||
|     Memory::WritePtr(csp - sizeof(duint), value); | ||||
|     return Memory::ReadPtr(csp); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Stack::Peek(int offset) | ||||
| { | ||||
|     return Memory::ReadPtr(Register::GetCSP() + offset * sizeof(duint)); | ||||
| #include "_scriptapi_stack.h" | ||||
| #include "_scriptapi_memory.h" | ||||
| #include "_scriptapi_register.h" | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Stack::Pop() | ||||
| { | ||||
|     duint csp = Register::GetCSP(); | ||||
|     duint top = Memory::ReadPtr(csp); | ||||
|     Register::SetCSP(csp + sizeof(duint)); | ||||
|     return top; | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Stack::Push(duint value) | ||||
| { | ||||
|     duint csp = Register::GetCSP(); | ||||
|     Register::SetCSP(csp - sizeof(duint)); | ||||
|     Memory::WritePtr(csp - sizeof(duint), value); | ||||
|     return Memory::ReadPtr(csp); | ||||
| } | ||||
| 
 | ||||
| SCRIPT_EXPORT duint Script::Stack::Peek(int offset) | ||||
| { | ||||
|     return Memory::ReadPtr(Register::GetCSP() + offset * sizeof(duint)); | ||||
| } | ||||
|  | @ -1,16 +1,16 @@ | |||
| #ifndef _SCRIPTAPI_STACK_H | ||||
| #define _SCRIPTAPI_STACK_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Stack | ||||
| { | ||||
| SCRIPT_EXPORT duint Pop(); | ||||
| SCRIPT_EXPORT duint Push(duint value); //returns the previous top, equal to Peek(1)
 | ||||
| SCRIPT_EXPORT duint Peek(int offset = 0); //offset is in multiples of Register::Size(), for easy x32/x64 portability
 | ||||
| }; //Stack
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #ifndef _SCRIPTAPI_STACK_H | ||||
| #define _SCRIPTAPI_STACK_H | ||||
| 
 | ||||
| #include "_scriptapi.h" | ||||
| 
 | ||||
| namespace Script | ||||
| { | ||||
| namespace Stack | ||||
| { | ||||
| SCRIPT_EXPORT duint Pop(); | ||||
| SCRIPT_EXPORT duint Push(duint value); //returns the previous top, equal to Peek(1)
 | ||||
| SCRIPT_EXPORT duint Peek(int offset = 0); //offset is in multiples of Register::Size(), for easy x32/x64 portability
 | ||||
| }; //Stack
 | ||||
| }; //Script
 | ||||
| 
 | ||||
| #endif //_SCRIPTAPI_STACK_H
 | ||||
|  | @ -1,236 +1,236 @@ | |||
| /**
 | ||||
|  @file addrinfo.cpp | ||||
| 
 | ||||
|  @brief Implements the addrinfo class. | ||||
|  */ | ||||
| 
 | ||||
| #include "addrinfo.h" | ||||
| #include "debugger.h" | ||||
| #include "console.h" | ||||
| #include "memory.h" | ||||
| #include "breakpoint.h" | ||||
| #include "lz4\lz4file.h" | ||||
| #include "patches.h" | ||||
| #include "module.h" | ||||
| #include "comment.h" | ||||
| #include "label.h" | ||||
| #include "bookmark.h" | ||||
| #include "function.h" | ||||
| #include "loop.h" | ||||
| 
 | ||||
| //database functions
 | ||||
| void dbsave() | ||||
| { | ||||
|     dprintf("Saving database..."); | ||||
|     DWORD ticks = GetTickCount(); | ||||
|     JSON root = json_object(); | ||||
|     CommentCacheSave(root); | ||||
|     LabelCacheSave(root); | ||||
|     BookmarkCacheSave(root); | ||||
|     FunctionCacheSave(root); | ||||
|     LoopCacheSave(root); | ||||
|     BpCacheSave(root); | ||||
|     //save notes
 | ||||
|     char* text = nullptr; | ||||
|     GuiGetDebuggeeNotes(&text); | ||||
|     if(text) | ||||
|     { | ||||
|         json_object_set_new(root, "notes", json_string(text)); | ||||
|         BridgeFree(text); | ||||
|     } | ||||
|     GuiSetDebuggeeNotes(""); | ||||
| 
 | ||||
|     WString wdbpath = StringUtils::Utf8ToUtf16(dbpath); | ||||
|     if(json_object_size(root)) | ||||
|     { | ||||
|         Handle hFile = CreateFileW(wdbpath.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); | ||||
|         if(!hFile) | ||||
|         { | ||||
|             dputs("\nFailed to open database for writing!"); | ||||
|             json_decref(root); //free root
 | ||||
|             return; | ||||
|         } | ||||
|         SetEndOfFile(hFile); | ||||
|         char* jsonText = json_dumps(root, JSON_INDENT(4)); | ||||
|         DWORD written = 0; | ||||
|         if(!WriteFile(hFile, jsonText, (DWORD)strlen(jsonText), &written, 0)) | ||||
|         { | ||||
|             json_free(jsonText); | ||||
|             dputs("\nFailed to write database file!"); | ||||
|             json_decref(root); //free root
 | ||||
|             return; | ||||
|         } | ||||
|         hFile.Close(); | ||||
|         json_free(jsonText); | ||||
|         if(!settingboolget("Engine", "DisableDatabaseCompression")) | ||||
|             LZ4_compress_fileW(wdbpath.c_str(), wdbpath.c_str()); | ||||
|     } | ||||
|     else //remove database when nothing is in there
 | ||||
|         DeleteFileW(wdbpath.c_str()); | ||||
|     dprintf("%ums\n", GetTickCount() - ticks); | ||||
|     json_decref(root); //free root
 | ||||
| } | ||||
| 
 | ||||
| void dbload() | ||||
| { | ||||
|     // If the file doesn't exist, there is no DB to load
 | ||||
|     if(!FileExists(dbpath)) | ||||
|         return; | ||||
| 
 | ||||
|     dprintf("Loading database..."); | ||||
|     DWORD ticks = GetTickCount(); | ||||
| 
 | ||||
|     // Multi-byte (UTF8) file path converted to UTF16
 | ||||
|     WString databasePathW = StringUtils::Utf8ToUtf16(dbpath); | ||||
| 
 | ||||
|     // Decompress the file if compression was enabled
 | ||||
|     bool useCompression = !settingboolget("Engine", "DisableDatabaseCompression"); | ||||
|     LZ4_STATUS lzmaStatus = LZ4_INVALID_ARCHIVE; | ||||
|     { | ||||
|         lzmaStatus = LZ4_decompress_fileW(databasePathW.c_str(), databasePathW.c_str()); | ||||
| 
 | ||||
|         // Check return code
 | ||||
|         if(useCompression && lzmaStatus != LZ4_SUCCESS && lzmaStatus != LZ4_INVALID_ARCHIVE) | ||||
|         { | ||||
|             dputs("\nInvalid database file!"); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Read the database file
 | ||||
|     Handle hFile = CreateFileW(databasePathW.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); | ||||
|     if(!hFile) | ||||
|     { | ||||
|         dputs("\nFailed to open database file!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     unsigned int jsonFileSize = GetFileSize(hFile, 0); | ||||
|     if(!jsonFileSize) | ||||
|     { | ||||
|         dputs("\nEmpty database file!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     Memory<char*> jsonText(jsonFileSize + 1); | ||||
|     DWORD read = 0; | ||||
|     if(!ReadFile(hFile, jsonText(), jsonFileSize, &read, 0)) | ||||
|     { | ||||
|         dputs("\nFailed to read database file!"); | ||||
|         return; | ||||
|     } | ||||
|     hFile.Close(); | ||||
| 
 | ||||
|     // Deserialize JSON
 | ||||
|     JSON root = json_loads(jsonText(), 0, 0); | ||||
| 
 | ||||
|     if(lzmaStatus != LZ4_INVALID_ARCHIVE && useCompression) | ||||
|         LZ4_compress_fileW(databasePathW.c_str(), databasePathW.c_str()); | ||||
| 
 | ||||
|     // Validate JSON load status
 | ||||
|     if(!root) | ||||
|     { | ||||
|         dputs("\nInvalid database file (JSON)!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Finally load all structures
 | ||||
|     CommentCacheLoad(root); | ||||
|     LabelCacheLoad(root); | ||||
|     BookmarkCacheLoad(root); | ||||
|     FunctionCacheLoad(root); | ||||
|     LoopCacheLoad(root); | ||||
|     BpCacheLoad(root); | ||||
| 
 | ||||
|     // Load notes
 | ||||
|     const char* text = json_string_value(json_object_get(root, "notes")); | ||||
|     GuiSetDebuggeeNotes(text); | ||||
| 
 | ||||
|     // Free root
 | ||||
|     json_decref(root); | ||||
|     dprintf("%ums\n", GetTickCount() - ticks); | ||||
| } | ||||
| 
 | ||||
| void dbclose() | ||||
| { | ||||
|     dbsave(); | ||||
|     CommentClear(); | ||||
|     LabelClear(); | ||||
|     BookmarkClear(); | ||||
|     FunctionClear(); | ||||
|     LoopClear(); | ||||
|     BpClear(); | ||||
|     PatchClear(); | ||||
| } | ||||
| 
 | ||||
| ///api functions
 | ||||
| bool apienumexports(uint base, EXPORTENUMCALLBACK cbEnum) | ||||
| { | ||||
|     MEMORY_BASIC_INFORMATION mbi; | ||||
|     VirtualQueryEx(fdProcessInfo->hProcess, (const void*)base, &mbi, sizeof(mbi)); | ||||
|     uint size = mbi.RegionSize; | ||||
|     Memory<void*> buffer(size, "apienumexports:buffer"); | ||||
|     if(!MemRead(base, buffer(), size)) | ||||
|         return false; | ||||
|     IMAGE_NT_HEADERS* pnth = (IMAGE_NT_HEADERS*)((uint)buffer() + GetPE32DataFromMappedFile((ULONG_PTR)buffer(), 0, UE_PE_OFFSET)); | ||||
|     uint export_dir_rva = pnth->OptionalHeader.DataDirectory[0].VirtualAddress; | ||||
|     uint export_dir_size = pnth->OptionalHeader.DataDirectory[0].Size; | ||||
|     IMAGE_EXPORT_DIRECTORY export_dir; | ||||
|     memset(&export_dir, 0, sizeof(export_dir)); | ||||
|     MemRead((export_dir_rva + base), &export_dir, sizeof(export_dir)); | ||||
|     unsigned int NumberOfNames = export_dir.NumberOfNames; | ||||
|     if(!export_dir.NumberOfFunctions || !NumberOfNames) //no named exports
 | ||||
|         return false; | ||||
|     char modname[MAX_MODULE_SIZE] = ""; | ||||
|     ModNameFromAddr(base, modname, true); | ||||
|     uint original_name_va = export_dir.Name + base; | ||||
|     char original_name[deflen] = ""; | ||||
|     memset(original_name, 0, sizeof(original_name)); | ||||
|     MemRead(original_name_va, original_name, deflen); | ||||
|     char* AddrOfFunctions_va = (char*)(export_dir.AddressOfFunctions + base); //not a valid local pointer
 | ||||
|     char* AddrOfNames_va = (char*)(export_dir.AddressOfNames + base); //not a valid local pointer
 | ||||
|     char* AddrOfNameOrdinals_va = (char*)(export_dir.AddressOfNameOrdinals + base); //not a valid local pointer
 | ||||
|     for(DWORD i = 0; i < NumberOfNames; i++) | ||||
|     { | ||||
|         DWORD curAddrOfName = 0; | ||||
|         MemRead((uint)(AddrOfNames_va + sizeof(DWORD)*i), &curAddrOfName, sizeof(DWORD)); | ||||
|         char* cur_name_va = (char*)(curAddrOfName + base); | ||||
|         char cur_name[deflen] = ""; | ||||
|         memset(cur_name, 0, deflen); | ||||
|         MemRead((uint)cur_name_va, cur_name, deflen); | ||||
|         WORD curAddrOfNameOrdinals = 0; | ||||
|         MemRead((uint)(AddrOfNameOrdinals_va + sizeof(WORD)*i), &curAddrOfNameOrdinals, sizeof(WORD)); | ||||
|         DWORD curFunctionRva = 0; | ||||
|         MemRead((uint)(AddrOfFunctions_va + sizeof(DWORD)*curAddrOfNameOrdinals), &curFunctionRva, sizeof(DWORD)); | ||||
| 
 | ||||
|         if(curFunctionRva >= export_dir_rva && curFunctionRva < export_dir_rva + export_dir_size) | ||||
|         { | ||||
|             char forwarded_api[deflen] = ""; | ||||
|             memset(forwarded_api, 0, deflen); | ||||
|             MemRead((curFunctionRva + base), forwarded_api, deflen); | ||||
|             int len = (int)strlen(forwarded_api); | ||||
|             int j = 0; | ||||
|             while(forwarded_api[j] != '.' && j < len) | ||||
|                 j++; | ||||
|             if(forwarded_api[j] == '.') | ||||
|             { | ||||
|                 forwarded_api[j] = 0; | ||||
|                 HINSTANCE hTempDll = LoadLibraryExA(forwarded_api, 0, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); | ||||
|                 if(hTempDll) | ||||
|                 { | ||||
|                     uint local_addr = (uint)GetProcAddress(hTempDll, forwarded_api + j + 1); | ||||
|                     if(local_addr) | ||||
|                     { | ||||
|                         uint remote_addr = ImporterGetRemoteAPIAddress(fdProcessInfo->hProcess, local_addr); | ||||
|                         cbEnum(base, modname, cur_name, remote_addr); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             cbEnum(base, modname, cur_name, curFunctionRva + base); | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| /**
 | ||||
|  @file addrinfo.cpp | ||||
| 
 | ||||
|  @brief Implements the addrinfo class. | ||||
|  */ | ||||
| 
 | ||||
| #include "addrinfo.h" | ||||
| #include "debugger.h" | ||||
| #include "console.h" | ||||
| #include "memory.h" | ||||
| #include "breakpoint.h" | ||||
| #include "lz4\lz4file.h" | ||||
| #include "patches.h" | ||||
| #include "module.h" | ||||
| #include "comment.h" | ||||
| #include "label.h" | ||||
| #include "bookmark.h" | ||||
| #include "function.h" | ||||
| #include "loop.h" | ||||
| 
 | ||||
| //database functions
 | ||||
| void dbsave() | ||||
| { | ||||
|     dprintf("Saving database..."); | ||||
|     DWORD ticks = GetTickCount(); | ||||
|     JSON root = json_object(); | ||||
|     CommentCacheSave(root); | ||||
|     LabelCacheSave(root); | ||||
|     BookmarkCacheSave(root); | ||||
|     FunctionCacheSave(root); | ||||
|     LoopCacheSave(root); | ||||
|     BpCacheSave(root); | ||||
|     //save notes
 | ||||
|     char* text = nullptr; | ||||
|     GuiGetDebuggeeNotes(&text); | ||||
|     if(text) | ||||
|     { | ||||
|         json_object_set_new(root, "notes", json_string(text)); | ||||
|         BridgeFree(text); | ||||
|     } | ||||
|     GuiSetDebuggeeNotes(""); | ||||
| 
 | ||||
|     WString wdbpath = StringUtils::Utf8ToUtf16(dbpath); | ||||
|     if(json_object_size(root)) | ||||
|     { | ||||
|         Handle hFile = CreateFileW(wdbpath.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); | ||||
|         if(!hFile) | ||||
|         { | ||||
|             dputs("\nFailed to open database for writing!"); | ||||
|             json_decref(root); //free root
 | ||||
|             return; | ||||
|         } | ||||
|         SetEndOfFile(hFile); | ||||
|         char* jsonText = json_dumps(root, JSON_INDENT(4)); | ||||
|         DWORD written = 0; | ||||
|         if(!WriteFile(hFile, jsonText, (DWORD)strlen(jsonText), &written, 0)) | ||||
|         { | ||||
|             json_free(jsonText); | ||||
|             dputs("\nFailed to write database file!"); | ||||
|             json_decref(root); //free root
 | ||||
|             return; | ||||
|         } | ||||
|         hFile.Close(); | ||||
|         json_free(jsonText); | ||||
|         if(!settingboolget("Engine", "DisableDatabaseCompression")) | ||||
|             LZ4_compress_fileW(wdbpath.c_str(), wdbpath.c_str()); | ||||
|     } | ||||
|     else //remove database when nothing is in there
 | ||||
|         DeleteFileW(wdbpath.c_str()); | ||||
|     dprintf("%ums\n", GetTickCount() - ticks); | ||||
|     json_decref(root); //free root
 | ||||
| } | ||||
| 
 | ||||
| void dbload() | ||||
| { | ||||
|     // If the file doesn't exist, there is no DB to load
 | ||||
|     if(!FileExists(dbpath)) | ||||
|         return; | ||||
| 
 | ||||
|     dprintf("Loading database..."); | ||||
|     DWORD ticks = GetTickCount(); | ||||
| 
 | ||||
|     // Multi-byte (UTF8) file path converted to UTF16
 | ||||
|     WString databasePathW = StringUtils::Utf8ToUtf16(dbpath); | ||||
| 
 | ||||
|     // Decompress the file if compression was enabled
 | ||||
|     bool useCompression = !settingboolget("Engine", "DisableDatabaseCompression"); | ||||
|     LZ4_STATUS lzmaStatus = LZ4_INVALID_ARCHIVE; | ||||
|     { | ||||
|         lzmaStatus = LZ4_decompress_fileW(databasePathW.c_str(), databasePathW.c_str()); | ||||
| 
 | ||||
|         // Check return code
 | ||||
|         if(useCompression && lzmaStatus != LZ4_SUCCESS && lzmaStatus != LZ4_INVALID_ARCHIVE) | ||||
|         { | ||||
|             dputs("\nInvalid database file!"); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Read the database file
 | ||||
|     Handle hFile = CreateFileW(databasePathW.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); | ||||
|     if(!hFile) | ||||
|     { | ||||
|         dputs("\nFailed to open database file!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     unsigned int jsonFileSize = GetFileSize(hFile, 0); | ||||
|     if(!jsonFileSize) | ||||
|     { | ||||
|         dputs("\nEmpty database file!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     Memory<char*> jsonText(jsonFileSize + 1); | ||||
|     DWORD read = 0; | ||||
|     if(!ReadFile(hFile, jsonText(), jsonFileSize, &read, 0)) | ||||
|     { | ||||
|         dputs("\nFailed to read database file!"); | ||||
|         return; | ||||
|     } | ||||
|     hFile.Close(); | ||||
| 
 | ||||
|     // Deserialize JSON
 | ||||
|     JSON root = json_loads(jsonText(), 0, 0); | ||||
| 
 | ||||
|     if(lzmaStatus != LZ4_INVALID_ARCHIVE && useCompression) | ||||
|         LZ4_compress_fileW(databasePathW.c_str(), databasePathW.c_str()); | ||||
| 
 | ||||
|     // Validate JSON load status
 | ||||
|     if(!root) | ||||
|     { | ||||
|         dputs("\nInvalid database file (JSON)!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Finally load all structures
 | ||||
|     CommentCacheLoad(root); | ||||
|     LabelCacheLoad(root); | ||||
|     BookmarkCacheLoad(root); | ||||
|     FunctionCacheLoad(root); | ||||
|     LoopCacheLoad(root); | ||||
|     BpCacheLoad(root); | ||||
| 
 | ||||
|     // Load notes
 | ||||
|     const char* text = json_string_value(json_object_get(root, "notes")); | ||||
|     GuiSetDebuggeeNotes(text); | ||||
| 
 | ||||
|     // Free root
 | ||||
|     json_decref(root); | ||||
|     dprintf("%ums\n", GetTickCount() - ticks); | ||||
| } | ||||
| 
 | ||||
| void dbclose() | ||||
| { | ||||
|     dbsave(); | ||||
|     CommentClear(); | ||||
|     LabelClear(); | ||||
|     BookmarkClear(); | ||||
|     FunctionClear(); | ||||
|     LoopClear(); | ||||
|     BpClear(); | ||||
|     PatchClear(); | ||||
| } | ||||
| 
 | ||||
| ///api functions
 | ||||
| bool apienumexports(uint base, EXPORTENUMCALLBACK cbEnum) | ||||
| { | ||||
|     MEMORY_BASIC_INFORMATION mbi; | ||||
|     VirtualQueryEx(fdProcessInfo->hProcess, (const void*)base, &mbi, sizeof(mbi)); | ||||
|     uint size = mbi.RegionSize; | ||||
|     Memory<void*> buffer(size, "apienumexports:buffer"); | ||||
|     if(!MemRead(base, buffer(), size)) | ||||
|         return false; | ||||
|     IMAGE_NT_HEADERS* pnth = (IMAGE_NT_HEADERS*)((uint)buffer() + GetPE32DataFromMappedFile((ULONG_PTR)buffer(), 0, UE_PE_OFFSET)); | ||||
|     uint export_dir_rva = pnth->OptionalHeader.DataDirectory[0].VirtualAddress; | ||||
|     uint export_dir_size = pnth->OptionalHeader.DataDirectory[0].Size; | ||||
|     IMAGE_EXPORT_DIRECTORY export_dir; | ||||
|     memset(&export_dir, 0, sizeof(export_dir)); | ||||
|     MemRead((export_dir_rva + base), &export_dir, sizeof(export_dir)); | ||||
|     unsigned int NumberOfNames = export_dir.NumberOfNames; | ||||
|     if(!export_dir.NumberOfFunctions || !NumberOfNames) //no named exports
 | ||||
|         return false; | ||||
|     char modname[MAX_MODULE_SIZE] = ""; | ||||
|     ModNameFromAddr(base, modname, true); | ||||
|     uint original_name_va = export_dir.Name + base; | ||||
|     char original_name[deflen] = ""; | ||||
|     memset(original_name, 0, sizeof(original_name)); | ||||
|     MemRead(original_name_va, original_name, deflen); | ||||
|     char* AddrOfFunctions_va = (char*)(export_dir.AddressOfFunctions + base); //not a valid local pointer
 | ||||
|     char* AddrOfNames_va = (char*)(export_dir.AddressOfNames + base); //not a valid local pointer
 | ||||
|     char* AddrOfNameOrdinals_va = (char*)(export_dir.AddressOfNameOrdinals + base); //not a valid local pointer
 | ||||
|     for(DWORD i = 0; i < NumberOfNames; i++) | ||||
|     { | ||||
|         DWORD curAddrOfName = 0; | ||||
|         MemRead((uint)(AddrOfNames_va + sizeof(DWORD)*i), &curAddrOfName, sizeof(DWORD)); | ||||
|         char* cur_name_va = (char*)(curAddrOfName + base); | ||||
|         char cur_name[deflen] = ""; | ||||
|         memset(cur_name, 0, deflen); | ||||
|         MemRead((uint)cur_name_va, cur_name, deflen); | ||||
|         WORD curAddrOfNameOrdinals = 0; | ||||
|         MemRead((uint)(AddrOfNameOrdinals_va + sizeof(WORD)*i), &curAddrOfNameOrdinals, sizeof(WORD)); | ||||
|         DWORD curFunctionRva = 0; | ||||
|         MemRead((uint)(AddrOfFunctions_va + sizeof(DWORD)*curAddrOfNameOrdinals), &curFunctionRva, sizeof(DWORD)); | ||||
| 
 | ||||
|         if(curFunctionRva >= export_dir_rva && curFunctionRva < export_dir_rva + export_dir_size) | ||||
|         { | ||||
|             char forwarded_api[deflen] = ""; | ||||
|             memset(forwarded_api, 0, deflen); | ||||
|             MemRead((curFunctionRva + base), forwarded_api, deflen); | ||||
|             int len = (int)strlen(forwarded_api); | ||||
|             int j = 0; | ||||
|             while(forwarded_api[j] != '.' && j < len) | ||||
|                 j++; | ||||
|             if(forwarded_api[j] == '.') | ||||
|             { | ||||
|                 forwarded_api[j] = 0; | ||||
|                 HINSTANCE hTempDll = LoadLibraryExA(forwarded_api, 0, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); | ||||
|                 if(hTempDll) | ||||
|                 { | ||||
|                     uint local_addr = (uint)GetProcAddress(hTempDll, forwarded_api + j + 1); | ||||
|                     if(local_addr) | ||||
|                     { | ||||
|                         uint remote_addr = ImporterGetRemoteAPIAddress(fdProcessInfo->hProcess, local_addr); | ||||
|                         cbEnum(base, modname, cur_name, remote_addr); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             cbEnum(base, modname, cur_name, curFunctionRva + base); | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | @ -1,65 +1,65 @@ | |||
| #ifndef _ADDRINFO_H | ||||
| #define _ADDRINFO_H | ||||
| 
 | ||||
| #include "_global.h" | ||||
| #include <functional> | ||||
| 
 | ||||
| //ranges
 | ||||
| typedef std::pair<uint, uint> Range; | ||||
| typedef std::pair<uint, Range> ModuleRange; //modhash + RVA range
 | ||||
| typedef std::pair<int, ModuleRange> DepthModuleRange; //depth + modulerange
 | ||||
| 
 | ||||
| struct RangeCompare | ||||
| { | ||||
|     bool operator()(const Range & a, const Range & b) //a before b?
 | ||||
|     { | ||||
|         return a.second < b.first; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct OverlappingRangeCompare | ||||
| { | ||||
|     bool operator()(const Range & a, const Range & b) //a before b?
 | ||||
|     { | ||||
|         return a.second < b.first || a.second < b.second; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct ModuleRangeCompare | ||||
| { | ||||
|     bool operator()(const ModuleRange & a, const ModuleRange & b) | ||||
|     { | ||||
|         if(a.first < b.first) //module hash is smaller
 | ||||
|             return true; | ||||
|         if(a.first != b.first) //module hashes are not equal
 | ||||
|             return false; | ||||
|         return a.second.second < b.second.first; //a.second is before b.second
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct DepthModuleRangeCompare | ||||
| { | ||||
|     bool operator()(const DepthModuleRange & a, const DepthModuleRange & b) | ||||
|     { | ||||
|         if(a.first < b.first) //module depth is smaller
 | ||||
|             return true; | ||||
|         if(a.first != b.first) //module depths are not equal
 | ||||
|             return false; | ||||
|         if(a.second.first < b.second.first) //module hash is smaller
 | ||||
|             return true; | ||||
|         if(a.second.first != b.second.first) //module hashes are not equal
 | ||||
|             return false; | ||||
|         return a.second.second.second < b.second.second.first; //a.second.second is before b.second.second
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| //typedefs
 | ||||
| typedef std::function<void (uint base, const char* mod, const char* name, uint addr)> EXPORTENUMCALLBACK; | ||||
| 
 | ||||
| void dbsave(); | ||||
| void dbload(); | ||||
| void dbclose(); | ||||
| 
 | ||||
| bool apienumexports(uint base, EXPORTENUMCALLBACK cbEnum); | ||||
| 
 | ||||
| #endif // _ADDRINFO_H
 | ||||
| #ifndef _ADDRINFO_H | ||||
| #define _ADDRINFO_H | ||||
| 
 | ||||
| #include "_global.h" | ||||
| #include <functional> | ||||
| 
 | ||||
| //ranges
 | ||||
| typedef std::pair<uint, uint> Range; | ||||
| typedef std::pair<uint, Range> ModuleRange; //modhash + RVA range
 | ||||
| typedef std::pair<int, ModuleRange> DepthModuleRange; //depth + modulerange
 | ||||
| 
 | ||||
| struct RangeCompare | ||||
| { | ||||
|     bool operator()(const Range & a, const Range & b) //a before b?
 | ||||
|     { | ||||
|         return a.second < b.first; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct OverlappingRangeCompare | ||||
| { | ||||
|     bool operator()(const Range & a, const Range & b) //a before b?
 | ||||
|     { | ||||
|         return a.second < b.first || a.second < b.second; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct ModuleRangeCompare | ||||
| { | ||||
|     bool operator()(const ModuleRange & a, const ModuleRange & b) | ||||
|     { | ||||
|         if(a.first < b.first) //module hash is smaller
 | ||||
|             return true; | ||||
|         if(a.first != b.first) //module hashes are not equal
 | ||||
|             return false; | ||||
|         return a.second.second < b.second.first; //a.second is before b.second
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct DepthModuleRangeCompare | ||||
| { | ||||
|     bool operator()(const DepthModuleRange & a, const DepthModuleRange & b) | ||||
|     { | ||||
|         if(a.first < b.first) //module depth is smaller
 | ||||
|             return true; | ||||
|         if(a.first != b.first) //module depths are not equal
 | ||||
|             return false; | ||||
|         if(a.second.first < b.second.first) //module hash is smaller
 | ||||
|             return true; | ||||
|         if(a.second.first != b.second.first) //module hashes are not equal
 | ||||
|             return false; | ||||
|         return a.second.second.second < b.second.second.first; //a.second.second is before b.second.second
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| //typedefs
 | ||||
| typedef std::function<void (uint base, const char* mod, const char* name, uint addr)> EXPORTENUMCALLBACK; | ||||
| 
 | ||||
| void dbsave(); | ||||
| void dbload(); | ||||
| void dbclose(); | ||||
| 
 | ||||
| bool apienumexports(uint base, EXPORTENUMCALLBACK cbEnum); | ||||
| 
 | ||||
| #endif // _ADDRINFO_H
 | ||||
|  | @ -1,81 +1,81 @@ | |||
| /**
 | ||||
|  @file assemble.cpp | ||||
| 
 | ||||
|  @brief Implements the assemble class. | ||||
|  */ | ||||
| 
 | ||||
| #include "assemble.h" | ||||
| #include "memory.h" | ||||
| #include "XEDParse\XEDParse.h" | ||||
| #include "value.h" | ||||
| #include "disasm_helper.h" | ||||
| 
 | ||||
| static bool cbUnknown(const char* text, ULONGLONG* value) | ||||
| { | ||||
|     if(!text || !value) | ||||
|         return false; | ||||
|     uint val; | ||||
|     if(!valfromstring(text, &val)) | ||||
|         return false; | ||||
|     *value = val; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool assemble(uint addr, unsigned char* dest, int* size, const char* instruction, char* error) | ||||
| { | ||||
|     if(strlen(instruction) >= XEDPARSE_MAXBUFSIZE) | ||||
|         return false; | ||||
|     XEDPARSE parse; | ||||
|     memset(&parse, 0, sizeof(parse)); | ||||
| #ifdef _WIN64 | ||||
|     parse.x64 = true; | ||||
| #else //x86
 | ||||
|     parse.x64 = false; | ||||
| #endif | ||||
|     parse.cbUnknown = cbUnknown; | ||||
|     parse.cip = addr; | ||||
|     strcpy_s(parse.instr, instruction); | ||||
|     if(XEDParseAssemble(&parse) == XEDPARSE_ERROR) | ||||
|     { | ||||
|         if(error) | ||||
|             strcpy_s(error, MAX_ERROR_SIZE, parse.error); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if(dest) | ||||
|         memcpy(dest, parse.dest, parse.dest_size); | ||||
|     if(size) | ||||
|         *size = parse.dest_size; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool assembleat(uint addr, const char* instruction, int* size, char* error, bool fillnop) | ||||
| { | ||||
|     int destSize; | ||||
|     unsigned char dest[16]; | ||||
|     if(!assemble(addr, dest, &destSize, instruction, error)) | ||||
|         return false; | ||||
|     //calculate the number of NOPs to insert
 | ||||
|     int origLen = disasmgetsize(addr); | ||||
|     while(origLen < destSize) | ||||
|         origLen += disasmgetsize(addr + origLen); | ||||
|     int nopsize = origLen - destSize; | ||||
|     unsigned char nops[16]; | ||||
|     memset(nops, 0x90, sizeof(nops)); | ||||
| 
 | ||||
|     if(size) | ||||
|         *size = destSize; | ||||
| 
 | ||||
|     bool ret = MemPatch(addr, dest, destSize); | ||||
|     if(ret && fillnop && nopsize) | ||||
|     { | ||||
|         if(size) | ||||
|             *size += nopsize; | ||||
| 
 | ||||
|         // Ignored if the memory patch for NOPs fail (although it should not)
 | ||||
|         MemPatch(addr + destSize, nops, nopsize); | ||||
|     } | ||||
|     GuiUpdatePatches(); | ||||
|     return true; | ||||
| } | ||||
| /**
 | ||||
|  @file assemble.cpp | ||||
| 
 | ||||
|  @brief Implements the assemble class. | ||||
|  */ | ||||
| 
 | ||||
| #include "assemble.h" | ||||
| #include "memory.h" | ||||
| #include "XEDParse\XEDParse.h" | ||||
| #include "value.h" | ||||
| #include "disasm_helper.h" | ||||
| 
 | ||||
| static bool cbUnknown(const char* text, ULONGLONG* value) | ||||
| { | ||||
|     if(!text || !value) | ||||
|         return false; | ||||
|     uint val; | ||||
|     if(!valfromstring(text, &val)) | ||||
|         return false; | ||||
|     *value = val; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool assemble(uint addr, unsigned char* dest, int* size, const char* instruction, char* error) | ||||
| { | ||||
|     if(strlen(instruction) >= XEDPARSE_MAXBUFSIZE) | ||||
|         return false; | ||||
|     XEDPARSE parse; | ||||
|     memset(&parse, 0, sizeof(parse)); | ||||
| #ifdef _WIN64 | ||||
|     parse.x64 = true; | ||||
| #else //x86
 | ||||
|     parse.x64 = false; | ||||
| #endif | ||||
|     parse.cbUnknown = cbUnknown; | ||||
|     parse.cip = addr; | ||||
|     strcpy_s(parse.instr, instruction); | ||||
|     if(XEDParseAssemble(&parse) == XEDPARSE_ERROR) | ||||
|     { | ||||
|         if(error) | ||||
|             strcpy_s(error, MAX_ERROR_SIZE, parse.error); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if(dest) | ||||
|         memcpy(dest, parse.dest, parse.dest_size); | ||||
|     if(size) | ||||
|         *size = parse.dest_size; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool assembleat(uint addr, const char* instruction, int* size, char* error, bool fillnop) | ||||
| { | ||||
|     int destSize; | ||||
|     unsigned char dest[16]; | ||||
|     if(!assemble(addr, dest, &destSize, instruction, error)) | ||||
|         return false; | ||||
|     //calculate the number of NOPs to insert
 | ||||
|     int origLen = disasmgetsize(addr); | ||||
|     while(origLen < destSize) | ||||
|         origLen += disasmgetsize(addr + origLen); | ||||
|     int nopsize = origLen - destSize; | ||||
|     unsigned char nops[16]; | ||||
|     memset(nops, 0x90, sizeof(nops)); | ||||
| 
 | ||||
|     if(size) | ||||
|         *size = destSize; | ||||
| 
 | ||||
|     bool ret = MemPatch(addr, dest, destSize); | ||||
|     if(ret && fillnop && nopsize) | ||||
|     { | ||||
|         if(size) | ||||
|             *size += nopsize; | ||||
| 
 | ||||
|         // Ignored if the memory patch for NOPs fail (although it should not)
 | ||||
|         MemPatch(addr + destSize, nops, nopsize); | ||||
|     } | ||||
|     GuiUpdatePatches(); | ||||
|     return true; | ||||
| } | ||||
|  | @ -1,9 +1,9 @@ | |||
| #ifndef _ASSEMBLE_H | ||||
| #define _ASSEMBLE_H | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| bool assemble(uint addr, unsigned char* dest, int* size, const char* instruction, char* error); | ||||
| bool assembleat(uint addr, const char* instruction, int* size, char* error, bool fillnop); | ||||
| 
 | ||||
| #endif // _ASSEMBLE_H
 | ||||
| #ifndef _ASSEMBLE_H | ||||
| #define _ASSEMBLE_H | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| bool assemble(uint addr, unsigned char* dest, int* size, const char* instruction, char* error); | ||||
| bool assembleat(uint addr, const char* instruction, int* size, char* error, bool fillnop); | ||||
| 
 | ||||
| #endif // _ASSEMBLE_H
 | ||||
|  | @ -1,209 +1,209 @@ | |||
| #include "bookmark.h" | ||||
| #include "threading.h" | ||||
| #include "module.h" | ||||
| #include "memory.h" | ||||
| 
 | ||||
| std::unordered_map<uint, BOOKMARKSINFO> bookmarks; | ||||
| 
 | ||||
| bool BookmarkSet(uint Address, bool Manual) | ||||
| { | ||||
|     // CHECK: Export call
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // Validate the incoming address
 | ||||
|     if(!MemIsValidReadPtr(Address)) | ||||
|         return false; | ||||
| 
 | ||||
|     BOOKMARKSINFO bookmark; | ||||
|     ModNameFromAddr(Address, bookmark.mod, true); | ||||
|     bookmark.addr = Address - ModBaseFromAddr(Address); | ||||
|     bookmark.manual = Manual; | ||||
| 
 | ||||
|     // Exclusive lock to insert new data
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
| 
 | ||||
|     if(!bookmarks.insert(std::make_pair(ModHashFromAddr(Address), bookmark)).second) | ||||
|     { | ||||
|         EXCLUSIVE_RELEASE(); | ||||
|         return BookmarkDelete(Address); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BookmarkGet(uint Address) | ||||
| { | ||||
|     // CHECK: Export call
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBookmarks); | ||||
|     return (bookmarks.count(ModHashFromAddr(Address)) > 0); | ||||
| } | ||||
| 
 | ||||
| bool BookmarkDelete(uint Address) | ||||
| { | ||||
|     // CHECK: Export call
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
|     return (bookmarks.erase(ModHashFromAddr(Address)) > 0); | ||||
| } | ||||
| 
 | ||||
| void BookmarkDelRange(uint Start, uint End) | ||||
| { | ||||
|     // CHECK: Export call
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return; | ||||
| 
 | ||||
|     // Are all bookmarks going to be deleted?
 | ||||
|     // 0x00000000 - 0xFFFFFFFF
 | ||||
|     if(Start == 0 && End == ~0) | ||||
|     { | ||||
|         BookmarkClear(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Make sure 'Start' and 'End' reference the same module
 | ||||
|         uint moduleBase = ModBaseFromAddr(Start); | ||||
| 
 | ||||
|         if(moduleBase != ModBaseFromAddr(End)) | ||||
|             return; | ||||
| 
 | ||||
|         // Virtual -> relative offset
 | ||||
|         Start -= moduleBase; | ||||
|         End -= moduleBase; | ||||
| 
 | ||||
|         EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
|         for(auto itr = bookmarks.begin(); itr != bookmarks.end();) | ||||
|         { | ||||
|             const auto & currentBookmark = itr->second; | ||||
| 
 | ||||
|             // Ignore manually set entries
 | ||||
|             if(currentBookmark.manual) | ||||
|             { | ||||
|                 ++itr; | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             // [Start, End)
 | ||||
|             if(currentBookmark.addr >= Start && currentBookmark.addr < End) | ||||
|                 itr = bookmarks.erase(itr); | ||||
|             else | ||||
|                 ++itr; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void BookmarkCacheSave(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
| 
 | ||||
|     const JSON jsonBookmarks = json_array(); | ||||
|     const JSON jsonAutoBookmarks = json_array(); | ||||
| 
 | ||||
|     // Save to the JSON root
 | ||||
|     for(auto & itr : bookmarks) | ||||
|     { | ||||
|         JSON currentBookmark = json_object(); | ||||
| 
 | ||||
|         json_object_set_new(currentBookmark, "module", json_string(itr.second.mod)); | ||||
|         json_object_set_new(currentBookmark, "address", json_hex(itr.second.addr)); | ||||
| 
 | ||||
|         if(itr.second.manual) | ||||
|             json_array_append_new(jsonBookmarks, currentBookmark); | ||||
|         else | ||||
|             json_array_append_new(jsonAutoBookmarks, currentBookmark); | ||||
|     } | ||||
| 
 | ||||
|     if(json_array_size(jsonBookmarks)) | ||||
|         json_object_set(Root, "bookmarks", jsonBookmarks); | ||||
| 
 | ||||
|     if(json_array_size(jsonAutoBookmarks)) | ||||
|         json_object_set(Root, "autobookmarks", jsonAutoBookmarks); | ||||
| 
 | ||||
|     json_decref(jsonBookmarks); | ||||
|     json_decref(jsonAutoBookmarks); | ||||
| } | ||||
| 
 | ||||
| void BookmarkCacheLoad(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
| 
 | ||||
|     // Inline lambda to parse each JSON entry
 | ||||
|     auto AddBookmarks = [](const JSON Object, bool Manual) | ||||
|     { | ||||
|         size_t i; | ||||
|         JSON value; | ||||
| 
 | ||||
|         json_array_foreach(Object, i, value) | ||||
|         { | ||||
|             BOOKMARKSINFO bookmarkInfo; | ||||
|             memset(&bookmarkInfo, 0, sizeof(BOOKMARKSINFO)); | ||||
| 
 | ||||
|             // Load the module name
 | ||||
|             const char* mod = json_string_value(json_object_get(value, "module")); | ||||
| 
 | ||||
|             if(mod && strlen(mod) < MAX_MODULE_SIZE) | ||||
|                 strcpy_s(bookmarkInfo.mod, mod); | ||||
| 
 | ||||
|             // Load address and set auto-generated flag
 | ||||
|             bookmarkInfo.addr = (uint)json_hex_value(json_object_get(value, "address")); | ||||
|             bookmarkInfo.manual = Manual; | ||||
| 
 | ||||
|             const uint key = ModHashFromName(bookmarkInfo.mod) + bookmarkInfo.addr; | ||||
|             bookmarks.insert(std::make_pair(key, bookmarkInfo)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // Remove existing entries
 | ||||
|     bookmarks.clear(); | ||||
| 
 | ||||
|     const JSON jsonBookmarks = json_object_get(Root, "bookmarks"); | ||||
|     const JSON jsonAutoBookmarks = json_object_get(Root, "autobookmarks"); | ||||
| 
 | ||||
|     // Load user-set bookmarks
 | ||||
|     if(jsonBookmarks) | ||||
|         AddBookmarks(jsonBookmarks, true); | ||||
| 
 | ||||
|     // Load auto-set bookmarks
 | ||||
|     if(jsonAutoBookmarks) | ||||
|         AddBookmarks(jsonAutoBookmarks, false); | ||||
| } | ||||
| 
 | ||||
| bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size) | ||||
| { | ||||
|     // The array container must be set, or the size must be set, or both
 | ||||
|     if(!List && !Size) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBookmarks); | ||||
| 
 | ||||
|     // Return the size if set
 | ||||
|     if(Size) | ||||
|     { | ||||
|         *Size = bookmarks.size() * sizeof(BOOKMARKSINFO); | ||||
| 
 | ||||
|         if(!List) | ||||
|             return true; | ||||
|     } | ||||
| 
 | ||||
|     // Copy struct and adjust the relative offset to a virtual address
 | ||||
|     for(auto & itr : bookmarks) | ||||
|     { | ||||
|         *List = itr.second; | ||||
|         List->addr += ModBaseFromName(List->mod); | ||||
| 
 | ||||
|         List++; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void BookmarkClear() | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
|     bookmarks.clear(); | ||||
| #include "bookmark.h" | ||||
| #include "threading.h" | ||||
| #include "module.h" | ||||
| #include "memory.h" | ||||
| 
 | ||||
| std::unordered_map<uint, BOOKMARKSINFO> bookmarks; | ||||
| 
 | ||||
| bool BookmarkSet(uint Address, bool Manual) | ||||
| { | ||||
|     // CHECK: Export call
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // Validate the incoming address
 | ||||
|     if(!MemIsValidReadPtr(Address)) | ||||
|         return false; | ||||
| 
 | ||||
|     BOOKMARKSINFO bookmark; | ||||
|     ModNameFromAddr(Address, bookmark.mod, true); | ||||
|     bookmark.addr = Address - ModBaseFromAddr(Address); | ||||
|     bookmark.manual = Manual; | ||||
| 
 | ||||
|     // Exclusive lock to insert new data
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
| 
 | ||||
|     if(!bookmarks.insert(std::make_pair(ModHashFromAddr(Address), bookmark)).second) | ||||
|     { | ||||
|         EXCLUSIVE_RELEASE(); | ||||
|         return BookmarkDelete(Address); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BookmarkGet(uint Address) | ||||
| { | ||||
|     // CHECK: Export call
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBookmarks); | ||||
|     return (bookmarks.count(ModHashFromAddr(Address)) > 0); | ||||
| } | ||||
| 
 | ||||
| bool BookmarkDelete(uint Address) | ||||
| { | ||||
|     // CHECK: Export call
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
|     return (bookmarks.erase(ModHashFromAddr(Address)) > 0); | ||||
| } | ||||
| 
 | ||||
| void BookmarkDelRange(uint Start, uint End) | ||||
| { | ||||
|     // CHECK: Export call
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return; | ||||
| 
 | ||||
|     // Are all bookmarks going to be deleted?
 | ||||
|     // 0x00000000 - 0xFFFFFFFF
 | ||||
|     if(Start == 0 && End == ~0) | ||||
|     { | ||||
|         BookmarkClear(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Make sure 'Start' and 'End' reference the same module
 | ||||
|         uint moduleBase = ModBaseFromAddr(Start); | ||||
| 
 | ||||
|         if(moduleBase != ModBaseFromAddr(End)) | ||||
|             return; | ||||
| 
 | ||||
|         // Virtual -> relative offset
 | ||||
|         Start -= moduleBase; | ||||
|         End -= moduleBase; | ||||
| 
 | ||||
|         EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
|         for(auto itr = bookmarks.begin(); itr != bookmarks.end();) | ||||
|         { | ||||
|             const auto & currentBookmark = itr->second; | ||||
| 
 | ||||
|             // Ignore manually set entries
 | ||||
|             if(currentBookmark.manual) | ||||
|             { | ||||
|                 ++itr; | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             // [Start, End)
 | ||||
|             if(currentBookmark.addr >= Start && currentBookmark.addr < End) | ||||
|                 itr = bookmarks.erase(itr); | ||||
|             else | ||||
|                 ++itr; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void BookmarkCacheSave(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
| 
 | ||||
|     const JSON jsonBookmarks = json_array(); | ||||
|     const JSON jsonAutoBookmarks = json_array(); | ||||
| 
 | ||||
|     // Save to the JSON root
 | ||||
|     for(auto & itr : bookmarks) | ||||
|     { | ||||
|         JSON currentBookmark = json_object(); | ||||
| 
 | ||||
|         json_object_set_new(currentBookmark, "module", json_string(itr.second.mod)); | ||||
|         json_object_set_new(currentBookmark, "address", json_hex(itr.second.addr)); | ||||
| 
 | ||||
|         if(itr.second.manual) | ||||
|             json_array_append_new(jsonBookmarks, currentBookmark); | ||||
|         else | ||||
|             json_array_append_new(jsonAutoBookmarks, currentBookmark); | ||||
|     } | ||||
| 
 | ||||
|     if(json_array_size(jsonBookmarks)) | ||||
|         json_object_set(Root, "bookmarks", jsonBookmarks); | ||||
| 
 | ||||
|     if(json_array_size(jsonAutoBookmarks)) | ||||
|         json_object_set(Root, "autobookmarks", jsonAutoBookmarks); | ||||
| 
 | ||||
|     json_decref(jsonBookmarks); | ||||
|     json_decref(jsonAutoBookmarks); | ||||
| } | ||||
| 
 | ||||
| void BookmarkCacheLoad(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
| 
 | ||||
|     // Inline lambda to parse each JSON entry
 | ||||
|     auto AddBookmarks = [](const JSON Object, bool Manual) | ||||
|     { | ||||
|         size_t i; | ||||
|         JSON value; | ||||
| 
 | ||||
|         json_array_foreach(Object, i, value) | ||||
|         { | ||||
|             BOOKMARKSINFO bookmarkInfo; | ||||
|             memset(&bookmarkInfo, 0, sizeof(BOOKMARKSINFO)); | ||||
| 
 | ||||
|             // Load the module name
 | ||||
|             const char* mod = json_string_value(json_object_get(value, "module")); | ||||
| 
 | ||||
|             if(mod && strlen(mod) < MAX_MODULE_SIZE) | ||||
|                 strcpy_s(bookmarkInfo.mod, mod); | ||||
| 
 | ||||
|             // Load address and set auto-generated flag
 | ||||
|             bookmarkInfo.addr = (uint)json_hex_value(json_object_get(value, "address")); | ||||
|             bookmarkInfo.manual = Manual; | ||||
| 
 | ||||
|             const uint key = ModHashFromName(bookmarkInfo.mod) + bookmarkInfo.addr; | ||||
|             bookmarks.insert(std::make_pair(key, bookmarkInfo)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // Remove existing entries
 | ||||
|     bookmarks.clear(); | ||||
| 
 | ||||
|     const JSON jsonBookmarks = json_object_get(Root, "bookmarks"); | ||||
|     const JSON jsonAutoBookmarks = json_object_get(Root, "autobookmarks"); | ||||
| 
 | ||||
|     // Load user-set bookmarks
 | ||||
|     if(jsonBookmarks) | ||||
|         AddBookmarks(jsonBookmarks, true); | ||||
| 
 | ||||
|     // Load auto-set bookmarks
 | ||||
|     if(jsonAutoBookmarks) | ||||
|         AddBookmarks(jsonAutoBookmarks, false); | ||||
| } | ||||
| 
 | ||||
| bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size) | ||||
| { | ||||
|     // The array container must be set, or the size must be set, or both
 | ||||
|     if(!List && !Size) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBookmarks); | ||||
| 
 | ||||
|     // Return the size if set
 | ||||
|     if(Size) | ||||
|     { | ||||
|         *Size = bookmarks.size() * sizeof(BOOKMARKSINFO); | ||||
| 
 | ||||
|         if(!List) | ||||
|             return true; | ||||
|     } | ||||
| 
 | ||||
|     // Copy struct and adjust the relative offset to a virtual address
 | ||||
|     for(auto & itr : bookmarks) | ||||
|     { | ||||
|         *List = itr.second; | ||||
|         List->addr += ModBaseFromName(List->mod); | ||||
| 
 | ||||
|         List++; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void BookmarkClear() | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBookmarks); | ||||
|     bookmarks.clear(); | ||||
| } | ||||
|  | @ -1,19 +1,19 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| struct BOOKMARKSINFO | ||||
| { | ||||
|     char mod[MAX_MODULE_SIZE]; | ||||
|     uint addr; | ||||
|     bool manual; | ||||
| }; | ||||
| 
 | ||||
| bool BookmarkSet(uint Address, bool Manual); | ||||
| bool BookmarkGet(uint Address); | ||||
| bool BookmarkDelete(uint Address); | ||||
| void BookmarkDelRange(uint Start, uint End); | ||||
| void BookmarkCacheSave(JSON Root); | ||||
| void BookmarkCacheLoad(JSON Root); | ||||
| bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size); | ||||
| #pragma once | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| struct BOOKMARKSINFO | ||||
| { | ||||
|     char mod[MAX_MODULE_SIZE]; | ||||
|     uint addr; | ||||
|     bool manual; | ||||
| }; | ||||
| 
 | ||||
| bool BookmarkSet(uint Address, bool Manual); | ||||
| bool BookmarkGet(uint Address); | ||||
| bool BookmarkDelete(uint Address); | ||||
| void BookmarkDelRange(uint Start, uint End); | ||||
| void BookmarkCacheSave(JSON Root); | ||||
| void BookmarkCacheLoad(JSON Root); | ||||
| bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size); | ||||
| void BookmarkClear(); | ||||
|  | @ -1,406 +1,406 @@ | |||
| /**
 | ||||
|  @file breakpoint.cpp | ||||
| 
 | ||||
|  @brief Implements the breakpoint class. | ||||
|  */ | ||||
| 
 | ||||
| #include "breakpoint.h" | ||||
| #include "memory.h" | ||||
| #include "threading.h" | ||||
| #include "module.h" | ||||
| 
 | ||||
| typedef std::pair<BP_TYPE, uint> BreakpointKey; | ||||
| std::map<BreakpointKey, BREAKPOINT> breakpoints; | ||||
| 
 | ||||
| BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, uint Address) | ||||
| { | ||||
|     //
 | ||||
|     // NOTE: THIS DOES _NOT_ USE LOCKS
 | ||||
|     //
 | ||||
|     auto found = breakpoints.find(BreakpointKey(Type, ModHashFromAddr(Address))); | ||||
| 
 | ||||
|     // Was the module found with this address?
 | ||||
|     if(found == breakpoints.end()) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     return &found->second; | ||||
| } | ||||
| 
 | ||||
| int BpGetList(std::vector<BREAKPOINT>* List) | ||||
| { | ||||
|     // CHECK: Exported function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Did the caller request an output?
 | ||||
|     if(List) | ||||
|     { | ||||
|         // Enumerate all breakpoints in the global list, fixing the relative
 | ||||
|         // offset to a virtual address
 | ||||
|         for(auto & i : breakpoints) | ||||
|         { | ||||
|             BREAKPOINT currentBp = i.second; | ||||
|             currentBp.addr += ModBaseFromName(currentBp.mod); | ||||
|             currentBp.active = MemIsValidReadPtr(currentBp.addr); | ||||
| 
 | ||||
|             List->push_back(currentBp); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return (int)breakpoints.size(); | ||||
| } | ||||
| 
 | ||||
| bool BpNew(uint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // Fail if the address is a bad memory region
 | ||||
|     if(!MemIsValidReadPtr(Address)) | ||||
|         return false; | ||||
| 
 | ||||
|     // Fail if the breakpoint already exists
 | ||||
|     if(BpGet(Address, Type, Name, nullptr)) | ||||
|         return false; | ||||
| 
 | ||||
|     // Default to an empty name if one wasn't supplied
 | ||||
|     if(!Name) | ||||
|         Name = ""; | ||||
| 
 | ||||
|     BREAKPOINT bp; | ||||
|     memset(&bp, 0, sizeof(BREAKPOINT)); | ||||
| 
 | ||||
|     ModNameFromAddr(Address, bp.mod, true); | ||||
|     strcpy_s(bp.name, Name); | ||||
| 
 | ||||
|     bp.active = true; | ||||
|     bp.addr = Address - ModBaseFromAddr(Address); | ||||
|     bp.enabled = Enable; | ||||
|     bp.oldbytes = OldBytes; | ||||
|     bp.singleshoot = Singleshot; | ||||
|     bp.titantype = TitanType; | ||||
|     bp.type = Type; | ||||
| 
 | ||||
|     // Insert new entry to the global list
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     breakpoints.insert(std::make_pair(BreakpointKey(Type, ModHashFromAddr(Address)), bp)); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BpGet(uint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp) | ||||
| { | ||||
|     // CHECK: Export/Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Name is optional
 | ||||
|     if(!Name || Name[0] == '\0') | ||||
|     { | ||||
|         // Perform a lookup by address only
 | ||||
|         BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address); | ||||
| 
 | ||||
|         if(!bpInfo) | ||||
|             return false; | ||||
| 
 | ||||
|         // Succeed even if the user didn't request anything
 | ||||
|         if(!Bp) | ||||
|             return true; | ||||
| 
 | ||||
|         *Bp = *bpInfo; | ||||
|         Bp->addr += ModBaseFromAddr(Address); | ||||
|         Bp->active = MemIsValidReadPtr(Bp->addr); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     // Do a lookup by breakpoint name
 | ||||
|     for(auto & i : breakpoints) | ||||
|     { | ||||
|         // Do the names match?
 | ||||
|         if(strcmp(Name, i.second.name) != 0) | ||||
|             continue; | ||||
| 
 | ||||
|         // Fill out the optional user buffer
 | ||||
|         if(Bp) | ||||
|         { | ||||
|             *Bp = i.second; | ||||
|             Bp->addr += ModBaseFromAddr(Address); | ||||
|             Bp->active = MemIsValidReadPtr(Bp->addr); | ||||
|         } | ||||
| 
 | ||||
|         // Return true if the name was found at all
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool BpDelete(uint Address, BP_TYPE Type) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // Erase the index from the global list
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     return (breakpoints.erase(BreakpointKey(Type, ModHashFromAddr(Address))) > 0); | ||||
| } | ||||
| 
 | ||||
| bool BpEnable(uint Address, BP_TYPE Type, bool Enable) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Check if the breakpoint exists first
 | ||||
|     BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address); | ||||
| 
 | ||||
|     if(!bpInfo) | ||||
|         return false; | ||||
| 
 | ||||
|     bpInfo->enabled = Enable; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BpSetName(uint Address, BP_TYPE Type, const char* Name) | ||||
| { | ||||
|     // CHECK: Future(?); This is not used anywhere
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // If a name wasn't supplied, set to nothing
 | ||||
|     if(!Name) | ||||
|         Name = ""; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Check if the breakpoint exists first
 | ||||
|     BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address); | ||||
| 
 | ||||
|     if(!bpInfo) | ||||
|         return false; | ||||
| 
 | ||||
|     strcpy_s(bpInfo->name, Name); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BpSetTitanType(uint Address, BP_TYPE Type, int TitanType) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Set the TitanEngine type, separate from BP_TYPE
 | ||||
|     BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address); | ||||
| 
 | ||||
|     if(!bpInfo) | ||||
|         return false; | ||||
| 
 | ||||
|     bpInfo->titantype = TitanType; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module) | ||||
| { | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Loop each entry, executing the user's callback
 | ||||
|     bool callbackStatus = true; | ||||
| 
 | ||||
|     auto i = breakpoints.begin(); | ||||
|     while(i != breakpoints.end()) | ||||
|     { | ||||
|         auto j = i; | ||||
|         ++i; //increment here, because the callback might remove the current entry
 | ||||
| 
 | ||||
|         // If a module name was sent, check it
 | ||||
|         if(Module && Module[0] != '\0') | ||||
|         { | ||||
|             if(strcmp(j->second.mod, Module) != 0) | ||||
|                 continue; | ||||
|         } | ||||
| 
 | ||||
|         BREAKPOINT bpInfo = j->second; | ||||
|         bpInfo.addr += ModBaseFromName(bpInfo.mod); | ||||
|         bpInfo.active = MemIsValidReadPtr(bpInfo.addr); | ||||
| 
 | ||||
|         // Lock must be released due to callback sub-locks
 | ||||
|         SHARED_RELEASE() | ||||
| 
 | ||||
|         // Execute the callback
 | ||||
|         if(!EnumCallback(&bpInfo)) | ||||
|             callbackStatus = false; | ||||
| 
 | ||||
|         // Restore the breakpoint map lock
 | ||||
|         SHARED_REACQUIRE(); | ||||
|     } | ||||
| 
 | ||||
|     return callbackStatus; | ||||
| } | ||||
| 
 | ||||
| bool BpEnumAll(BPENUMCALLBACK EnumCallback) | ||||
| { | ||||
|     return BpEnumAll(EnumCallback, nullptr); | ||||
| } | ||||
| 
 | ||||
| int BpGetCount(BP_TYPE Type, bool EnabledOnly) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Count the number of enabled/disabled breakpoint types
 | ||||
|     int count = 0; | ||||
| 
 | ||||
|     for(auto & i : breakpoints) | ||||
|     { | ||||
|         // Check if the type matches
 | ||||
|         if(i.first.first != Type) | ||||
|             continue; | ||||
| 
 | ||||
|         // If it's not enabled, skip it
 | ||||
|         if(EnabledOnly && !i.second.enabled) | ||||
|             continue; | ||||
| 
 | ||||
|         count++; | ||||
|     } | ||||
| 
 | ||||
|     return count; | ||||
| } | ||||
| 
 | ||||
| void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp) | ||||
| { | ||||
|     //
 | ||||
|     // Convert a debugger breakpoint to an open/exported
 | ||||
|     // bridge breakpoint
 | ||||
|     //
 | ||||
|     // TOOD: ASSERT(?) These should never be null
 | ||||
|     if(!Bp || !BridgeBp) | ||||
|         return; | ||||
| 
 | ||||
|     memset(BridgeBp, 0, sizeof(BRIDGEBP)); | ||||
|     strcpy_s(BridgeBp->mod, Bp->mod); | ||||
|     strcpy_s(BridgeBp->name, Bp->name); | ||||
| 
 | ||||
|     BridgeBp->active = Bp->active; | ||||
|     BridgeBp->addr = Bp->addr; | ||||
|     BridgeBp->enabled = Bp->enabled; | ||||
|     BridgeBp->singleshoot = Bp->singleshoot; | ||||
| 
 | ||||
|     switch(Bp->type) | ||||
|     { | ||||
|     case BPNORMAL: | ||||
|         BridgeBp->type = bp_normal; | ||||
|         break; | ||||
|     case BPHARDWARE: | ||||
|         BridgeBp->type = bp_hardware; | ||||
|         break; | ||||
|     case BPMEMORY: | ||||
|         BridgeBp->type = bp_memory; | ||||
|         break; | ||||
|     default: | ||||
|         BridgeBp->type = bp_none; | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void BpCacheSave(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Create a JSON array to store each sub-object with a breakpoint
 | ||||
|     const JSON jsonBreakpoints = json_array(); | ||||
| 
 | ||||
|     // Loop all breakpoints
 | ||||
|     for(auto & i : breakpoints) | ||||
|     { | ||||
|         auto & breakpoint = i.second; | ||||
| 
 | ||||
|         // Ignore single-shot breakpoints
 | ||||
|         if(breakpoint.singleshoot) | ||||
|             continue; | ||||
| 
 | ||||
|         JSON jsonObj = json_object(); | ||||
|         json_object_set_new(jsonObj, "address", json_hex(breakpoint.addr)); | ||||
|         json_object_set_new(jsonObj, "enabled", json_boolean(breakpoint.enabled)); | ||||
| 
 | ||||
|         // "Normal" breakpoints save the old data
 | ||||
|         if(breakpoint.type == BPNORMAL) | ||||
|             json_object_set_new(jsonObj, "oldbytes", json_hex(breakpoint.oldbytes)); | ||||
| 
 | ||||
|         json_object_set_new(jsonObj, "type", json_integer(breakpoint.type)); | ||||
|         json_object_set_new(jsonObj, "titantype", json_hex(breakpoint.titantype)); | ||||
|         json_object_set_new(jsonObj, "name", json_string(breakpoint.name)); | ||||
|         json_object_set_new(jsonObj, "module", json_string(breakpoint.mod)); | ||||
|         json_array_append_new(jsonBreakpoints, jsonObj); | ||||
|     } | ||||
| 
 | ||||
|     if(json_array_size(jsonBreakpoints)) | ||||
|         json_object_set(Root, "breakpoints", jsonBreakpoints); | ||||
| 
 | ||||
|     // Notify garbage collector
 | ||||
|     json_decref(jsonBreakpoints); | ||||
| } | ||||
| 
 | ||||
| void BpCacheLoad(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Remove all existing elements
 | ||||
|     breakpoints.clear(); | ||||
| 
 | ||||
|     // Get a handle to the root object -> breakpoints subtree
 | ||||
|     const JSON jsonBreakpoints = json_object_get(Root, "breakpoints"); | ||||
| 
 | ||||
|     // Return if there was nothing to load
 | ||||
|     if(!jsonBreakpoints) | ||||
|         return; | ||||
| 
 | ||||
|     size_t i; | ||||
|     JSON value; | ||||
|     json_array_foreach(jsonBreakpoints, i, value) | ||||
|     { | ||||
|         BREAKPOINT breakpoint; | ||||
|         memset(&breakpoint, 0, sizeof(BREAKPOINT)); | ||||
| 
 | ||||
|         if(breakpoint.type == BPNORMAL) | ||||
|             breakpoint.oldbytes = (short)json_hex_value(json_object_get(value, "oldbytes")); | ||||
|         breakpoint.type = (BP_TYPE)json_integer_value(json_object_get(value, "type")); | ||||
|         breakpoint.addr = (uint)json_hex_value(json_object_get(value, "address")); | ||||
|         breakpoint.enabled = json_boolean_value(json_object_get(value, "enabled")); | ||||
|         breakpoint.titantype = (DWORD)json_hex_value(json_object_get(value, "titantype")); | ||||
| 
 | ||||
|         // Name
 | ||||
|         const char* name = json_string_value(json_object_get(value, "name")); | ||||
| 
 | ||||
|         if(name) | ||||
|             strcpy_s(breakpoint.name, name); | ||||
| 
 | ||||
|         // Module
 | ||||
|         const char* mod = json_string_value(json_object_get(value, "module")); | ||||
| 
 | ||||
|         if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE) | ||||
|             strcpy_s(breakpoint.mod, mod); | ||||
| 
 | ||||
|         // Build the hash map key: MOD_HASH + ADDRESS
 | ||||
|         const uint key = ModHashFromName(breakpoint.mod) + breakpoint.addr; | ||||
|         breakpoints.insert(std::make_pair(BreakpointKey(breakpoint.type, key), breakpoint)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void BpClear() | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
|     breakpoints.clear(); | ||||
| /**
 | ||||
|  @file breakpoint.cpp | ||||
| 
 | ||||
|  @brief Implements the breakpoint class. | ||||
|  */ | ||||
| 
 | ||||
| #include "breakpoint.h" | ||||
| #include "memory.h" | ||||
| #include "threading.h" | ||||
| #include "module.h" | ||||
| 
 | ||||
| typedef std::pair<BP_TYPE, uint> BreakpointKey; | ||||
| std::map<BreakpointKey, BREAKPOINT> breakpoints; | ||||
| 
 | ||||
| BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, uint Address) | ||||
| { | ||||
|     //
 | ||||
|     // NOTE: THIS DOES _NOT_ USE LOCKS
 | ||||
|     //
 | ||||
|     auto found = breakpoints.find(BreakpointKey(Type, ModHashFromAddr(Address))); | ||||
| 
 | ||||
|     // Was the module found with this address?
 | ||||
|     if(found == breakpoints.end()) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     return &found->second; | ||||
| } | ||||
| 
 | ||||
| int BpGetList(std::vector<BREAKPOINT>* List) | ||||
| { | ||||
|     // CHECK: Exported function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Did the caller request an output?
 | ||||
|     if(List) | ||||
|     { | ||||
|         // Enumerate all breakpoints in the global list, fixing the relative
 | ||||
|         // offset to a virtual address
 | ||||
|         for(auto & i : breakpoints) | ||||
|         { | ||||
|             BREAKPOINT currentBp = i.second; | ||||
|             currentBp.addr += ModBaseFromName(currentBp.mod); | ||||
|             currentBp.active = MemIsValidReadPtr(currentBp.addr); | ||||
| 
 | ||||
|             List->push_back(currentBp); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return (int)breakpoints.size(); | ||||
| } | ||||
| 
 | ||||
| bool BpNew(uint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // Fail if the address is a bad memory region
 | ||||
|     if(!MemIsValidReadPtr(Address)) | ||||
|         return false; | ||||
| 
 | ||||
|     // Fail if the breakpoint already exists
 | ||||
|     if(BpGet(Address, Type, Name, nullptr)) | ||||
|         return false; | ||||
| 
 | ||||
|     // Default to an empty name if one wasn't supplied
 | ||||
|     if(!Name) | ||||
|         Name = ""; | ||||
| 
 | ||||
|     BREAKPOINT bp; | ||||
|     memset(&bp, 0, sizeof(BREAKPOINT)); | ||||
| 
 | ||||
|     ModNameFromAddr(Address, bp.mod, true); | ||||
|     strcpy_s(bp.name, Name); | ||||
| 
 | ||||
|     bp.active = true; | ||||
|     bp.addr = Address - ModBaseFromAddr(Address); | ||||
|     bp.enabled = Enable; | ||||
|     bp.oldbytes = OldBytes; | ||||
|     bp.singleshoot = Singleshot; | ||||
|     bp.titantype = TitanType; | ||||
|     bp.type = Type; | ||||
| 
 | ||||
|     // Insert new entry to the global list
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     breakpoints.insert(std::make_pair(BreakpointKey(Type, ModHashFromAddr(Address)), bp)); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BpGet(uint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp) | ||||
| { | ||||
|     // CHECK: Export/Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Name is optional
 | ||||
|     if(!Name || Name[0] == '\0') | ||||
|     { | ||||
|         // Perform a lookup by address only
 | ||||
|         BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address); | ||||
| 
 | ||||
|         if(!bpInfo) | ||||
|             return false; | ||||
| 
 | ||||
|         // Succeed even if the user didn't request anything
 | ||||
|         if(!Bp) | ||||
|             return true; | ||||
| 
 | ||||
|         *Bp = *bpInfo; | ||||
|         Bp->addr += ModBaseFromAddr(Address); | ||||
|         Bp->active = MemIsValidReadPtr(Bp->addr); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     // Do a lookup by breakpoint name
 | ||||
|     for(auto & i : breakpoints) | ||||
|     { | ||||
|         // Do the names match?
 | ||||
|         if(strcmp(Name, i.second.name) != 0) | ||||
|             continue; | ||||
| 
 | ||||
|         // Fill out the optional user buffer
 | ||||
|         if(Bp) | ||||
|         { | ||||
|             *Bp = i.second; | ||||
|             Bp->addr += ModBaseFromAddr(Address); | ||||
|             Bp->active = MemIsValidReadPtr(Bp->addr); | ||||
|         } | ||||
| 
 | ||||
|         // Return true if the name was found at all
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool BpDelete(uint Address, BP_TYPE Type) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // Erase the index from the global list
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     return (breakpoints.erase(BreakpointKey(Type, ModHashFromAddr(Address))) > 0); | ||||
| } | ||||
| 
 | ||||
| bool BpEnable(uint Address, BP_TYPE Type, bool Enable) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Check if the breakpoint exists first
 | ||||
|     BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address); | ||||
| 
 | ||||
|     if(!bpInfo) | ||||
|         return false; | ||||
| 
 | ||||
|     bpInfo->enabled = Enable; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BpSetName(uint Address, BP_TYPE Type, const char* Name) | ||||
| { | ||||
|     // CHECK: Future(?); This is not used anywhere
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // If a name wasn't supplied, set to nothing
 | ||||
|     if(!Name) | ||||
|         Name = ""; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Check if the breakpoint exists first
 | ||||
|     BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address); | ||||
| 
 | ||||
|     if(!bpInfo) | ||||
|         return false; | ||||
| 
 | ||||
|     strcpy_s(bpInfo->name, Name); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BpSetTitanType(uint Address, BP_TYPE Type, int TitanType) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Set the TitanEngine type, separate from BP_TYPE
 | ||||
|     BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address); | ||||
| 
 | ||||
|     if(!bpInfo) | ||||
|         return false; | ||||
| 
 | ||||
|     bpInfo->titantype = TitanType; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module) | ||||
| { | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Loop each entry, executing the user's callback
 | ||||
|     bool callbackStatus = true; | ||||
| 
 | ||||
|     auto i = breakpoints.begin(); | ||||
|     while(i != breakpoints.end()) | ||||
|     { | ||||
|         auto j = i; | ||||
|         ++i; //increment here, because the callback might remove the current entry
 | ||||
| 
 | ||||
|         // If a module name was sent, check it
 | ||||
|         if(Module && Module[0] != '\0') | ||||
|         { | ||||
|             if(strcmp(j->second.mod, Module) != 0) | ||||
|                 continue; | ||||
|         } | ||||
| 
 | ||||
|         BREAKPOINT bpInfo = j->second; | ||||
|         bpInfo.addr += ModBaseFromName(bpInfo.mod); | ||||
|         bpInfo.active = MemIsValidReadPtr(bpInfo.addr); | ||||
| 
 | ||||
|         // Lock must be released due to callback sub-locks
 | ||||
|         SHARED_RELEASE() | ||||
| 
 | ||||
|         // Execute the callback
 | ||||
|         if(!EnumCallback(&bpInfo)) | ||||
|             callbackStatus = false; | ||||
| 
 | ||||
|         // Restore the breakpoint map lock
 | ||||
|         SHARED_REACQUIRE(); | ||||
|     } | ||||
| 
 | ||||
|     return callbackStatus; | ||||
| } | ||||
| 
 | ||||
| bool BpEnumAll(BPENUMCALLBACK EnumCallback) | ||||
| { | ||||
|     return BpEnumAll(EnumCallback, nullptr); | ||||
| } | ||||
| 
 | ||||
| int BpGetCount(BP_TYPE Type, bool EnabledOnly) | ||||
| { | ||||
|     SHARED_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Count the number of enabled/disabled breakpoint types
 | ||||
|     int count = 0; | ||||
| 
 | ||||
|     for(auto & i : breakpoints) | ||||
|     { | ||||
|         // Check if the type matches
 | ||||
|         if(i.first.first != Type) | ||||
|             continue; | ||||
| 
 | ||||
|         // If it's not enabled, skip it
 | ||||
|         if(EnabledOnly && !i.second.enabled) | ||||
|             continue; | ||||
| 
 | ||||
|         count++; | ||||
|     } | ||||
| 
 | ||||
|     return count; | ||||
| } | ||||
| 
 | ||||
| void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp) | ||||
| { | ||||
|     //
 | ||||
|     // Convert a debugger breakpoint to an open/exported
 | ||||
|     // bridge breakpoint
 | ||||
|     //
 | ||||
|     // TOOD: ASSERT(?) These should never be null
 | ||||
|     if(!Bp || !BridgeBp) | ||||
|         return; | ||||
| 
 | ||||
|     memset(BridgeBp, 0, sizeof(BRIDGEBP)); | ||||
|     strcpy_s(BridgeBp->mod, Bp->mod); | ||||
|     strcpy_s(BridgeBp->name, Bp->name); | ||||
| 
 | ||||
|     BridgeBp->active = Bp->active; | ||||
|     BridgeBp->addr = Bp->addr; | ||||
|     BridgeBp->enabled = Bp->enabled; | ||||
|     BridgeBp->singleshoot = Bp->singleshoot; | ||||
| 
 | ||||
|     switch(Bp->type) | ||||
|     { | ||||
|     case BPNORMAL: | ||||
|         BridgeBp->type = bp_normal; | ||||
|         break; | ||||
|     case BPHARDWARE: | ||||
|         BridgeBp->type = bp_hardware; | ||||
|         break; | ||||
|     case BPMEMORY: | ||||
|         BridgeBp->type = bp_memory; | ||||
|         break; | ||||
|     default: | ||||
|         BridgeBp->type = bp_none; | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void BpCacheSave(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Create a JSON array to store each sub-object with a breakpoint
 | ||||
|     const JSON jsonBreakpoints = json_array(); | ||||
| 
 | ||||
|     // Loop all breakpoints
 | ||||
|     for(auto & i : breakpoints) | ||||
|     { | ||||
|         auto & breakpoint = i.second; | ||||
| 
 | ||||
|         // Ignore single-shot breakpoints
 | ||||
|         if(breakpoint.singleshoot) | ||||
|             continue; | ||||
| 
 | ||||
|         JSON jsonObj = json_object(); | ||||
|         json_object_set_new(jsonObj, "address", json_hex(breakpoint.addr)); | ||||
|         json_object_set_new(jsonObj, "enabled", json_boolean(breakpoint.enabled)); | ||||
| 
 | ||||
|         // "Normal" breakpoints save the old data
 | ||||
|         if(breakpoint.type == BPNORMAL) | ||||
|             json_object_set_new(jsonObj, "oldbytes", json_hex(breakpoint.oldbytes)); | ||||
| 
 | ||||
|         json_object_set_new(jsonObj, "type", json_integer(breakpoint.type)); | ||||
|         json_object_set_new(jsonObj, "titantype", json_hex(breakpoint.titantype)); | ||||
|         json_object_set_new(jsonObj, "name", json_string(breakpoint.name)); | ||||
|         json_object_set_new(jsonObj, "module", json_string(breakpoint.mod)); | ||||
|         json_array_append_new(jsonBreakpoints, jsonObj); | ||||
|     } | ||||
| 
 | ||||
|     if(json_array_size(jsonBreakpoints)) | ||||
|         json_object_set(Root, "breakpoints", jsonBreakpoints); | ||||
| 
 | ||||
|     // Notify garbage collector
 | ||||
|     json_decref(jsonBreakpoints); | ||||
| } | ||||
| 
 | ||||
| void BpCacheLoad(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
| 
 | ||||
|     // Remove all existing elements
 | ||||
|     breakpoints.clear(); | ||||
| 
 | ||||
|     // Get a handle to the root object -> breakpoints subtree
 | ||||
|     const JSON jsonBreakpoints = json_object_get(Root, "breakpoints"); | ||||
| 
 | ||||
|     // Return if there was nothing to load
 | ||||
|     if(!jsonBreakpoints) | ||||
|         return; | ||||
| 
 | ||||
|     size_t i; | ||||
|     JSON value; | ||||
|     json_array_foreach(jsonBreakpoints, i, value) | ||||
|     { | ||||
|         BREAKPOINT breakpoint; | ||||
|         memset(&breakpoint, 0, sizeof(BREAKPOINT)); | ||||
| 
 | ||||
|         if(breakpoint.type == BPNORMAL) | ||||
|             breakpoint.oldbytes = (short)json_hex_value(json_object_get(value, "oldbytes")); | ||||
|         breakpoint.type = (BP_TYPE)json_integer_value(json_object_get(value, "type")); | ||||
|         breakpoint.addr = (uint)json_hex_value(json_object_get(value, "address")); | ||||
|         breakpoint.enabled = json_boolean_value(json_object_get(value, "enabled")); | ||||
|         breakpoint.titantype = (DWORD)json_hex_value(json_object_get(value, "titantype")); | ||||
| 
 | ||||
|         // Name
 | ||||
|         const char* name = json_string_value(json_object_get(value, "name")); | ||||
| 
 | ||||
|         if(name) | ||||
|             strcpy_s(breakpoint.name, name); | ||||
| 
 | ||||
|         // Module
 | ||||
|         const char* mod = json_string_value(json_object_get(value, "module")); | ||||
| 
 | ||||
|         if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE) | ||||
|             strcpy_s(breakpoint.mod, mod); | ||||
| 
 | ||||
|         // Build the hash map key: MOD_HASH + ADDRESS
 | ||||
|         const uint key = ModHashFromName(breakpoint.mod) + breakpoint.addr; | ||||
|         breakpoints.insert(std::make_pair(BreakpointKey(breakpoint.type, key), breakpoint)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void BpClear() | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockBreakpoints); | ||||
|     breakpoints.clear(); | ||||
| } | ||||
|  | @ -1,49 +1,49 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| #define TITANSETDRX(titantype, drx) titantype &= 0x0FF; titantype |= (drx<<8) | ||||
| #define TITANGETDRX(titantype) (titantype >> 8) & 0xF | ||||
| #define TITANSETTYPE(titantype, type) titantype &= 0xF0F; titantype |= (type<<4) | ||||
| #define TITANGETTYPE(titantype) (titantype >> 4) & 0xF | ||||
| #define TITANSETSIZE(titantype, size) titantype &= 0xFF0; titantype |= size; | ||||
| #define TITANGETSIZE(titantype) titantype & 0xF | ||||
| 
 | ||||
| enum BP_TYPE | ||||
| { | ||||
|     BPNORMAL = 0, | ||||
|     BPHARDWARE = 1, | ||||
|     BPMEMORY = 2 | ||||
| }; | ||||
| 
 | ||||
| struct BREAKPOINT | ||||
| { | ||||
|     uint addr; | ||||
|     bool enabled; | ||||
|     bool singleshoot; | ||||
|     bool active; | ||||
|     short oldbytes; | ||||
|     BP_TYPE type; | ||||
|     DWORD titantype; | ||||
|     char name[MAX_BREAKPOINT_SIZE]; | ||||
|     char mod[MAX_MODULE_SIZE]; | ||||
| }; | ||||
| 
 | ||||
| // Breakpoint enumeration callback
 | ||||
| typedef bool (*BPENUMCALLBACK)(const BREAKPOINT* bp); | ||||
| 
 | ||||
| BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, uint Address); | ||||
| int BpGetList(std::vector<BREAKPOINT>* List); | ||||
| bool BpNew(uint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name); | ||||
| bool BpGet(uint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp); | ||||
| bool BpDelete(uint Address, BP_TYPE Type); | ||||
| bool BpEnable(uint Address, BP_TYPE Type, bool Enable); | ||||
| bool BpSetName(uint Address, BP_TYPE Type, const char* Name); | ||||
| bool BpSetTitanType(uint Address, BP_TYPE Type, int TitanType); | ||||
| bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module); | ||||
| bool BpEnumAll(BPENUMCALLBACK EnumCallback); | ||||
| int BpGetCount(BP_TYPE Type, bool EnabledOnly = false); | ||||
| void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp); | ||||
| void BpCacheSave(JSON Root); | ||||
| void BpCacheLoad(JSON Root); | ||||
| #pragma once | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| #define TITANSETDRX(titantype, drx) titantype &= 0x0FF; titantype |= (drx<<8) | ||||
| #define TITANGETDRX(titantype) (titantype >> 8) & 0xF | ||||
| #define TITANSETTYPE(titantype, type) titantype &= 0xF0F; titantype |= (type<<4) | ||||
| #define TITANGETTYPE(titantype) (titantype >> 4) & 0xF | ||||
| #define TITANSETSIZE(titantype, size) titantype &= 0xFF0; titantype |= size; | ||||
| #define TITANGETSIZE(titantype) titantype & 0xF | ||||
| 
 | ||||
| enum BP_TYPE | ||||
| { | ||||
|     BPNORMAL = 0, | ||||
|     BPHARDWARE = 1, | ||||
|     BPMEMORY = 2 | ||||
| }; | ||||
| 
 | ||||
| struct BREAKPOINT | ||||
| { | ||||
|     uint addr; | ||||
|     bool enabled; | ||||
|     bool singleshoot; | ||||
|     bool active; | ||||
|     short oldbytes; | ||||
|     BP_TYPE type; | ||||
|     DWORD titantype; | ||||
|     char name[MAX_BREAKPOINT_SIZE]; | ||||
|     char mod[MAX_MODULE_SIZE]; | ||||
| }; | ||||
| 
 | ||||
| // Breakpoint enumeration callback
 | ||||
| typedef bool (*BPENUMCALLBACK)(const BREAKPOINT* bp); | ||||
| 
 | ||||
| BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, uint Address); | ||||
| int BpGetList(std::vector<BREAKPOINT>* List); | ||||
| bool BpNew(uint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name); | ||||
| bool BpGet(uint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp); | ||||
| bool BpDelete(uint Address, BP_TYPE Type); | ||||
| bool BpEnable(uint Address, BP_TYPE Type, bool Enable); | ||||
| bool BpSetName(uint Address, BP_TYPE Type, const char* Name); | ||||
| bool BpSetTitanType(uint Address, BP_TYPE Type, int TitanType); | ||||
| bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module); | ||||
| bool BpEnumAll(BPENUMCALLBACK EnumCallback); | ||||
| int BpGetCount(BP_TYPE Type, bool EnabledOnly = false); | ||||
| void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp); | ||||
| void BpCacheSave(JSON Root); | ||||
| void BpCacheLoad(JSON Root); | ||||
| void BpClear(); | ||||
|  | @ -1,199 +1,199 @@ | |||
| #include "console.h" | ||||
| #include "capstone_wrapper.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; | ||||
|     mError = CS_ERR_OK; | ||||
| } | ||||
| 
 | ||||
| Capstone::~Capstone() | ||||
| { | ||||
|     if(mInstr) //free last disassembled instruction
 | ||||
|         cs_free(mInstr, 1); | ||||
| } | ||||
| 
 | ||||
| bool Capstone::Disassemble(uint addr, const unsigned char data[MAX_DISASM_BUFFER]) | ||||
| { | ||||
|     return Disassemble(addr, data, MAX_DISASM_BUFFER); | ||||
| } | ||||
| 
 | ||||
| bool Capstone::Disassemble(uint addr, const unsigned char* data, int size) | ||||
| { | ||||
|     if(!data) | ||||
|         return false; | ||||
|     if(mInstr) //free last disassembled instruction
 | ||||
|     { | ||||
|         cs_free(mInstr, 1); | ||||
|         mInstr = nullptr; | ||||
|     } | ||||
|     return !!cs_disasm(mHandle, data, size, addr, 1, &mInstr); | ||||
| } | ||||
| 
 | ||||
| const cs_insn* Capstone::GetInstr() const | ||||
| { | ||||
|     return mInstr; | ||||
| } | ||||
| 
 | ||||
| cs_err Capstone::GetError() const | ||||
| { | ||||
|     return mError; | ||||
| } | ||||
| 
 | ||||
| const char* Capstone::RegName(x86_reg reg) const | ||||
| { | ||||
|     return cs_reg_name(mHandle, reg); | ||||
| } | ||||
| 
 | ||||
| bool Capstone::InGroup(cs_group_type group) const | ||||
| { | ||||
|     return cs_insn_group(mHandle, mInstr, group); | ||||
| } | ||||
| 
 | ||||
| String Capstone::OperandText(int opindex) const | ||||
| { | ||||
|     if(opindex >= mInstr->detail->x86.op_count) | ||||
|         return ""; | ||||
|     const auto & op = mInstr->detail->x86.operands[opindex]; | ||||
|     String result; | ||||
|     char temp[32] = ""; | ||||
|     switch(op.type) | ||||
|     { | ||||
|     case X86_OP_REG: | ||||
|     { | ||||
|         result = RegName(x86_reg(op.reg)); | ||||
|     } | ||||
|     break; | ||||
| 
 | ||||
|     case X86_OP_IMM: | ||||
|     { | ||||
|         if(InGroup(CS_GRP_JUMP) || InGroup(CS_GRP_CALL) || IsLoop()) | ||||
|             sprintf_s(temp, "%" fext "X", op.imm + mInstr->size); | ||||
|         else | ||||
|             sprintf_s(temp, "%" fext "X", 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, "%" fext "X", mInstr->address + op.mem.disp + mInstr->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, "%" fext "X", mem.disp * -1); | ||||
|                 } | ||||
|                 else | ||||
|                     sprintf_s(temp, "%" fext "X", mem.disp); | ||||
|                 if(prependPlus) | ||||
|                     result += operatorText; | ||||
|                 result += temp; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     break; | ||||
| 
 | ||||
|     case X86_OP_FP: | ||||
|     case X86_OP_INVALID: | ||||
|     { | ||||
|     } | ||||
|     break; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| int Capstone::Size() const | ||||
| { | ||||
|     return GetInstr()->size; | ||||
| } | ||||
| 
 | ||||
| uint Capstone::Address() const | ||||
| { | ||||
|     return uint(GetInstr()->address); | ||||
| } | ||||
| 
 | ||||
| const cs_x86 & Capstone::x86() const | ||||
| { | ||||
|     return GetInstr()->detail->x86; | ||||
| } | ||||
| 
 | ||||
| bool Capstone::IsFilling() const | ||||
| { | ||||
|     switch(GetId()) | ||||
|     { | ||||
|     case X86_INS_NOP: | ||||
|     case X86_INS_INT3: | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool Capstone::IsLoop() const | ||||
| { | ||||
|     switch(GetId()) | ||||
|     { | ||||
|     case X86_INS_LOOP: | ||||
|     case X86_INS_LOOPE: | ||||
|     case X86_INS_LOOPNE: | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| x86_insn Capstone::GetId() const | ||||
| { | ||||
|     return x86_insn(mInstr->id); | ||||
| } | ||||
| 
 | ||||
| String Capstone::InstructionText() const | ||||
| { | ||||
|     String result = mInstr->mnemonic; | ||||
|     result += " "; | ||||
|     result += mInstr->op_str; | ||||
|     return result; | ||||
| #include "console.h" | ||||
| #include "capstone_wrapper.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; | ||||
|     mError = CS_ERR_OK; | ||||
| } | ||||
| 
 | ||||
| Capstone::~Capstone() | ||||
| { | ||||
|     if(mInstr) //free last disassembled instruction
 | ||||
|         cs_free(mInstr, 1); | ||||
| } | ||||
| 
 | ||||
| bool Capstone::Disassemble(uint addr, const unsigned char data[MAX_DISASM_BUFFER]) | ||||
| { | ||||
|     return Disassemble(addr, data, MAX_DISASM_BUFFER); | ||||
| } | ||||
| 
 | ||||
| bool Capstone::Disassemble(uint addr, const unsigned char* data, int size) | ||||
| { | ||||
|     if(!data) | ||||
|         return false; | ||||
|     if(mInstr) //free last disassembled instruction
 | ||||
|     { | ||||
|         cs_free(mInstr, 1); | ||||
|         mInstr = nullptr; | ||||
|     } | ||||
|     return !!cs_disasm(mHandle, data, size, addr, 1, &mInstr); | ||||
| } | ||||
| 
 | ||||
| const cs_insn* Capstone::GetInstr() const | ||||
| { | ||||
|     return mInstr; | ||||
| } | ||||
| 
 | ||||
| cs_err Capstone::GetError() const | ||||
| { | ||||
|     return mError; | ||||
| } | ||||
| 
 | ||||
| const char* Capstone::RegName(x86_reg reg) const | ||||
| { | ||||
|     return cs_reg_name(mHandle, reg); | ||||
| } | ||||
| 
 | ||||
| bool Capstone::InGroup(cs_group_type group) const | ||||
| { | ||||
|     return cs_insn_group(mHandle, mInstr, group); | ||||
| } | ||||
| 
 | ||||
| String Capstone::OperandText(int opindex) const | ||||
| { | ||||
|     if(opindex >= mInstr->detail->x86.op_count) | ||||
|         return ""; | ||||
|     const auto & op = mInstr->detail->x86.operands[opindex]; | ||||
|     String result; | ||||
|     char temp[32] = ""; | ||||
|     switch(op.type) | ||||
|     { | ||||
|     case X86_OP_REG: | ||||
|     { | ||||
|         result = RegName(x86_reg(op.reg)); | ||||
|     } | ||||
|     break; | ||||
| 
 | ||||
|     case X86_OP_IMM: | ||||
|     { | ||||
|         if(InGroup(CS_GRP_JUMP) || InGroup(CS_GRP_CALL) || IsLoop()) | ||||
|             sprintf_s(temp, "%" fext "X", op.imm + mInstr->size); | ||||
|         else | ||||
|             sprintf_s(temp, "%" fext "X", 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, "%" fext "X", mInstr->address + op.mem.disp + mInstr->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, "%" fext "X", mem.disp * -1); | ||||
|                 } | ||||
|                 else | ||||
|                     sprintf_s(temp, "%" fext "X", mem.disp); | ||||
|                 if(prependPlus) | ||||
|                     result += operatorText; | ||||
|                 result += temp; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     break; | ||||
| 
 | ||||
|     case X86_OP_FP: | ||||
|     case X86_OP_INVALID: | ||||
|     { | ||||
|     } | ||||
|     break; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| int Capstone::Size() const | ||||
| { | ||||
|     return GetInstr()->size; | ||||
| } | ||||
| 
 | ||||
| uint Capstone::Address() const | ||||
| { | ||||
|     return uint(GetInstr()->address); | ||||
| } | ||||
| 
 | ||||
| const cs_x86 & Capstone::x86() const | ||||
| { | ||||
|     return GetInstr()->detail->x86; | ||||
| } | ||||
| 
 | ||||
| bool Capstone::IsFilling() const | ||||
| { | ||||
|     switch(GetId()) | ||||
|     { | ||||
|     case X86_INS_NOP: | ||||
|     case X86_INS_INT3: | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool Capstone::IsLoop() const | ||||
| { | ||||
|     switch(GetId()) | ||||
|     { | ||||
|     case X86_INS_LOOP: | ||||
|     case X86_INS_LOOPE: | ||||
|     case X86_INS_LOOPNE: | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| x86_insn Capstone::GetId() const | ||||
| { | ||||
|     return x86_insn(mInstr->id); | ||||
| } | ||||
| 
 | ||||
| String Capstone::InstructionText() const | ||||
| { | ||||
|     String result = mInstr->mnemonic; | ||||
|     result += " "; | ||||
|     result += mInstr->op_str; | ||||
|     return result; | ||||
| } | ||||
|  | @ -1,37 +1,37 @@ | |||
| #ifndef _CAPSTONE_WRAPPER_H | ||||
| #define _CAPSTONE_WRAPPER_H | ||||
| 
 | ||||
| #include "capstone\capstone.h" | ||||
| 
 | ||||
| #define MAX_DISASM_BUFFER 16 | ||||
| #define INVALID_TITAN_REG 0 | ||||
| 
 | ||||
| class Capstone | ||||
| { | ||||
| public: | ||||
|     static void GlobalInitialize(); | ||||
|     static void GlobalFinalize(); | ||||
|     Capstone(); | ||||
|     ~Capstone(); | ||||
|     bool Disassemble(uint addr, const unsigned char data[MAX_DISASM_BUFFER]); | ||||
|     bool Disassemble(uint addr, const unsigned char* data, int size); | ||||
|     const cs_insn* GetInstr() const; | ||||
|     cs_err GetError() const; | ||||
|     const char* RegName(x86_reg reg) const; | ||||
|     bool InGroup(cs_group_type group) const; | ||||
|     String OperandText(int opindex) const; | ||||
|     int Size() const; | ||||
|     uint Address() const; | ||||
|     const cs_x86 & x86() const; | ||||
|     bool IsFilling() const; | ||||
|     bool IsLoop() const; | ||||
|     x86_insn GetId() const; | ||||
|     String InstructionText() const; | ||||
| 
 | ||||
| private: | ||||
|     static csh mHandle; | ||||
|     cs_insn* mInstr; | ||||
|     cs_err mError; | ||||
| }; | ||||
| 
 | ||||
| #ifndef _CAPSTONE_WRAPPER_H | ||||
| #define _CAPSTONE_WRAPPER_H | ||||
| 
 | ||||
| #include "capstone\capstone.h" | ||||
| 
 | ||||
| #define MAX_DISASM_BUFFER 16 | ||||
| #define INVALID_TITAN_REG 0 | ||||
| 
 | ||||
| class Capstone | ||||
| { | ||||
| public: | ||||
|     static void GlobalInitialize(); | ||||
|     static void GlobalFinalize(); | ||||
|     Capstone(); | ||||
|     ~Capstone(); | ||||
|     bool Disassemble(uint addr, const unsigned char data[MAX_DISASM_BUFFER]); | ||||
|     bool Disassemble(uint addr, const unsigned char* data, int size); | ||||
|     const cs_insn* GetInstr() const; | ||||
|     cs_err GetError() const; | ||||
|     const char* RegName(x86_reg reg) const; | ||||
|     bool InGroup(cs_group_type group) const; | ||||
|     String OperandText(int opindex) const; | ||||
|     int Size() const; | ||||
|     uint Address() const; | ||||
|     const cs_x86 & x86() const; | ||||
|     bool IsFilling() const; | ||||
|     bool IsLoop() const; | ||||
|     x86_insn GetId() const; | ||||
|     String InstructionText() const; | ||||
| 
 | ||||
| private: | ||||
|     static csh mHandle; | ||||
|     cs_insn* mInstr; | ||||
|     cs_err mError; | ||||
| }; | ||||
| 
 | ||||
| #endif //_CAPSTONE_WRAPPER_H
 | ||||
|  | @ -1,400 +1,400 @@ | |||
| /**
 | ||||
|  @file command.cpp | ||||
| 
 | ||||
|  @brief Implements the command class. | ||||
|  */ | ||||
| 
 | ||||
| #include "command.h" | ||||
| #include "value.h" | ||||
| #include "console.h" | ||||
| #include "commandparser.h" | ||||
| 
 | ||||
| /**
 | ||||
| \brief Finds a ::COMMAND in a command list. | ||||
| \param [in] command list. | ||||
| \param name The name of the command to find. | ||||
| \param [out] Link to the command. | ||||
| \return null if it fails, else a ::COMMAND*. | ||||
| */ | ||||
| COMMAND* cmdfind(COMMAND* command_list, const char* name, COMMAND** link) | ||||
| { | ||||
|     COMMAND* cur = command_list; | ||||
|     if(!cur->name) | ||||
|         return 0; | ||||
|     COMMAND* prev = 0; | ||||
|     while(cur) | ||||
|     { | ||||
|         if(arraycontains(cur->name, name)) | ||||
|         { | ||||
|             if(link) | ||||
|                 *link = prev; | ||||
|             return cur; | ||||
|         } | ||||
|         prev = cur; | ||||
|         cur = cur->next; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Initialize a command list. | ||||
| \return a ::COMMAND* | ||||
| */ | ||||
| COMMAND* cmdinit() | ||||
| { | ||||
|     COMMAND* cmd = (COMMAND*)emalloc(sizeof(COMMAND), "cmdinit:cmd"); | ||||
|     memset(cmd, 0, sizeof(COMMAND)); | ||||
|     return cmd; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Clear a command list. | ||||
| \param [in] cmd_list Command list to clear. | ||||
| */ | ||||
| void cmdfree(COMMAND* cmd_list) | ||||
| { | ||||
|     COMMAND* cur = cmd_list; | ||||
|     while(cur) | ||||
|     { | ||||
|         efree(cur->name, "cmdfree:cur->name"); | ||||
|         COMMAND* next = cur->next; | ||||
|         efree(cur, "cmdfree:cur"); | ||||
|         cur = next; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Creates a new command and adds it to the list. | ||||
| \param [in,out] command_list Command list. Cannot be null. | ||||
| \param name The command name. | ||||
| \param cbCommand The command callback. | ||||
| \param debugonly true if the command can only be executed in a debugging context. | ||||
| \return true if the command was successfully added to the list. | ||||
| */ | ||||
| bool cmdnew(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly) | ||||
| { | ||||
|     if(!command_list || !cbCommand || !name || !*name || cmdfind(command_list, name, 0)) | ||||
|         return false; | ||||
|     COMMAND* cmd; | ||||
|     bool nonext = false; | ||||
|     if(!command_list->name) | ||||
|     { | ||||
|         cmd = command_list; | ||||
|         nonext = true; | ||||
|     } | ||||
|     else | ||||
|         cmd = (COMMAND*)emalloc(sizeof(COMMAND), "cmdnew:cmd"); | ||||
|     memset(cmd, 0, sizeof(COMMAND)); | ||||
|     cmd->name = (char*)emalloc(strlen(name) + 1, "cmdnew:cmd->name"); | ||||
|     strcpy(cmd->name, name); | ||||
|     cmd->cbCommand = cbCommand; | ||||
|     cmd->debugonly = debugonly; | ||||
|     COMMAND* cur = command_list; | ||||
|     if(!nonext) | ||||
|     { | ||||
|         while(cur->next) | ||||
|             cur = cur->next; | ||||
|         cur->next = cmd; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Gets a ::COMMAND from the command list. | ||||
| \param [in] command_list Command list. | ||||
| \param cmd The command to get from the list. | ||||
| \return null if the command was not found. Otherwise a ::COMMAND*. | ||||
| */ | ||||
| COMMAND* cmdget(COMMAND* command_list, const char* cmd) | ||||
| { | ||||
|     char new_cmd[deflen] = ""; | ||||
|     strcpy_s(new_cmd, deflen, cmd); | ||||
|     int len = (int)strlen(new_cmd); | ||||
|     int start = 0; | ||||
|     while(new_cmd[start] != ' ' && start < len) | ||||
|         start++; | ||||
|     new_cmd[start] = 0; | ||||
|     COMMAND* found = cmdfind(command_list, new_cmd, 0); | ||||
|     if(!found) | ||||
|         return 0; | ||||
|     return found; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Sets a new command callback and debugonly property in a command list. | ||||
| \param [in] command_list Command list. | ||||
| \param name The name of the command to change. | ||||
| \param cbCommand The new command callback. | ||||
| \param debugonly The new debugonly value. | ||||
| \return The old command callback. | ||||
| */ | ||||
| CBCOMMAND cmdset(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly) | ||||
| { | ||||
|     if(!cbCommand) | ||||
|         return 0; | ||||
|     COMMAND* found = cmdfind(command_list, name, 0); | ||||
|     if(!found) | ||||
|         return 0; | ||||
|     CBCOMMAND old = found->cbCommand; | ||||
|     found->cbCommand = cbCommand; | ||||
|     found->debugonly = debugonly; | ||||
|     return old; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Deletes a command from a command list. | ||||
| \param [in] command_list Command list. | ||||
| \param name The name of the command to delete. | ||||
| \return true if the command was deleted. | ||||
| */ | ||||
| bool cmddel(COMMAND* command_list, const char* name) | ||||
| { | ||||
|     COMMAND* prev = 0; | ||||
|     COMMAND* found = cmdfind(command_list, name, &prev); | ||||
|     if(!found) | ||||
|         return false; | ||||
|     efree(found->name, "cmddel:found->name"); | ||||
|     if(found == command_list) | ||||
|     { | ||||
|         COMMAND* next = command_list->next; | ||||
|         if(next) | ||||
|         { | ||||
|             memcpy(command_list, command_list->next, sizeof(COMMAND)); | ||||
|             command_list->next = next->next; | ||||
|             efree(next, "cmddel:next"); | ||||
|         } | ||||
|         else | ||||
|             memset(command_list, 0, sizeof(COMMAND)); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         prev->next = found->next; | ||||
|         efree(found, "cmddel:found"); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| command_list:         command list | ||||
| cbUnknownCommand:     function to execute when an unknown command was found | ||||
| cbCommandProvider:    function that provides commands (fgets for example), does not return until a command was found | ||||
| cbCommandFinder:      non-default command finder | ||||
| error_is_fatal:       error return of a command callback stops the command processing | ||||
| */ | ||||
| 
 | ||||
| /**
 | ||||
| \brief Initiates a command loop. This function will not return until a command returns ::STATUS_EXIT. | ||||
| \param [in] command_list Command list to use for the command lookups. | ||||
| \param cbUnknownCommand The unknown command callback. | ||||
| \param cbCommandProvider The command provider callback. | ||||
| \param cbCommandFinder The command finder callback. | ||||
| \param error_is_fatal true if commands that return ::STATUS_ERROR terminate the command loop. | ||||
| \return A CMDRESULT, will always be ::STATUS_EXIT. | ||||
| */ | ||||
| CMDRESULT cmdloop(COMMAND* command_list, CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal) | ||||
| { | ||||
|     if(!cbUnknownCommand || !cbCommandProvider) | ||||
|         return STATUS_ERROR; | ||||
|     char command[deflen] = ""; | ||||
|     bool bLoop = true; | ||||
|     while(bLoop) | ||||
|     { | ||||
|         if(!cbCommandProvider(command, deflen)) | ||||
|             break; | ||||
|         if(strlen(command)) | ||||
|         { | ||||
|             strcpy_s(command, StringUtils::Trim(command).c_str()); | ||||
|             COMMAND* cmd; | ||||
|             if(!cbCommandFinder) //'clean' command processing
 | ||||
|                 cmd = cmdget(command_list, command); | ||||
|             else //'dirty' command processing
 | ||||
|                 cmd = cbCommandFinder(command_list, command); | ||||
| 
 | ||||
|             if(!cmd || !cmd->cbCommand) //unknown command
 | ||||
|             { | ||||
|                 char* argv[1]; | ||||
|                 *argv = command; | ||||
|                 CMDRESULT res = cbUnknownCommand(1, argv); | ||||
|                 if((error_is_fatal && res == STATUS_ERROR) || res == STATUS_EXIT) | ||||
|                     bLoop = false; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if(cmd->debugonly && !DbgIsDebugging()) | ||||
|                 { | ||||
|                     dputs("this command is debug-only"); | ||||
|                     if(error_is_fatal) | ||||
|                         bLoop = false; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Command commandParsed(command); | ||||
|                     int argcount = commandParsed.GetArgCount(); | ||||
|                     char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmdloop:argv"); | ||||
|                     argv[0] = command; | ||||
|                     for(int i = 0; i < argcount; i++) | ||||
|                     { | ||||
|                         argv[i + 1] = (char*)emalloc(deflen, "cmdloop:argv[i+1]"); | ||||
|                         *argv[i + 1] = 0; | ||||
|                         strcpy_s(argv[i + 1], deflen, commandParsed.GetArg(i).c_str()); | ||||
|                     } | ||||
|                     CMDRESULT res = cmd->cbCommand(argcount + 1, argv); | ||||
|                     for(int i = 0; i < argcount; i++) | ||||
|                         efree(argv[i + 1], "cmdloop:argv[i+1]"); | ||||
|                     efree(argv, "cmdloop:argv"); | ||||
|                     if((error_is_fatal && res == STATUS_ERROR) || res == STATUS_EXIT) | ||||
|                         bLoop = false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return STATUS_EXIT; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| - custom command formatting rules | ||||
| */ | ||||
| 
 | ||||
| /**
 | ||||
| \brief Query if a string is a valid expression. | ||||
| \param expression The expression to check. | ||||
| \return true if the string is a valid expression. | ||||
| */ | ||||
| static bool isvalidexpression(const char* expression) | ||||
| { | ||||
|     uint value; | ||||
|     return valfromstring(expression, &value); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Check if a character is a mathematical operator. Used to determine stuff like "a *= b" | ||||
| \param ch The character to check. | ||||
| \return true if the character is an operator, false otherwise. | ||||
| */ | ||||
| static bool mathisoperator(const char ch) | ||||
| { | ||||
|     switch(ch) | ||||
|     { | ||||
|     case '*': | ||||
|     case '`': | ||||
|     case '/': | ||||
|     case '%': | ||||
|     case '+': | ||||
|     case '-': | ||||
|     case '<': | ||||
|     case '>': | ||||
|     case '&': | ||||
|     case '^': | ||||
|     case '|': | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Special formats a given command. Used as a little hack to support stuff like 'x++' and 'x=y' | ||||
| \param [in,out] string String to format. | ||||
| */ | ||||
| static void specialformat(char* string) | ||||
| { | ||||
|     int len = (int)strlen(string); | ||||
|     char* found = strstr(string, "="); | ||||
|     char str[deflen] = ""; | ||||
|     char backup[deflen] = ""; | ||||
|     strcpy_s(backup, string); //create a backup of the string
 | ||||
|     if(found) //contains =
 | ||||
|     { | ||||
|         char* a = (found - 1); | ||||
|         *found = 0; | ||||
|         found++; | ||||
|         if(!*found) | ||||
|         { | ||||
|             *found = '='; | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if(mathisoperator(*a)) //x*=3 -> x=x*3
 | ||||
|         { | ||||
|             char op = *a; | ||||
|             *a = 0; | ||||
|             if(isvalidexpression(string)) | ||||
|                 sprintf_s(str, "mov %s,%s%c%s", string, string, op, found); | ||||
|             else | ||||
|                 strcpy_s(str, backup); | ||||
|         } | ||||
|         else //x=y
 | ||||
|         { | ||||
|             if(isvalidexpression(found)) | ||||
|                 sprintf_s(str, "mov %s,%s", string, found); | ||||
|             else | ||||
|                 strcpy_s(str, backup); | ||||
|         } | ||||
|         strcpy_s(string, deflen, str); | ||||
|     } | ||||
|     else if((string[len - 1] == '+' && string[len - 2] == '+') || (string[len - 1] == '-' && string[len - 2] == '-')) //eax++/eax--
 | ||||
|     { | ||||
|         string[len - 2] = 0; | ||||
|         char op = string[len - 1]; | ||||
|         if(isvalidexpression(string)) | ||||
|             sprintf_s(str, "mov %s,%s%c1", string, string, op); | ||||
|         else | ||||
|             strcpy_s(str, backup); | ||||
|         strcpy_s(string, deflen, str); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| - 'default' command finder, with some custom rules | ||||
| */ | ||||
| 
 | ||||
| /**
 | ||||
| \brief Default command finder. It uses specialformat() and mathformat() to make sure the command is optimally checked. | ||||
| \param [in] cmd_list Command list. | ||||
| \param [in] command Command name. | ||||
| \return null if it fails, else a COMMAND*. | ||||
| */ | ||||
| COMMAND* cmdfindmain(COMMAND* cmd_list, char* command) | ||||
| { | ||||
|     COMMAND* cmd = cmdfind(cmd_list, command, 0); | ||||
|     if(!cmd) | ||||
|     { | ||||
|         specialformat(command); | ||||
|         cmd = cmdget(cmd_list, command); | ||||
|     } | ||||
|     return cmd; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Directly execute a command. | ||||
| \param [in,out] cmd_list Command list. | ||||
| \param cmd The command to execute. | ||||
| \return A CMDRESULT. | ||||
| */ | ||||
| CMDRESULT cmddirectexec(COMMAND* cmd_list, const char* cmd) | ||||
| { | ||||
|     if(!cmd || !strlen(cmd)) | ||||
|         return STATUS_ERROR; | ||||
|     char command[deflen] = ""; | ||||
|     strcpy_s(command, StringUtils::Trim(cmd).c_str()); | ||||
|     COMMAND* found = cmdfindmain(cmd_list, command); | ||||
|     if(!found || !found->cbCommand) | ||||
|         return STATUS_ERROR; | ||||
|     if(found->debugonly && !DbgIsDebugging()) | ||||
|         return STATUS_ERROR; | ||||
|     Command cmdParsed(command); | ||||
|     int argcount = cmdParsed.GetArgCount(); | ||||
|     char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmddirectexec:argv"); | ||||
|     argv[0] = command; | ||||
|     for(int i = 0; i < argcount; i++) | ||||
|     { | ||||
|         argv[i + 1] = (char*)emalloc(deflen, "cmddirectexec:argv[i+1]"); | ||||
|         *argv[i + 1] = 0; | ||||
|         strcpy_s(argv[i + 1], deflen, cmdParsed.GetArg(i).c_str()); | ||||
|     } | ||||
|     CMDRESULT res = found->cbCommand(argcount + 1, argv); | ||||
|     for(int i = 0; i < argcount; i++) | ||||
|         efree(argv[i + 1], "cmddirectexec:argv[i+1]"); | ||||
|     efree(argv, "cmddirectexec:argv"); | ||||
|     return res; | ||||
| } | ||||
| /**
 | ||||
|  @file command.cpp | ||||
| 
 | ||||
|  @brief Implements the command class. | ||||
|  */ | ||||
| 
 | ||||
| #include "command.h" | ||||
| #include "value.h" | ||||
| #include "console.h" | ||||
| #include "commandparser.h" | ||||
| 
 | ||||
| /**
 | ||||
| \brief Finds a ::COMMAND in a command list. | ||||
| \param [in] command list. | ||||
| \param name The name of the command to find. | ||||
| \param [out] Link to the command. | ||||
| \return null if it fails, else a ::COMMAND*. | ||||
| */ | ||||
| COMMAND* cmdfind(COMMAND* command_list, const char* name, COMMAND** link) | ||||
| { | ||||
|     COMMAND* cur = command_list; | ||||
|     if(!cur->name) | ||||
|         return 0; | ||||
|     COMMAND* prev = 0; | ||||
|     while(cur) | ||||
|     { | ||||
|         if(arraycontains(cur->name, name)) | ||||
|         { | ||||
|             if(link) | ||||
|                 *link = prev; | ||||
|             return cur; | ||||
|         } | ||||
|         prev = cur; | ||||
|         cur = cur->next; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Initialize a command list. | ||||
| \return a ::COMMAND* | ||||
| */ | ||||
| COMMAND* cmdinit() | ||||
| { | ||||
|     COMMAND* cmd = (COMMAND*)emalloc(sizeof(COMMAND), "cmdinit:cmd"); | ||||
|     memset(cmd, 0, sizeof(COMMAND)); | ||||
|     return cmd; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Clear a command list. | ||||
| \param [in] cmd_list Command list to clear. | ||||
| */ | ||||
| void cmdfree(COMMAND* cmd_list) | ||||
| { | ||||
|     COMMAND* cur = cmd_list; | ||||
|     while(cur) | ||||
|     { | ||||
|         efree(cur->name, "cmdfree:cur->name"); | ||||
|         COMMAND* next = cur->next; | ||||
|         efree(cur, "cmdfree:cur"); | ||||
|         cur = next; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Creates a new command and adds it to the list. | ||||
| \param [in,out] command_list Command list. Cannot be null. | ||||
| \param name The command name. | ||||
| \param cbCommand The command callback. | ||||
| \param debugonly true if the command can only be executed in a debugging context. | ||||
| \return true if the command was successfully added to the list. | ||||
| */ | ||||
| bool cmdnew(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly) | ||||
| { | ||||
|     if(!command_list || !cbCommand || !name || !*name || cmdfind(command_list, name, 0)) | ||||
|         return false; | ||||
|     COMMAND* cmd; | ||||
|     bool nonext = false; | ||||
|     if(!command_list->name) | ||||
|     { | ||||
|         cmd = command_list; | ||||
|         nonext = true; | ||||
|     } | ||||
|     else | ||||
|         cmd = (COMMAND*)emalloc(sizeof(COMMAND), "cmdnew:cmd"); | ||||
|     memset(cmd, 0, sizeof(COMMAND)); | ||||
|     cmd->name = (char*)emalloc(strlen(name) + 1, "cmdnew:cmd->name"); | ||||
|     strcpy(cmd->name, name); | ||||
|     cmd->cbCommand = cbCommand; | ||||
|     cmd->debugonly = debugonly; | ||||
|     COMMAND* cur = command_list; | ||||
|     if(!nonext) | ||||
|     { | ||||
|         while(cur->next) | ||||
|             cur = cur->next; | ||||
|         cur->next = cmd; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Gets a ::COMMAND from the command list. | ||||
| \param [in] command_list Command list. | ||||
| \param cmd The command to get from the list. | ||||
| \return null if the command was not found. Otherwise a ::COMMAND*. | ||||
| */ | ||||
| COMMAND* cmdget(COMMAND* command_list, const char* cmd) | ||||
| { | ||||
|     char new_cmd[deflen] = ""; | ||||
|     strcpy_s(new_cmd, deflen, cmd); | ||||
|     int len = (int)strlen(new_cmd); | ||||
|     int start = 0; | ||||
|     while(new_cmd[start] != ' ' && start < len) | ||||
|         start++; | ||||
|     new_cmd[start] = 0; | ||||
|     COMMAND* found = cmdfind(command_list, new_cmd, 0); | ||||
|     if(!found) | ||||
|         return 0; | ||||
|     return found; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Sets a new command callback and debugonly property in a command list. | ||||
| \param [in] command_list Command list. | ||||
| \param name The name of the command to change. | ||||
| \param cbCommand The new command callback. | ||||
| \param debugonly The new debugonly value. | ||||
| \return The old command callback. | ||||
| */ | ||||
| CBCOMMAND cmdset(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly) | ||||
| { | ||||
|     if(!cbCommand) | ||||
|         return 0; | ||||
|     COMMAND* found = cmdfind(command_list, name, 0); | ||||
|     if(!found) | ||||
|         return 0; | ||||
|     CBCOMMAND old = found->cbCommand; | ||||
|     found->cbCommand = cbCommand; | ||||
|     found->debugonly = debugonly; | ||||
|     return old; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Deletes a command from a command list. | ||||
| \param [in] command_list Command list. | ||||
| \param name The name of the command to delete. | ||||
| \return true if the command was deleted. | ||||
| */ | ||||
| bool cmddel(COMMAND* command_list, const char* name) | ||||
| { | ||||
|     COMMAND* prev = 0; | ||||
|     COMMAND* found = cmdfind(command_list, name, &prev); | ||||
|     if(!found) | ||||
|         return false; | ||||
|     efree(found->name, "cmddel:found->name"); | ||||
|     if(found == command_list) | ||||
|     { | ||||
|         COMMAND* next = command_list->next; | ||||
|         if(next) | ||||
|         { | ||||
|             memcpy(command_list, command_list->next, sizeof(COMMAND)); | ||||
|             command_list->next = next->next; | ||||
|             efree(next, "cmddel:next"); | ||||
|         } | ||||
|         else | ||||
|             memset(command_list, 0, sizeof(COMMAND)); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         prev->next = found->next; | ||||
|         efree(found, "cmddel:found"); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| command_list:         command list | ||||
| cbUnknownCommand:     function to execute when an unknown command was found | ||||
| cbCommandProvider:    function that provides commands (fgets for example), does not return until a command was found | ||||
| cbCommandFinder:      non-default command finder | ||||
| error_is_fatal:       error return of a command callback stops the command processing | ||||
| */ | ||||
| 
 | ||||
| /**
 | ||||
| \brief Initiates a command loop. This function will not return until a command returns ::STATUS_EXIT. | ||||
| \param [in] command_list Command list to use for the command lookups. | ||||
| \param cbUnknownCommand The unknown command callback. | ||||
| \param cbCommandProvider The command provider callback. | ||||
| \param cbCommandFinder The command finder callback. | ||||
| \param error_is_fatal true if commands that return ::STATUS_ERROR terminate the command loop. | ||||
| \return A CMDRESULT, will always be ::STATUS_EXIT. | ||||
| */ | ||||
| CMDRESULT cmdloop(COMMAND* command_list, CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal) | ||||
| { | ||||
|     if(!cbUnknownCommand || !cbCommandProvider) | ||||
|         return STATUS_ERROR; | ||||
|     char command[deflen] = ""; | ||||
|     bool bLoop = true; | ||||
|     while(bLoop) | ||||
|     { | ||||
|         if(!cbCommandProvider(command, deflen)) | ||||
|             break; | ||||
|         if(strlen(command)) | ||||
|         { | ||||
|             strcpy_s(command, StringUtils::Trim(command).c_str()); | ||||
|             COMMAND* cmd; | ||||
|             if(!cbCommandFinder) //'clean' command processing
 | ||||
|                 cmd = cmdget(command_list, command); | ||||
|             else //'dirty' command processing
 | ||||
|                 cmd = cbCommandFinder(command_list, command); | ||||
| 
 | ||||
|             if(!cmd || !cmd->cbCommand) //unknown command
 | ||||
|             { | ||||
|                 char* argv[1]; | ||||
|                 *argv = command; | ||||
|                 CMDRESULT res = cbUnknownCommand(1, argv); | ||||
|                 if((error_is_fatal && res == STATUS_ERROR) || res == STATUS_EXIT) | ||||
|                     bLoop = false; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if(cmd->debugonly && !DbgIsDebugging()) | ||||
|                 { | ||||
|                     dputs("this command is debug-only"); | ||||
|                     if(error_is_fatal) | ||||
|                         bLoop = false; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Command commandParsed(command); | ||||
|                     int argcount = commandParsed.GetArgCount(); | ||||
|                     char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmdloop:argv"); | ||||
|                     argv[0] = command; | ||||
|                     for(int i = 0; i < argcount; i++) | ||||
|                     { | ||||
|                         argv[i + 1] = (char*)emalloc(deflen, "cmdloop:argv[i+1]"); | ||||
|                         *argv[i + 1] = 0; | ||||
|                         strcpy_s(argv[i + 1], deflen, commandParsed.GetArg(i).c_str()); | ||||
|                     } | ||||
|                     CMDRESULT res = cmd->cbCommand(argcount + 1, argv); | ||||
|                     for(int i = 0; i < argcount; i++) | ||||
|                         efree(argv[i + 1], "cmdloop:argv[i+1]"); | ||||
|                     efree(argv, "cmdloop:argv"); | ||||
|                     if((error_is_fatal && res == STATUS_ERROR) || res == STATUS_EXIT) | ||||
|                         bLoop = false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return STATUS_EXIT; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| - custom command formatting rules | ||||
| */ | ||||
| 
 | ||||
| /**
 | ||||
| \brief Query if a string is a valid expression. | ||||
| \param expression The expression to check. | ||||
| \return true if the string is a valid expression. | ||||
| */ | ||||
| static bool isvalidexpression(const char* expression) | ||||
| { | ||||
|     uint value; | ||||
|     return valfromstring(expression, &value); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Check if a character is a mathematical operator. Used to determine stuff like "a *= b" | ||||
| \param ch The character to check. | ||||
| \return true if the character is an operator, false otherwise. | ||||
| */ | ||||
| static bool mathisoperator(const char ch) | ||||
| { | ||||
|     switch(ch) | ||||
|     { | ||||
|     case '*': | ||||
|     case '`': | ||||
|     case '/': | ||||
|     case '%': | ||||
|     case '+': | ||||
|     case '-': | ||||
|     case '<': | ||||
|     case '>': | ||||
|     case '&': | ||||
|     case '^': | ||||
|     case '|': | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Special formats a given command. Used as a little hack to support stuff like 'x++' and 'x=y' | ||||
| \param [in,out] string String to format. | ||||
| */ | ||||
| static void specialformat(char* string) | ||||
| { | ||||
|     int len = (int)strlen(string); | ||||
|     char* found = strstr(string, "="); | ||||
|     char str[deflen] = ""; | ||||
|     char backup[deflen] = ""; | ||||
|     strcpy_s(backup, string); //create a backup of the string
 | ||||
|     if(found) //contains =
 | ||||
|     { | ||||
|         char* a = (found - 1); | ||||
|         *found = 0; | ||||
|         found++; | ||||
|         if(!*found) | ||||
|         { | ||||
|             *found = '='; | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if(mathisoperator(*a)) //x*=3 -> x=x*3
 | ||||
|         { | ||||
|             char op = *a; | ||||
|             *a = 0; | ||||
|             if(isvalidexpression(string)) | ||||
|                 sprintf_s(str, "mov %s,%s%c%s", string, string, op, found); | ||||
|             else | ||||
|                 strcpy_s(str, backup); | ||||
|         } | ||||
|         else //x=y
 | ||||
|         { | ||||
|             if(isvalidexpression(found)) | ||||
|                 sprintf_s(str, "mov %s,%s", string, found); | ||||
|             else | ||||
|                 strcpy_s(str, backup); | ||||
|         } | ||||
|         strcpy_s(string, deflen, str); | ||||
|     } | ||||
|     else if((string[len - 1] == '+' && string[len - 2] == '+') || (string[len - 1] == '-' && string[len - 2] == '-')) //eax++/eax--
 | ||||
|     { | ||||
|         string[len - 2] = 0; | ||||
|         char op = string[len - 1]; | ||||
|         if(isvalidexpression(string)) | ||||
|             sprintf_s(str, "mov %s,%s%c1", string, string, op); | ||||
|         else | ||||
|             strcpy_s(str, backup); | ||||
|         strcpy_s(string, deflen, str); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| - 'default' command finder, with some custom rules | ||||
| */ | ||||
| 
 | ||||
| /**
 | ||||
| \brief Default command finder. It uses specialformat() and mathformat() to make sure the command is optimally checked. | ||||
| \param [in] cmd_list Command list. | ||||
| \param [in] command Command name. | ||||
| \return null if it fails, else a COMMAND*. | ||||
| */ | ||||
| COMMAND* cmdfindmain(COMMAND* cmd_list, char* command) | ||||
| { | ||||
|     COMMAND* cmd = cmdfind(cmd_list, command, 0); | ||||
|     if(!cmd) | ||||
|     { | ||||
|         specialformat(command); | ||||
|         cmd = cmdget(cmd_list, command); | ||||
|     } | ||||
|     return cmd; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Directly execute a command. | ||||
| \param [in,out] cmd_list Command list. | ||||
| \param cmd The command to execute. | ||||
| \return A CMDRESULT. | ||||
| */ | ||||
| CMDRESULT cmddirectexec(COMMAND* cmd_list, const char* cmd) | ||||
| { | ||||
|     if(!cmd || !strlen(cmd)) | ||||
|         return STATUS_ERROR; | ||||
|     char command[deflen] = ""; | ||||
|     strcpy_s(command, StringUtils::Trim(cmd).c_str()); | ||||
|     COMMAND* found = cmdfindmain(cmd_list, command); | ||||
|     if(!found || !found->cbCommand) | ||||
|         return STATUS_ERROR; | ||||
|     if(found->debugonly && !DbgIsDebugging()) | ||||
|         return STATUS_ERROR; | ||||
|     Command cmdParsed(command); | ||||
|     int argcount = cmdParsed.GetArgCount(); | ||||
|     char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmddirectexec:argv"); | ||||
|     argv[0] = command; | ||||
|     for(int i = 0; i < argcount; i++) | ||||
|     { | ||||
|         argv[i + 1] = (char*)emalloc(deflen, "cmddirectexec:argv[i+1]"); | ||||
|         *argv[i + 1] = 0; | ||||
|         strcpy_s(argv[i + 1], deflen, cmdParsed.GetArg(i).c_str()); | ||||
|     } | ||||
|     CMDRESULT res = found->cbCommand(argcount + 1, argv); | ||||
|     for(int i = 0; i < argcount; i++) | ||||
|         efree(argv[i + 1], "cmddirectexec:argv[i+1]"); | ||||
|     efree(argv, "cmddirectexec:argv"); | ||||
|     return res; | ||||
| } | ||||
|  | @ -1,42 +1,42 @@ | |||
| #ifndef _COMMAND_H | ||||
| #define _COMMAND_H | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| //typedefs
 | ||||
| 
 | ||||
| struct COMMAND; | ||||
| 
 | ||||
| enum CMDRESULT | ||||
| { | ||||
|     STATUS_ERROR = false, | ||||
|     STATUS_CONTINUE = true, | ||||
|     STATUS_EXIT = 2, | ||||
|     STATUS_PAUSE = 3 | ||||
| }; | ||||
| 
 | ||||
| typedef CMDRESULT(*CBCOMMAND)(int, char**); | ||||
| typedef bool (*CBCOMMANDPROVIDER)(char*, int); | ||||
| typedef COMMAND* (*CBCOMMANDFINDER)(COMMAND*, char*); | ||||
| 
 | ||||
| struct COMMAND | ||||
| { | ||||
|     char* name; | ||||
|     CBCOMMAND cbCommand; | ||||
|     bool debugonly; | ||||
|     COMMAND* next; | ||||
| }; | ||||
| 
 | ||||
| //functions
 | ||||
| COMMAND* cmdinit(); | ||||
| void cmdfree(COMMAND* cmd_list); | ||||
| COMMAND* cmdfind(COMMAND* command_list, const char* name, COMMAND** link); | ||||
| bool cmdnew(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly); | ||||
| COMMAND* cmdget(COMMAND* command_list, const char* cmd); | ||||
| CBCOMMAND cmdset(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly); | ||||
| bool cmddel(COMMAND* command_list, const char* name); | ||||
| CMDRESULT cmdloop(COMMAND* command_list, CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal); | ||||
| COMMAND* cmdfindmain(COMMAND* cmd_list, char* command); | ||||
| CMDRESULT cmddirectexec(COMMAND* cmd_list, const char* cmd); | ||||
| 
 | ||||
| #endif // _COMMAND_H
 | ||||
| #ifndef _COMMAND_H | ||||
| #define _COMMAND_H | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| //typedefs
 | ||||
| 
 | ||||
| struct COMMAND; | ||||
| 
 | ||||
| enum CMDRESULT | ||||
| { | ||||
|     STATUS_ERROR = false, | ||||
|     STATUS_CONTINUE = true, | ||||
|     STATUS_EXIT = 2, | ||||
|     STATUS_PAUSE = 3 | ||||
| }; | ||||
| 
 | ||||
| typedef CMDRESULT(*CBCOMMAND)(int, char**); | ||||
| typedef bool (*CBCOMMANDPROVIDER)(char*, int); | ||||
| typedef COMMAND* (*CBCOMMANDFINDER)(COMMAND*, char*); | ||||
| 
 | ||||
| struct COMMAND | ||||
| { | ||||
|     char* name; | ||||
|     CBCOMMAND cbCommand; | ||||
|     bool debugonly; | ||||
|     COMMAND* next; | ||||
| }; | ||||
| 
 | ||||
| //functions
 | ||||
| COMMAND* cmdinit(); | ||||
| void cmdfree(COMMAND* cmd_list); | ||||
| COMMAND* cmdfind(COMMAND* command_list, const char* name, COMMAND** link); | ||||
| bool cmdnew(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly); | ||||
| COMMAND* cmdget(COMMAND* command_list, const char* cmd); | ||||
| CBCOMMAND cmdset(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly); | ||||
| bool cmddel(COMMAND* command_list, const char* name); | ||||
| CMDRESULT cmdloop(COMMAND* command_list, CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal); | ||||
| COMMAND* cmdfindmain(COMMAND* cmd_list, char* command); | ||||
| CMDRESULT cmddirectexec(COMMAND* cmd_list, const char* cmd); | ||||
| 
 | ||||
| #endif // _COMMAND_H
 | ||||
|  | @ -1,114 +1,114 @@ | |||
| #include "commandparser.h" | ||||
| 
 | ||||
| Command::Command(const String & command) | ||||
| { | ||||
|     ParseState state = Default; | ||||
|     int len = (int)command.length(); | ||||
|     for(int i = 0; i < len; i++) | ||||
|     { | ||||
|         char ch = command[i]; | ||||
|         switch(state) | ||||
|         { | ||||
|         case Default: | ||||
|             switch(ch) | ||||
|             { | ||||
|             case ' ': | ||||
|                 if(!_tokens.size()) | ||||
|                     dataFinish(); | ||||
|                 break; | ||||
|             case ',': | ||||
|                 dataFinish(); | ||||
|                 break; | ||||
|             case '\\': | ||||
|                 state = Escaped; | ||||
|                 break; | ||||
|             case '\"': | ||||
|                 state = Text; | ||||
|                 break; | ||||
|             default: | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             } | ||||
|             break; | ||||
|         case Escaped: | ||||
|             switch(ch) | ||||
|             { | ||||
|             case ' ': | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             case ',': | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             case '\"': | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             default: | ||||
|                 dataAppend('\\'); | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             } | ||||
|             state = Default; | ||||
|             break; | ||||
|         case Text: | ||||
|             switch(ch) | ||||
|             { | ||||
|             case '\\': | ||||
|                 state = TextEscaped; | ||||
|                 break; | ||||
|             case '\"': | ||||
|                 dataFinish(); | ||||
|                 state = Default; | ||||
|                 break; | ||||
|             default: | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             } | ||||
|             break; | ||||
|         case TextEscaped: | ||||
|             switch(ch) | ||||
|             { | ||||
|             case '\"': | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             default: | ||||
|                 dataAppend('\\'); | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             } | ||||
|             state = Text; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if(state == Escaped || state == TextEscaped) | ||||
|         dataAppend('\\'); | ||||
|     dataFinish(); | ||||
| } | ||||
| 
 | ||||
| const String Command::GetText() | ||||
| { | ||||
|     return _tokens.size() ? _tokens[0] : String(); | ||||
| } | ||||
| 
 | ||||
| const int Command::GetArgCount() | ||||
| { | ||||
|     return _tokens.size() ? (int)_tokens.size() - 1 : 0; | ||||
| } | ||||
| 
 | ||||
| const String Command::GetArg(int argnum) | ||||
| { | ||||
|     return (int)_tokens.size() < argnum + 1 ? String() : _tokens[argnum + 1]; | ||||
| } | ||||
| 
 | ||||
| void Command::dataAppend(const char ch) | ||||
| { | ||||
|     _data += ch; | ||||
| } | ||||
| 
 | ||||
| void Command::dataFinish() | ||||
| { | ||||
|     if(_data.length()) | ||||
|     { | ||||
|         _tokens.push_back(_data); | ||||
|         _data.clear(); | ||||
|     } | ||||
| } | ||||
| #include "commandparser.h" | ||||
| 
 | ||||
| Command::Command(const String & command) | ||||
| { | ||||
|     ParseState state = Default; | ||||
|     int len = (int)command.length(); | ||||
|     for(int i = 0; i < len; i++) | ||||
|     { | ||||
|         char ch = command[i]; | ||||
|         switch(state) | ||||
|         { | ||||
|         case Default: | ||||
|             switch(ch) | ||||
|             { | ||||
|             case ' ': | ||||
|                 if(!_tokens.size()) | ||||
|                     dataFinish(); | ||||
|                 break; | ||||
|             case ',': | ||||
|                 dataFinish(); | ||||
|                 break; | ||||
|             case '\\': | ||||
|                 state = Escaped; | ||||
|                 break; | ||||
|             case '\"': | ||||
|                 state = Text; | ||||
|                 break; | ||||
|             default: | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             } | ||||
|             break; | ||||
|         case Escaped: | ||||
|             switch(ch) | ||||
|             { | ||||
|             case ' ': | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             case ',': | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             case '\"': | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             default: | ||||
|                 dataAppend('\\'); | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             } | ||||
|             state = Default; | ||||
|             break; | ||||
|         case Text: | ||||
|             switch(ch) | ||||
|             { | ||||
|             case '\\': | ||||
|                 state = TextEscaped; | ||||
|                 break; | ||||
|             case '\"': | ||||
|                 dataFinish(); | ||||
|                 state = Default; | ||||
|                 break; | ||||
|             default: | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             } | ||||
|             break; | ||||
|         case TextEscaped: | ||||
|             switch(ch) | ||||
|             { | ||||
|             case '\"': | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             default: | ||||
|                 dataAppend('\\'); | ||||
|                 dataAppend(ch); | ||||
|                 break; | ||||
|             } | ||||
|             state = Text; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if(state == Escaped || state == TextEscaped) | ||||
|         dataAppend('\\'); | ||||
|     dataFinish(); | ||||
| } | ||||
| 
 | ||||
| const String Command::GetText() | ||||
| { | ||||
|     return _tokens.size() ? _tokens[0] : String(); | ||||
| } | ||||
| 
 | ||||
| const int Command::GetArgCount() | ||||
| { | ||||
|     return _tokens.size() ? (int)_tokens.size() - 1 : 0; | ||||
| } | ||||
| 
 | ||||
| const String Command::GetArg(int argnum) | ||||
| { | ||||
|     return (int)_tokens.size() < argnum + 1 ? String() : _tokens[argnum + 1]; | ||||
| } | ||||
| 
 | ||||
| void Command::dataAppend(const char ch) | ||||
| { | ||||
|     _data += ch; | ||||
| } | ||||
| 
 | ||||
| void Command::dataFinish() | ||||
| { | ||||
|     if(_data.length()) | ||||
|     { | ||||
|         _tokens.push_back(_data); | ||||
|         _data.clear(); | ||||
|     } | ||||
| } | ||||
|  | @ -1,30 +1,30 @@ | |||
| #ifndef _COMMANDPARSER_H | ||||
| #define _COMMANDPARSER_H | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| class Command | ||||
| { | ||||
| public: | ||||
|     Command(const String & command); | ||||
|     const String GetText(); | ||||
|     const String GetArg(const int argnum); | ||||
|     const int GetArgCount(); | ||||
| 
 | ||||
| private: | ||||
|     String _data; | ||||
|     std::vector<String> _tokens; | ||||
| 
 | ||||
|     enum ParseState | ||||
|     { | ||||
|         Default, | ||||
|         Escaped, | ||||
|         Text, | ||||
|         TextEscaped | ||||
|     }; | ||||
| 
 | ||||
|     void dataFinish(); | ||||
|     void dataAppend(const char ch); | ||||
| }; | ||||
| 
 | ||||
| #endif // _COMMANDPARSER_H
 | ||||
| #ifndef _COMMANDPARSER_H | ||||
| #define _COMMANDPARSER_H | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| class Command | ||||
| { | ||||
| public: | ||||
|     Command(const String & command); | ||||
|     const String GetText(); | ||||
|     const String GetArg(const int argnum); | ||||
|     const int GetArgCount(); | ||||
| 
 | ||||
| private: | ||||
|     String _data; | ||||
|     std::vector<String> _tokens; | ||||
| 
 | ||||
|     enum ParseState | ||||
|     { | ||||
|         Default, | ||||
|         Escaped, | ||||
|         Text, | ||||
|         TextEscaped | ||||
|     }; | ||||
| 
 | ||||
|     void dataFinish(); | ||||
|     void dataAppend(const char ch); | ||||
| }; | ||||
| 
 | ||||
| #endif // _COMMANDPARSER_H
 | ||||
|  | @ -1,249 +1,249 @@ | |||
| #include "comment.h" | ||||
| #include "threading.h" | ||||
| #include "module.h" | ||||
| #include "memory.h" | ||||
| 
 | ||||
| std::unordered_map<uint, COMMENTSINFO> comments; | ||||
| 
 | ||||
| bool CommentSet(uint Address, const char* Text, bool Manual) | ||||
| { | ||||
|     // CHECK: Exported/Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // A valid memory address must be supplied
 | ||||
|     if(!MemIsValidReadPtr(Address)) | ||||
|         return false; | ||||
| 
 | ||||
|     // Make sure the string is supplied, within bounds, and not a special delimiter
 | ||||
|     if(!Text || Text[0] == '\1' || strlen(Text) >= MAX_COMMENT_SIZE - 1) | ||||
|         return false; | ||||
| 
 | ||||
|     // Delete the comment if no text was supplied
 | ||||
|     if(Text[0] == '\0') | ||||
|         return CommentDelete(Address); | ||||
| 
 | ||||
|     // Fill out the structure
 | ||||
|     COMMENTSINFO comment; | ||||
|     strcpy_s(comment.text, Text); | ||||
|     ModNameFromAddr(Address, comment.mod, true); | ||||
| 
 | ||||
|     comment.manual = Manual; | ||||
|     comment.addr = Address - ModBaseFromAddr(Address); | ||||
| 
 | ||||
|     // Key generated from module hash
 | ||||
|     const uint key = ModHashFromAddr(Address); | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     // Insert if possible, otherwise replace
 | ||||
|     if(!comments.insert(std::make_pair(key, comment)).second) | ||||
|         comments[key] = comment; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CommentGet(uint Address, char* Text) | ||||
| { | ||||
|     // CHECK: Exported/Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     // Get an existing comment and copy the string buffer
 | ||||
|     auto found = comments.find(ModHashFromAddr(Address)); | ||||
| 
 | ||||
|     // Was it found?
 | ||||
|     if(found == comments.end()) | ||||
|         return false; | ||||
| 
 | ||||
|     if(found->second.manual)  //autocomment
 | ||||
|         strcpy_s(Text, MAX_COMMENT_SIZE, found->second.text); | ||||
|     else | ||||
|         sprintf_s(Text, MAX_COMMENT_SIZE, "\1%s", found->second.text); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CommentDelete(uint Address) | ||||
| { | ||||
|     // CHECK: Command/Sub function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
|     return (comments.erase(ModHashFromAddr(Address)) > 0); | ||||
| } | ||||
| 
 | ||||
| void CommentDelRange(uint Start, uint End) | ||||
| { | ||||
|     // CHECK: Export function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return; | ||||
| 
 | ||||
|     // Are all comments going to be deleted?
 | ||||
|     // 0x00000000 - 0xFFFFFFFF
 | ||||
|     if(Start == 0 && End == ~0) | ||||
|     { | ||||
|         CommentClear(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Make sure 'Start' and 'End' reference the same module
 | ||||
|         uint moduleBase = ModBaseFromAddr(Start); | ||||
| 
 | ||||
|         if(moduleBase != ModBaseFromAddr(End)) | ||||
|             return; | ||||
| 
 | ||||
|         // Virtual -> relative offset
 | ||||
|         Start -= moduleBase; | ||||
|         End -= moduleBase; | ||||
| 
 | ||||
|         EXCLUSIVE_ACQUIRE(LockComments); | ||||
|         for(auto itr = comments.begin(); itr != comments.end();) | ||||
|         { | ||||
|             const auto & currentComment = itr->second; | ||||
|             // Ignore manually set entries
 | ||||
|             if(currentComment.manual) | ||||
|             { | ||||
|                 ++itr; | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             // [Start, End)
 | ||||
|             if(currentComment.addr >= Start && currentComment.addr < End) | ||||
|                 itr = comments.erase(itr); | ||||
|             else | ||||
|                 ++itr; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CommentCacheSave(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     const JSON jsonComments = json_array(); | ||||
|     const JSON jsonAutoComments = json_array(); | ||||
| 
 | ||||
|     // Build the JSON array
 | ||||
|     for(auto & itr : comments) | ||||
|     { | ||||
|         JSON currentComment = json_object(); | ||||
| 
 | ||||
|         json_object_set_new(currentComment, "module", json_string(itr.second.mod)); | ||||
|         json_object_set_new(currentComment, "address", json_hex(itr.second.addr)); | ||||
|         json_object_set_new(currentComment, "text", json_string(itr.second.text)); | ||||
| 
 | ||||
|         if(itr.second.manual) | ||||
|             json_array_append_new(jsonComments, currentComment); | ||||
|         else | ||||
|             json_array_append_new(jsonAutoComments, currentComment); | ||||
|     } | ||||
| 
 | ||||
|     // Save to the JSON root
 | ||||
|     if(json_array_size(jsonComments)) | ||||
|         json_object_set(Root, "comments", jsonComments); | ||||
| 
 | ||||
|     if(json_array_size(jsonAutoComments)) | ||||
|         json_object_set(Root, "autocomments", jsonAutoComments); | ||||
| 
 | ||||
|     json_decref(jsonComments); | ||||
|     json_decref(jsonAutoComments); | ||||
| } | ||||
| 
 | ||||
| void CommentCacheLoad(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     // Inline lambda to parse each JSON entry
 | ||||
|     auto AddComments = [](const JSON Object, bool Manual) | ||||
|     { | ||||
|         size_t i; | ||||
|         JSON value; | ||||
| 
 | ||||
|         json_array_foreach(Object, i, value) | ||||
|         { | ||||
|             COMMENTSINFO commentInfo; | ||||
|             memset(&commentInfo, 0, sizeof(COMMENTSINFO)); | ||||
| 
 | ||||
|             // Module
 | ||||
|             const char* mod = json_string_value(json_object_get(value, "module")); | ||||
| 
 | ||||
|             if(mod && strlen(mod) < MAX_MODULE_SIZE) | ||||
|                 strcpy_s(commentInfo.mod, mod); | ||||
| 
 | ||||
|             // Address/Manual
 | ||||
|             commentInfo.addr = (uint)json_hex_value(json_object_get(value, "address")); | ||||
|             commentInfo.manual = Manual; | ||||
| 
 | ||||
|             // String value
 | ||||
|             const char* text = json_string_value(json_object_get(value, "text")); | ||||
| 
 | ||||
|             if(text) | ||||
|                 strcpy_s(commentInfo.text, text); | ||||
|             else | ||||
|             { | ||||
|                 // Skip blank comments
 | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const uint key = ModHashFromName(commentInfo.mod) + commentInfo.addr; | ||||
|             comments.insert(std::make_pair(key, commentInfo)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // Remove existing entries
 | ||||
|     comments.clear(); | ||||
| 
 | ||||
|     const JSON jsonComments = json_object_get(Root, "comments"); | ||||
|     const JSON jsonAutoComments = json_object_get(Root, "autocomments"); | ||||
| 
 | ||||
|     // Load user-set comments
 | ||||
|     if(jsonComments) | ||||
|         AddComments(jsonComments, true); | ||||
| 
 | ||||
|     // Load auto-set comments
 | ||||
|     if(jsonAutoComments) | ||||
|         AddComments(jsonAutoComments, false); | ||||
| } | ||||
| 
 | ||||
| bool CommentEnum(COMMENTSINFO* List, size_t* Size) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // At least 1 parameter must be supplied
 | ||||
|     if(!List && !Size) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     // Check if the user requested size only
 | ||||
|     if(Size) | ||||
|     { | ||||
|         *Size = comments.size() * sizeof(COMMENTSINFO); | ||||
| 
 | ||||
|         if(!List) | ||||
|             return true; | ||||
|     } | ||||
| 
 | ||||
|     // Populate the returned array
 | ||||
|     for(auto & itr : comments) | ||||
|     { | ||||
|         *List = itr.second; | ||||
|         List->addr += ModBaseFromName(List->mod); | ||||
| 
 | ||||
|         List++; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void CommentClear() | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
|     comments.clear(); | ||||
| #include "comment.h" | ||||
| #include "threading.h" | ||||
| #include "module.h" | ||||
| #include "memory.h" | ||||
| 
 | ||||
| std::unordered_map<uint, COMMENTSINFO> comments; | ||||
| 
 | ||||
| bool CommentSet(uint Address, const char* Text, bool Manual) | ||||
| { | ||||
|     // CHECK: Exported/Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // A valid memory address must be supplied
 | ||||
|     if(!MemIsValidReadPtr(Address)) | ||||
|         return false; | ||||
| 
 | ||||
|     // Make sure the string is supplied, within bounds, and not a special delimiter
 | ||||
|     if(!Text || Text[0] == '\1' || strlen(Text) >= MAX_COMMENT_SIZE - 1) | ||||
|         return false; | ||||
| 
 | ||||
|     // Delete the comment if no text was supplied
 | ||||
|     if(Text[0] == '\0') | ||||
|         return CommentDelete(Address); | ||||
| 
 | ||||
|     // Fill out the structure
 | ||||
|     COMMENTSINFO comment; | ||||
|     strcpy_s(comment.text, Text); | ||||
|     ModNameFromAddr(Address, comment.mod, true); | ||||
| 
 | ||||
|     comment.manual = Manual; | ||||
|     comment.addr = Address - ModBaseFromAddr(Address); | ||||
| 
 | ||||
|     // Key generated from module hash
 | ||||
|     const uint key = ModHashFromAddr(Address); | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     // Insert if possible, otherwise replace
 | ||||
|     if(!comments.insert(std::make_pair(key, comment)).second) | ||||
|         comments[key] = comment; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CommentGet(uint Address, char* Text) | ||||
| { | ||||
|     // CHECK: Exported/Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     // Get an existing comment and copy the string buffer
 | ||||
|     auto found = comments.find(ModHashFromAddr(Address)); | ||||
| 
 | ||||
|     // Was it found?
 | ||||
|     if(found == comments.end()) | ||||
|         return false; | ||||
| 
 | ||||
|     if(found->second.manual)  //autocomment
 | ||||
|         strcpy_s(Text, MAX_COMMENT_SIZE, found->second.text); | ||||
|     else | ||||
|         sprintf_s(Text, MAX_COMMENT_SIZE, "\1%s", found->second.text); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CommentDelete(uint Address) | ||||
| { | ||||
|     // CHECK: Command/Sub function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
|     return (comments.erase(ModHashFromAddr(Address)) > 0); | ||||
| } | ||||
| 
 | ||||
| void CommentDelRange(uint Start, uint End) | ||||
| { | ||||
|     // CHECK: Export function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return; | ||||
| 
 | ||||
|     // Are all comments going to be deleted?
 | ||||
|     // 0x00000000 - 0xFFFFFFFF
 | ||||
|     if(Start == 0 && End == ~0) | ||||
|     { | ||||
|         CommentClear(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Make sure 'Start' and 'End' reference the same module
 | ||||
|         uint moduleBase = ModBaseFromAddr(Start); | ||||
| 
 | ||||
|         if(moduleBase != ModBaseFromAddr(End)) | ||||
|             return; | ||||
| 
 | ||||
|         // Virtual -> relative offset
 | ||||
|         Start -= moduleBase; | ||||
|         End -= moduleBase; | ||||
| 
 | ||||
|         EXCLUSIVE_ACQUIRE(LockComments); | ||||
|         for(auto itr = comments.begin(); itr != comments.end();) | ||||
|         { | ||||
|             const auto & currentComment = itr->second; | ||||
|             // Ignore manually set entries
 | ||||
|             if(currentComment.manual) | ||||
|             { | ||||
|                 ++itr; | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             // [Start, End)
 | ||||
|             if(currentComment.addr >= Start && currentComment.addr < End) | ||||
|                 itr = comments.erase(itr); | ||||
|             else | ||||
|                 ++itr; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CommentCacheSave(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     const JSON jsonComments = json_array(); | ||||
|     const JSON jsonAutoComments = json_array(); | ||||
| 
 | ||||
|     // Build the JSON array
 | ||||
|     for(auto & itr : comments) | ||||
|     { | ||||
|         JSON currentComment = json_object(); | ||||
| 
 | ||||
|         json_object_set_new(currentComment, "module", json_string(itr.second.mod)); | ||||
|         json_object_set_new(currentComment, "address", json_hex(itr.second.addr)); | ||||
|         json_object_set_new(currentComment, "text", json_string(itr.second.text)); | ||||
| 
 | ||||
|         if(itr.second.manual) | ||||
|             json_array_append_new(jsonComments, currentComment); | ||||
|         else | ||||
|             json_array_append_new(jsonAutoComments, currentComment); | ||||
|     } | ||||
| 
 | ||||
|     // Save to the JSON root
 | ||||
|     if(json_array_size(jsonComments)) | ||||
|         json_object_set(Root, "comments", jsonComments); | ||||
| 
 | ||||
|     if(json_array_size(jsonAutoComments)) | ||||
|         json_object_set(Root, "autocomments", jsonAutoComments); | ||||
| 
 | ||||
|     json_decref(jsonComments); | ||||
|     json_decref(jsonAutoComments); | ||||
| } | ||||
| 
 | ||||
| void CommentCacheLoad(JSON Root) | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     // Inline lambda to parse each JSON entry
 | ||||
|     auto AddComments = [](const JSON Object, bool Manual) | ||||
|     { | ||||
|         size_t i; | ||||
|         JSON value; | ||||
| 
 | ||||
|         json_array_foreach(Object, i, value) | ||||
|         { | ||||
|             COMMENTSINFO commentInfo; | ||||
|             memset(&commentInfo, 0, sizeof(COMMENTSINFO)); | ||||
| 
 | ||||
|             // Module
 | ||||
|             const char* mod = json_string_value(json_object_get(value, "module")); | ||||
| 
 | ||||
|             if(mod && strlen(mod) < MAX_MODULE_SIZE) | ||||
|                 strcpy_s(commentInfo.mod, mod); | ||||
| 
 | ||||
|             // Address/Manual
 | ||||
|             commentInfo.addr = (uint)json_hex_value(json_object_get(value, "address")); | ||||
|             commentInfo.manual = Manual; | ||||
| 
 | ||||
|             // String value
 | ||||
|             const char* text = json_string_value(json_object_get(value, "text")); | ||||
| 
 | ||||
|             if(text) | ||||
|                 strcpy_s(commentInfo.text, text); | ||||
|             else | ||||
|             { | ||||
|                 // Skip blank comments
 | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const uint key = ModHashFromName(commentInfo.mod) + commentInfo.addr; | ||||
|             comments.insert(std::make_pair(key, commentInfo)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // Remove existing entries
 | ||||
|     comments.clear(); | ||||
| 
 | ||||
|     const JSON jsonComments = json_object_get(Root, "comments"); | ||||
|     const JSON jsonAutoComments = json_object_get(Root, "autocomments"); | ||||
| 
 | ||||
|     // Load user-set comments
 | ||||
|     if(jsonComments) | ||||
|         AddComments(jsonComments, true); | ||||
| 
 | ||||
|     // Load auto-set comments
 | ||||
|     if(jsonAutoComments) | ||||
|         AddComments(jsonAutoComments, false); | ||||
| } | ||||
| 
 | ||||
| bool CommentEnum(COMMENTSINFO* List, size_t* Size) | ||||
| { | ||||
|     // CHECK: Command function
 | ||||
|     if(!DbgIsDebugging()) | ||||
|         return false; | ||||
| 
 | ||||
|     // At least 1 parameter must be supplied
 | ||||
|     if(!List && !Size) | ||||
|         return false; | ||||
| 
 | ||||
|     SHARED_ACQUIRE(LockComments); | ||||
| 
 | ||||
|     // Check if the user requested size only
 | ||||
|     if(Size) | ||||
|     { | ||||
|         *Size = comments.size() * sizeof(COMMENTSINFO); | ||||
| 
 | ||||
|         if(!List) | ||||
|             return true; | ||||
|     } | ||||
| 
 | ||||
|     // Populate the returned array
 | ||||
|     for(auto & itr : comments) | ||||
|     { | ||||
|         *List = itr.second; | ||||
|         List->addr += ModBaseFromName(List->mod); | ||||
| 
 | ||||
|         List++; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void CommentClear() | ||||
| { | ||||
|     EXCLUSIVE_ACQUIRE(LockComments); | ||||
|     comments.clear(); | ||||
| } | ||||
|  | @ -1,20 +1,20 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| struct COMMENTSINFO | ||||
| { | ||||
|     char mod[MAX_MODULE_SIZE]; | ||||
|     uint addr; | ||||
|     char text[MAX_COMMENT_SIZE]; | ||||
|     bool manual; | ||||
| }; | ||||
| 
 | ||||
| bool CommentSet(uint Address, const char* Text, bool Manual); | ||||
| bool CommentGet(uint Address, char* Text); | ||||
| bool CommentDelete(uint Address); | ||||
| void CommentDelRange(uint Start, uint End); | ||||
| void CommentCacheSave(JSON Root); | ||||
| void CommentCacheLoad(JSON Root); | ||||
| bool CommentEnum(COMMENTSINFO* List, size_t* Size); | ||||
| #pragma once | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| struct COMMENTSINFO | ||||
| { | ||||
|     char mod[MAX_MODULE_SIZE]; | ||||
|     uint addr; | ||||
|     char text[MAX_COMMENT_SIZE]; | ||||
|     bool manual; | ||||
| }; | ||||
| 
 | ||||
| bool CommentSet(uint Address, const char* Text, bool Manual); | ||||
| bool CommentGet(uint Address, char* Text); | ||||
| bool CommentDelete(uint Address); | ||||
| void CommentDelRange(uint Start, uint End); | ||||
| void CommentCacheSave(JSON Root); | ||||
| void CommentCacheLoad(JSON Root); | ||||
| bool CommentEnum(COMMENTSINFO* List, size_t* Size); | ||||
| void CommentClear(); | ||||
|  | @ -1,41 +1,41 @@ | |||
| /**
 | ||||
| \file console.cpp | ||||
| \brief Implements the console class. | ||||
| */ | ||||
| 
 | ||||
| #include "console.h" | ||||
| 
 | ||||
| /**
 | ||||
| \brief Print a line with text, terminated with a newline to the console. | ||||
| \param text The text to print. | ||||
| */ | ||||
| void dputs(const char* Text) | ||||
| { | ||||
|     dprintf("%s\n", Text); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Print a formatted string to the console. | ||||
| \param format The printf format to use (see documentation of printf for more information). | ||||
| */ | ||||
| void dprintf(const char* Format, ...) | ||||
| { | ||||
|     va_list args; | ||||
| 
 | ||||
|     va_start(args, Format); | ||||
|     dprintf_args(Format, args); | ||||
|     va_end(args); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Print a formatted string to the console. | ||||
| \param format The printf format to use (see documentation of printf for more information). | ||||
| \param Args The argument buffer passed to the string parser. | ||||
| */ | ||||
| void dprintf_args(const char* Format, va_list Args) | ||||
| { | ||||
|     char buffer[16384]; | ||||
|     vsnprintf_s(buffer, _TRUNCATE, Format, Args); | ||||
| 
 | ||||
|     GuiAddLogMessage(buffer); | ||||
| } | ||||
| /**
 | ||||
| \file console.cpp | ||||
| \brief Implements the console class. | ||||
| */ | ||||
| 
 | ||||
| #include "console.h" | ||||
| 
 | ||||
| /**
 | ||||
| \brief Print a line with text, terminated with a newline to the console. | ||||
| \param text The text to print. | ||||
| */ | ||||
| void dputs(const char* Text) | ||||
| { | ||||
|     dprintf("%s\n", Text); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Print a formatted string to the console. | ||||
| \param format The printf format to use (see documentation of printf for more information). | ||||
| */ | ||||
| void dprintf(const char* Format, ...) | ||||
| { | ||||
|     va_list args; | ||||
| 
 | ||||
|     va_start(args, Format); | ||||
|     dprintf_args(Format, args); | ||||
|     va_end(args); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| \brief Print a formatted string to the console. | ||||
| \param format The printf format to use (see documentation of printf for more information). | ||||
| \param Args The argument buffer passed to the string parser. | ||||
| */ | ||||
| void dprintf_args(const char* Format, va_list Args) | ||||
| { | ||||
|     char buffer[16384]; | ||||
|     vsnprintf_s(buffer, _TRUNCATE, Format, Args); | ||||
| 
 | ||||
|     GuiAddLogMessage(buffer); | ||||
| } | ||||
|  | @ -1,7 +1,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| void dputs(const char* Text); | ||||
| void dprintf(const char* Format, ...); | ||||
| #pragma once | ||||
| 
 | ||||
| #include "_global.h" | ||||
| 
 | ||||
| void dputs(const char* Text); | ||||
| void dprintf(const char* Format, ...); | ||||
| void dprintf_args(const char* Format, va_list Args); | ||||
|  | @ -1,445 +1,445 @@ | |||
| #include "controlflowanalysis.h" | ||||
| #include "console.h" | ||||
| #include "module.h" | ||||
| #include "TitanEngine/TitanEngine.h" | ||||
| #include "memory.h" | ||||
| #include "function.h" | ||||
| 
 | ||||
| ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size, bool exceptionDirectory) : Analysis(base, size) | ||||
| { | ||||
|     _functionInfoData = nullptr; | ||||
| #ifdef _WIN64 | ||||
|     // This will only be valid if the address range is within a loaded module
 | ||||
|     _moduleBase = ModBaseFromAddr(base); | ||||
| 
 | ||||
|     if(exceptionDirectory && _moduleBase != 0) | ||||
|     { | ||||
|         char modulePath[MAX_PATH]; | ||||
|         memset(modulePath, 0, sizeof(modulePath)); | ||||
| 
 | ||||
|         ModPathFromAddr(_moduleBase, modulePath, ARRAYSIZE(modulePath)); | ||||
| 
 | ||||
|         HANDLE fileHandle; | ||||
|         DWORD fileSize; | ||||
|         HANDLE fileMapHandle; | ||||
|         ULONG_PTR fileMapVa; | ||||
|         if(StaticFileLoadW( | ||||
|                     StringUtils::Utf8ToUtf16(modulePath).c_str(), | ||||
|                     UE_ACCESS_READ, | ||||
|                     false, | ||||
|                     &fileHandle, | ||||
|                     &fileSize, | ||||
|                     &fileMapHandle, | ||||
|                     &fileMapVa)) | ||||
|         { | ||||
|             // Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use
 | ||||
|             ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET); | ||||
|             _functionInfoSize = (uint)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE); | ||||
| 
 | ||||
|             // Unload the file
 | ||||
|             StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa); | ||||
| 
 | ||||
|             // Get a copy of the function table
 | ||||
|             if(virtualOffset) | ||||
|             { | ||||
|                 // Read the table into a buffer
 | ||||
|                 _functionInfoData = emalloc(_functionInfoSize); | ||||
| 
 | ||||
|                 if(_functionInfoData) | ||||
|                     MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| #endif //_WIN64
 | ||||
| } | ||||
| 
 | ||||
| ControlFlowAnalysis::~ControlFlowAnalysis() | ||||
| { | ||||
|     if(_functionInfoData) | ||||
|         efree(_functionInfoData); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::Analyse() | ||||
| { | ||||
|     dputs("Starting analysis..."); | ||||
|     DWORD ticks = GetTickCount(); | ||||
| 
 | ||||
|     BasicBlockStarts(); | ||||
|     dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks); | ||||
|     ticks = GetTickCount(); | ||||
| 
 | ||||
|     BasicBlocks(); | ||||
|     dprintf("Basic blocks in %ums!\n", GetTickCount() - ticks); | ||||
|     ticks = GetTickCount(); | ||||
| 
 | ||||
|     Functions(); | ||||
|     dprintf("Functions in %ums!\n", GetTickCount() - ticks); | ||||
|     ticks = GetTickCount(); | ||||
| 
 | ||||
|     FunctionRanges(); | ||||
|     dprintf("Function ranges in %ums!\n", GetTickCount() - ticks); | ||||
|     ticks = GetTickCount(); | ||||
| 
 | ||||
|     dprintf("Analysis finished!\n"); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::SetMarkers() | ||||
| { | ||||
|     FunctionDelRange(_base, _base + _size); | ||||
|     auto size = _functionRanges.size(); | ||||
|     for(size_t i = size - 1; i != -1; i--) | ||||
|     { | ||||
|         const auto & range = _functionRanges[i]; | ||||
|         FunctionAdd(range.first, range.second, false); | ||||
|     } | ||||
|     /*dprintf("digraph ControlFlow {\n");
 | ||||
|     int i = 0; | ||||
|     std::map<uint, int> nodeMap; | ||||
|     for(const auto & it : _blocks) | ||||
|     { | ||||
|         const auto & block = it.second; | ||||
|         nodeMap.insert({ block.start, i }); | ||||
|         dprintf("    node%u [label=\"s=%p, e=%p, f=%p\"];\n", i, block.start, block.end, block.function); | ||||
|         i++; | ||||
|     } | ||||
|     for(auto it : _blocks) | ||||
|     { | ||||
|         const auto & block = it.second; | ||||
|         int startNode = nodeMap[block.start]; | ||||
|         if(block.left) | ||||
|         { | ||||
|             if(nodeMap.count(block.left)) | ||||
|                 dprintf("    node%u -> node%u;\n", startNode, nodeMap[block.left]); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             dprintf("    node%u [shape=point];\n", i); | ||||
|             dprintf("    node%u -> node%u;\n", startNode, i); | ||||
|             i++; | ||||
|         } | ||||
|         if(block.right) | ||||
|         { | ||||
|             if(nodeMap.count(block.right)) | ||||
|                 dprintf("    node%u -> node%u;\n", startNode, nodeMap[block.right]); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             dprintf("    node%u [shape=point];\n", i); | ||||
|             dprintf("    node%u -> node%u;\n", startNode, i); | ||||
|             i++; | ||||
|         } | ||||
|     } | ||||
|     dprintf("}\n");*/ | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::BasicBlockStarts() | ||||
| { | ||||
|     _blockStarts.insert(_base); | ||||
|     bool bSkipFilling = false; | ||||
|     for(uint i = 0; i < _size;) | ||||
|     { | ||||
|         uint addr = _base + i; | ||||
|         if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER)) | ||||
|         { | ||||
|             if(bSkipFilling) //handle filling skip mode
 | ||||
|             { | ||||
|                 if(!_cp.IsFilling()) //do nothing until the filling stopped
 | ||||
|                 { | ||||
|                     bSkipFilling = false; | ||||
|                     _blockStarts.insert(addr); | ||||
|                 } | ||||
|             } | ||||
|             else if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) //RET/INT3 break control flow
 | ||||
|             { | ||||
|                 bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
 | ||||
|             } | ||||
|             else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())   //branches
 | ||||
|             { | ||||
|                 uint dest1 = GetReferenceOperand(); | ||||
|                 uint dest2 = 0; | ||||
|                 if(_cp.GetId() != X86_INS_JMP)    //unconditional jump
 | ||||
|                     dest2 = addr + _cp.Size(); | ||||
| 
 | ||||
|                 if(!dest1 && !dest2)  //TODO: better code for this (make sure absolutely no filling is inserted)
 | ||||
|                     bSkipFilling = true; | ||||
|                 if(dest1) | ||||
|                     _blockStarts.insert(dest1); | ||||
|                 if(dest2) | ||||
|                     _blockStarts.insert(dest2); | ||||
|             } | ||||
|             else if(_cp.InGroup(CS_GRP_CALL)) | ||||
|             { | ||||
|                 uint dest1 = GetReferenceOperand(); | ||||
|                 if(dest1) | ||||
|                 { | ||||
|                     _blockStarts.insert(dest1); | ||||
|                     _functionStarts.insert(dest1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 uint dest1 = GetReferenceOperand(); | ||||
|                 if(dest1) | ||||
|                     _blockStarts.insert(dest1); | ||||
|             } | ||||
|             i += _cp.Size(); | ||||
|         } | ||||
|         else | ||||
|             i++; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::BasicBlocks() | ||||
| { | ||||
|     for(auto i = _blockStarts.begin(); i != _blockStarts.end(); ++i) | ||||
|     { | ||||
|         uint start = *i; | ||||
|         if(!IsValidAddress(start)) | ||||
|             continue; | ||||
|         uint nextStart = _base + _size; | ||||
|         auto next = std::next(i); | ||||
|         if(next != _blockStarts.end()) | ||||
|             nextStart = *next; | ||||
|         for(uint addr = start, prevaddr = 0; addr < _base + _size;) | ||||
|         { | ||||
|             prevaddr = addr; | ||||
|             if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER)) | ||||
|             { | ||||
|                 if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) | ||||
|                 { | ||||
|                     insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block
 | ||||
|                     break; | ||||
|                 } | ||||
|                 else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) | ||||
|                 { | ||||
|                     uint dest1 = GetReferenceOperand(); | ||||
|                     uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0; | ||||
|                     insertBlock(BasicBlock(start, addr, dest1, dest2)); | ||||
|                     insertParent(dest1, start); | ||||
|                     insertParent(dest2, start); | ||||
|                     break; | ||||
|                 } | ||||
|                 addr += _cp.Size(); | ||||
|             } | ||||
|             else | ||||
|                 addr++; | ||||
|             if(addr == nextStart)   //special case handling overlapping blocks
 | ||||
|             { | ||||
|                 insertBlock(BasicBlock(start, prevaddr, 0, nextStart)); | ||||
|                 insertParent(nextStart, start); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     _blockStarts.clear(); | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
|     int count = 0; | ||||
|     EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function) | ||||
|     { | ||||
|         const uint funcAddr = _moduleBase + Function->BeginAddress; | ||||
|         const uint funcEnd = _moduleBase + Function->EndAddress; | ||||
| 
 | ||||
|         // If within limits...
 | ||||
|         if(funcAddr >= _base && funcAddr < _base + _size) | ||||
|             _functionStarts.insert(funcAddr); | ||||
|         count++; | ||||
|         return true; | ||||
|     }); | ||||
|     dprintf("%u functions from the exception directory...\n", count); | ||||
| #endif // _WIN64
 | ||||
| 
 | ||||
|     dprintf("%u basic blocks, %u function starts detected...\n", _blocks.size(), _functionStarts.size()); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::Functions() | ||||
| { | ||||
|     typedef std::pair<BasicBlock*, UintSet*> DelayedBlock; | ||||
|     std::vector<DelayedBlock> delayedBlocks; | ||||
|     for(auto & it : _blocks) | ||||
|     { | ||||
|         BasicBlock* block = &it.second; | ||||
|         UintSet* parents = findParents(block->start); | ||||
|         if(!block->function) | ||||
|         { | ||||
|             if(!parents || _functionStarts.count(block->start))  //no parents = function start
 | ||||
|             { | ||||
|                 uint functionStart = block->start; | ||||
|                 block->function = functionStart; | ||||
|                 UintSet functionBlocks; | ||||
|                 functionBlocks.insert(functionStart); | ||||
|                 _functions[functionStart] = functionBlocks; | ||||
|             } | ||||
|             else //in function
 | ||||
|             { | ||||
|                 uint function = findFunctionStart(block, parents); | ||||
|                 if(!function)  //this happens with loops / unreferenced blocks sometimes
 | ||||
|                     delayedBlocks.push_back(DelayedBlock(block, parents)); | ||||
|                 else | ||||
|                     block->function = function; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|             DebugBreak(); //this should not happen
 | ||||
|     } | ||||
|     int delayedCount = (int)delayedBlocks.size(); | ||||
|     dprintf("%u/%u delayed blocks...\n", delayedCount, _blocks.size()); | ||||
|     int resolved = 0; | ||||
|     for(auto & delayedBlock : delayedBlocks) | ||||
|     { | ||||
|         BasicBlock* block = delayedBlock.first; | ||||
|         UintSet* parents = delayedBlock.second; | ||||
|         uint function = findFunctionStart(block, parents); | ||||
|         if(!function) | ||||
|         { | ||||
|             continue; | ||||
|             /*dprintf("unresolved block %s\n", blockToString(block).c_str());
 | ||||
|             if(parents) | ||||
|             { | ||||
|                 dprintf("parents:\n"); | ||||
|                 for(auto parent : *parents) | ||||
|                     dprintf("  %s\n", blockToString(findBlock(parent)).c_str()); | ||||
|             } | ||||
|             else | ||||
|                 dprintf("parents: null"); | ||||
|             dprintf("left: %s\n", blockToString(findBlock(block->left)).c_str()); | ||||
|             dprintf("right: %s\n", blockToString(findBlock(block->right)).c_str()); | ||||
|             return;*/ | ||||
|         } | ||||
|         block->function = function; | ||||
|         resolved++; | ||||
|     } | ||||
|     dprintf("%u/%u delayed blocks resolved (%u/%u still left, probably unreferenced functions)\n", resolved, delayedCount, delayedCount - resolved, _blocks.size()); | ||||
|     int unreferencedCount = 0; | ||||
|     for(const auto & block : _blocks) | ||||
|     { | ||||
|         auto found = _functions.find(block.second.function); | ||||
|         if(found == _functions.end())  //unreferenced block
 | ||||
|         { | ||||
|             unreferencedCount++; | ||||
|             continue; | ||||
|         } | ||||
|         found->second.insert(block.second.start); | ||||
|     } | ||||
|     dprintf("%u/%u unreferenced blocks\n", unreferencedCount, _blocks.size()); | ||||
|     dprintf("%u functions found!\n", _functions.size()); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::FunctionRanges() | ||||
| { | ||||
|     //iterate over the functions and then find the deepest block = function end
 | ||||
|     for(const auto & function : _functions) | ||||
|     { | ||||
|         uint start = function.first; | ||||
|         uint end = start; | ||||
|         for(auto blockstart : function.second) | ||||
|         { | ||||
|             BasicBlock* block = this->findBlock(blockstart); | ||||
|             if(!block) | ||||
|                 DebugBreak(); //this shouldn't happen
 | ||||
|             if(block->end > end) | ||||
|                 end = block->end; | ||||
|         } | ||||
|         _functionRanges.push_back({ start, end }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::insertBlock(BasicBlock block) | ||||
| { | ||||
|     if(_blocks.find(block.start) != _blocks.end()) | ||||
|         DebugBreak(); | ||||
|     _blocks[block.start] = block; | ||||
| } | ||||
| 
 | ||||
| ControlFlowAnalysis::BasicBlock* ControlFlowAnalysis::findBlock(uint start) | ||||
| { | ||||
|     if(!start) | ||||
|         return nullptr; | ||||
|     auto found = _blocks.find(start); | ||||
|     return found != _blocks.end() ? &found->second : nullptr; | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::insertParent(uint child, uint parent) | ||||
| { | ||||
|     if(!child || !parent) | ||||
|         return; | ||||
|     auto found = _parentMap.find(child); | ||||
|     if(found == _parentMap.end()) | ||||
|     { | ||||
|         UintSet parents; | ||||
|         parents.insert(parent); | ||||
|         _parentMap[child] = parents; | ||||
|     } | ||||
|     else | ||||
|         found->second.insert(parent); | ||||
| } | ||||
| 
 | ||||
| ControlFlowAnalysis::UintSet* ControlFlowAnalysis::findParents(uint child) | ||||
| { | ||||
|     if(!child) | ||||
|         return nullptr; | ||||
|     auto found = _parentMap.find(child); | ||||
|     return found != _parentMap.end() ? &found->second : nullptr; | ||||
| } | ||||
| 
 | ||||
| uint ControlFlowAnalysis::findFunctionStart(BasicBlock* block, ControlFlowAnalysis::UintSet* parents) | ||||
| { | ||||
|     if(!block) | ||||
|         return 0; | ||||
|     if(block->function) | ||||
|         return block->function; | ||||
|     BasicBlock* left = findBlock(block->left); | ||||
|     if(left && left->function) | ||||
|         return left->function; | ||||
|     BasicBlock* right = findBlock(block->right); | ||||
|     if(right && right->function) | ||||
|         return right->function; | ||||
|     for(auto start : *parents) | ||||
|     { | ||||
|         BasicBlock* parent = findBlock(start); | ||||
|         if(parent->function) | ||||
|             return parent->function; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| String ControlFlowAnalysis::blockToString(BasicBlock* block) | ||||
| { | ||||
|     if(!block) | ||||
|         return String("null"); | ||||
|     return block->toString(); | ||||
| } | ||||
| 
 | ||||
| uint ControlFlowAnalysis::GetReferenceOperand() | ||||
| { | ||||
|     for(int i = 0; i < _cp.x86().op_count; i++) | ||||
|     { | ||||
|         const cs_x86_op & operand = _cp.x86().operands[i]; | ||||
|         if(operand.type == X86_OP_IMM) | ||||
|         { | ||||
|             uint dest = (uint)operand.imm; | ||||
|             if(dest >= _base && dest < _base + _size) | ||||
|                 return dest; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| void ControlFlowAnalysis::EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback) | ||||
| { | ||||
|     if(!_functionInfoData) | ||||
|         return; | ||||
| 
 | ||||
|     // Get the table pointer and size
 | ||||
|     auto functionTable = (PRUNTIME_FUNCTION)_functionInfoData; | ||||
|     uint totalCount = (_functionInfoSize / sizeof(RUNTIME_FUNCTION)); | ||||
| 
 | ||||
|     // Enumerate each entry
 | ||||
|     for(ULONG i = 0; i < totalCount; i++) | ||||
|     { | ||||
|         if(!Callback(&functionTable[i])) | ||||
|             break; | ||||
|     } | ||||
| } | ||||
| #include "controlflowanalysis.h" | ||||
| #include "console.h" | ||||
| #include "module.h" | ||||
| #include "TitanEngine/TitanEngine.h" | ||||
| #include "memory.h" | ||||
| #include "function.h" | ||||
| 
 | ||||
| ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size, bool exceptionDirectory) : Analysis(base, size) | ||||
| { | ||||
|     _functionInfoData = nullptr; | ||||
| #ifdef _WIN64 | ||||
|     // This will only be valid if the address range is within a loaded module
 | ||||
|     _moduleBase = ModBaseFromAddr(base); | ||||
| 
 | ||||
|     if(exceptionDirectory && _moduleBase != 0) | ||||
|     { | ||||
|         char modulePath[MAX_PATH]; | ||||
|         memset(modulePath, 0, sizeof(modulePath)); | ||||
| 
 | ||||
|         ModPathFromAddr(_moduleBase, modulePath, ARRAYSIZE(modulePath)); | ||||
| 
 | ||||
|         HANDLE fileHandle; | ||||
|         DWORD fileSize; | ||||
|         HANDLE fileMapHandle; | ||||
|         ULONG_PTR fileMapVa; | ||||
|         if(StaticFileLoadW( | ||||
|                     StringUtils::Utf8ToUtf16(modulePath).c_str(), | ||||
|                     UE_ACCESS_READ, | ||||
|                     false, | ||||
|                     &fileHandle, | ||||
|                     &fileSize, | ||||
|                     &fileMapHandle, | ||||
|                     &fileMapVa)) | ||||
|         { | ||||
|             // Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use
 | ||||
|             ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET); | ||||
|             _functionInfoSize = (uint)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE); | ||||
| 
 | ||||
|             // Unload the file
 | ||||
|             StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa); | ||||
| 
 | ||||
|             // Get a copy of the function table
 | ||||
|             if(virtualOffset) | ||||
|             { | ||||
|                 // Read the table into a buffer
 | ||||
|                 _functionInfoData = emalloc(_functionInfoSize); | ||||
| 
 | ||||
|                 if(_functionInfoData) | ||||
|                     MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| #endif //_WIN64
 | ||||
| } | ||||
| 
 | ||||
| ControlFlowAnalysis::~ControlFlowAnalysis() | ||||
| { | ||||
|     if(_functionInfoData) | ||||
|         efree(_functionInfoData); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::Analyse() | ||||
| { | ||||
|     dputs("Starting analysis..."); | ||||
|     DWORD ticks = GetTickCount(); | ||||
| 
 | ||||
|     BasicBlockStarts(); | ||||
|     dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks); | ||||
|     ticks = GetTickCount(); | ||||
| 
 | ||||
|     BasicBlocks(); | ||||
|     dprintf("Basic blocks in %ums!\n", GetTickCount() - ticks); | ||||
|     ticks = GetTickCount(); | ||||
| 
 | ||||
|     Functions(); | ||||
|     dprintf("Functions in %ums!\n", GetTickCount() - ticks); | ||||
|     ticks = GetTickCount(); | ||||
| 
 | ||||
|     FunctionRanges(); | ||||
|     dprintf("Function ranges in %ums!\n", GetTickCount() - ticks); | ||||
|     ticks = GetTickCount(); | ||||
| 
 | ||||
|     dprintf("Analysis finished!\n"); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::SetMarkers() | ||||
| { | ||||
|     FunctionDelRange(_base, _base + _size); | ||||
|     auto size = _functionRanges.size(); | ||||
|     for(size_t i = size - 1; i != -1; i--) | ||||
|     { | ||||
|         const auto & range = _functionRanges[i]; | ||||
|         FunctionAdd(range.first, range.second, false); | ||||
|     } | ||||
|     /*dprintf("digraph ControlFlow {\n");
 | ||||
|     int i = 0; | ||||
|     std::map<uint, int> nodeMap; | ||||
|     for(const auto & it : _blocks) | ||||
|     { | ||||
|         const auto & block = it.second; | ||||
|         nodeMap.insert({ block.start, i }); | ||||
|         dprintf("    node%u [label=\"s=%p, e=%p, f=%p\"];\n", i, block.start, block.end, block.function); | ||||
|         i++; | ||||
|     } | ||||
|     for(auto it : _blocks) | ||||
|     { | ||||
|         const auto & block = it.second; | ||||
|         int startNode = nodeMap[block.start]; | ||||
|         if(block.left) | ||||
|         { | ||||
|             if(nodeMap.count(block.left)) | ||||
|                 dprintf("    node%u -> node%u;\n", startNode, nodeMap[block.left]); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             dprintf("    node%u [shape=point];\n", i); | ||||
|             dprintf("    node%u -> node%u;\n", startNode, i); | ||||
|             i++; | ||||
|         } | ||||
|         if(block.right) | ||||
|         { | ||||
|             if(nodeMap.count(block.right)) | ||||
|                 dprintf("    node%u -> node%u;\n", startNode, nodeMap[block.right]); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             dprintf("    node%u [shape=point];\n", i); | ||||
|             dprintf("    node%u -> node%u;\n", startNode, i); | ||||
|             i++; | ||||
|         } | ||||
|     } | ||||
|     dprintf("}\n");*/ | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::BasicBlockStarts() | ||||
| { | ||||
|     _blockStarts.insert(_base); | ||||
|     bool bSkipFilling = false; | ||||
|     for(uint i = 0; i < _size;) | ||||
|     { | ||||
|         uint addr = _base + i; | ||||
|         if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER)) | ||||
|         { | ||||
|             if(bSkipFilling) //handle filling skip mode
 | ||||
|             { | ||||
|                 if(!_cp.IsFilling()) //do nothing until the filling stopped
 | ||||
|                 { | ||||
|                     bSkipFilling = false; | ||||
|                     _blockStarts.insert(addr); | ||||
|                 } | ||||
|             } | ||||
|             else if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) //RET/INT3 break control flow
 | ||||
|             { | ||||
|                 bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
 | ||||
|             } | ||||
|             else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())   //branches
 | ||||
|             { | ||||
|                 uint dest1 = GetReferenceOperand(); | ||||
|                 uint dest2 = 0; | ||||
|                 if(_cp.GetId() != X86_INS_JMP)    //unconditional jump
 | ||||
|                     dest2 = addr + _cp.Size(); | ||||
| 
 | ||||
|                 if(!dest1 && !dest2)  //TODO: better code for this (make sure absolutely no filling is inserted)
 | ||||
|                     bSkipFilling = true; | ||||
|                 if(dest1) | ||||
|                     _blockStarts.insert(dest1); | ||||
|                 if(dest2) | ||||
|                     _blockStarts.insert(dest2); | ||||
|             } | ||||
|             else if(_cp.InGroup(CS_GRP_CALL)) | ||||
|             { | ||||
|                 uint dest1 = GetReferenceOperand(); | ||||
|                 if(dest1) | ||||
|                 { | ||||
|                     _blockStarts.insert(dest1); | ||||
|                     _functionStarts.insert(dest1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 uint dest1 = GetReferenceOperand(); | ||||
|                 if(dest1) | ||||
|                     _blockStarts.insert(dest1); | ||||
|             } | ||||
|             i += _cp.Size(); | ||||
|         } | ||||
|         else | ||||
|             i++; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::BasicBlocks() | ||||
| { | ||||
|     for(auto i = _blockStarts.begin(); i != _blockStarts.end(); ++i) | ||||
|     { | ||||
|         uint start = *i; | ||||
|         if(!IsValidAddress(start)) | ||||
|             continue; | ||||
|         uint nextStart = _base + _size; | ||||
|         auto next = std::next(i); | ||||
|         if(next != _blockStarts.end()) | ||||
|             nextStart = *next; | ||||
|         for(uint addr = start, prevaddr = 0; addr < _base + _size;) | ||||
|         { | ||||
|             prevaddr = addr; | ||||
|             if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER)) | ||||
|             { | ||||
|                 if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) | ||||
|                 { | ||||
|                     insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block
 | ||||
|                     break; | ||||
|                 } | ||||
|                 else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) | ||||
|                 { | ||||
|                     uint dest1 = GetReferenceOperand(); | ||||
|                     uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0; | ||||
|                     insertBlock(BasicBlock(start, addr, dest1, dest2)); | ||||
|                     insertParent(dest1, start); | ||||
|                     insertParent(dest2, start); | ||||
|                     break; | ||||
|                 } | ||||
|                 addr += _cp.Size(); | ||||
|             } | ||||
|             else | ||||
|                 addr++; | ||||
|             if(addr == nextStart)   //special case handling overlapping blocks
 | ||||
|             { | ||||
|                 insertBlock(BasicBlock(start, prevaddr, 0, nextStart)); | ||||
|                 insertParent(nextStart, start); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     _blockStarts.clear(); | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
|     int count = 0; | ||||
|     EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function) | ||||
|     { | ||||
|         const uint funcAddr = _moduleBase + Function->BeginAddress; | ||||
|         const uint funcEnd = _moduleBase + Function->EndAddress; | ||||
| 
 | ||||
|         // If within limits...
 | ||||
|         if(funcAddr >= _base && funcAddr < _base + _size) | ||||
|             _functionStarts.insert(funcAddr); | ||||
|         count++; | ||||
|         return true; | ||||
|     }); | ||||
|     dprintf("%u functions from the exception directory...\n", count); | ||||
| #endif // _WIN64
 | ||||
| 
 | ||||
|     dprintf("%u basic blocks, %u function starts detected...\n", _blocks.size(), _functionStarts.size()); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::Functions() | ||||
| { | ||||
|     typedef std::pair<BasicBlock*, UintSet*> DelayedBlock; | ||||
|     std::vector<DelayedBlock> delayedBlocks; | ||||
|     for(auto & it : _blocks) | ||||
|     { | ||||
|         BasicBlock* block = &it.second; | ||||
|         UintSet* parents = findParents(block->start); | ||||
|         if(!block->function) | ||||
|         { | ||||
|             if(!parents || _functionStarts.count(block->start))  //no parents = function start
 | ||||
|             { | ||||
|                 uint functionStart = block->start; | ||||
|                 block->function = functionStart; | ||||
|                 UintSet functionBlocks; | ||||
|                 functionBlocks.insert(functionStart); | ||||
|                 _functions[functionStart] = functionBlocks; | ||||
|             } | ||||
|             else //in function
 | ||||
|             { | ||||
|                 uint function = findFunctionStart(block, parents); | ||||
|                 if(!function)  //this happens with loops / unreferenced blocks sometimes
 | ||||
|                     delayedBlocks.push_back(DelayedBlock(block, parents)); | ||||
|                 else | ||||
|                     block->function = function; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|             DebugBreak(); //this should not happen
 | ||||
|     } | ||||
|     int delayedCount = (int)delayedBlocks.size(); | ||||
|     dprintf("%u/%u delayed blocks...\n", delayedCount, _blocks.size()); | ||||
|     int resolved = 0; | ||||
|     for(auto & delayedBlock : delayedBlocks) | ||||
|     { | ||||
|         BasicBlock* block = delayedBlock.first; | ||||
|         UintSet* parents = delayedBlock.second; | ||||
|         uint function = findFunctionStart(block, parents); | ||||
|         if(!function) | ||||
|         { | ||||
|             continue; | ||||
|             /*dprintf("unresolved block %s\n", blockToString(block).c_str());
 | ||||
|             if(parents) | ||||
|             { | ||||
|                 dprintf("parents:\n"); | ||||
|                 for(auto parent : *parents) | ||||
|                     dprintf("  %s\n", blockToString(findBlock(parent)).c_str()); | ||||
|             } | ||||
|             else | ||||
|                 dprintf("parents: null"); | ||||
|             dprintf("left: %s\n", blockToString(findBlock(block->left)).c_str()); | ||||
|             dprintf("right: %s\n", blockToString(findBlock(block->right)).c_str()); | ||||
|             return;*/ | ||||
|         } | ||||
|         block->function = function; | ||||
|         resolved++; | ||||
|     } | ||||
|     dprintf("%u/%u delayed blocks resolved (%u/%u still left, probably unreferenced functions)\n", resolved, delayedCount, delayedCount - resolved, _blocks.size()); | ||||
|     int unreferencedCount = 0; | ||||
|     for(const auto & block : _blocks) | ||||
|     { | ||||
|         auto found = _functions.find(block.second.function); | ||||
|         if(found == _functions.end())  //unreferenced block
 | ||||
|         { | ||||
|             unreferencedCount++; | ||||
|             continue; | ||||
|         } | ||||
|         found->second.insert(block.second.start); | ||||
|     } | ||||
|     dprintf("%u/%u unreferenced blocks\n", unreferencedCount, _blocks.size()); | ||||
|     dprintf("%u functions found!\n", _functions.size()); | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::FunctionRanges() | ||||
| { | ||||
|     //iterate over the functions and then find the deepest block = function end
 | ||||
|     for(const auto & function : _functions) | ||||
|     { | ||||
|         uint start = function.first; | ||||
|         uint end = start; | ||||
|         for(auto blockstart : function.second) | ||||
|         { | ||||
|             BasicBlock* block = this->findBlock(blockstart); | ||||
|             if(!block) | ||||
|                 DebugBreak(); //this shouldn't happen
 | ||||
|             if(block->end > end) | ||||
|                 end = block->end; | ||||
|         } | ||||
|         _functionRanges.push_back({ start, end }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::insertBlock(BasicBlock block) | ||||
| { | ||||
|     if(_blocks.find(block.start) != _blocks.end()) | ||||
|         DebugBreak(); | ||||
|     _blocks[block.start] = block; | ||||
| } | ||||
| 
 | ||||
| ControlFlowAnalysis::BasicBlock* ControlFlowAnalysis::findBlock(uint start) | ||||
| { | ||||
|     if(!start) | ||||
|         return nullptr; | ||||
|     auto found = _blocks.find(start); | ||||
|     return found != _blocks.end() ? &found->second : nullptr; | ||||
| } | ||||
| 
 | ||||
| void ControlFlowAnalysis::insertParent(uint child, uint parent) | ||||
| { | ||||
|     if(!child || !parent) | ||||
|         return; | ||||
|     auto found = _parentMap.find(child); | ||||
|     if(found == _parentMap.end()) | ||||
|     { | ||||
|         UintSet parents; | ||||
|         parents.insert(parent); | ||||
|         _parentMap[child] = parents; | ||||
|     } | ||||
|     else | ||||
|         found->second.insert(parent); | ||||
| } | ||||
| 
 | ||||
| ControlFlowAnalysis::UintSet* ControlFlowAnalysis::findParents(uint child) | ||||
| { | ||||
|     if(!child) | ||||
|         return nullptr; | ||||
|     auto found = _parentMap.find(child); | ||||
|     return found != _parentMap.end() ? &found->second : nullptr; | ||||
| } | ||||
| 
 | ||||
| uint ControlFlowAnalysis::findFunctionStart(BasicBlock* block, ControlFlowAnalysis::UintSet* parents) | ||||
| { | ||||
|     if(!block) | ||||
|         return 0; | ||||
|     if(block->function) | ||||
|         return block->function; | ||||
|     BasicBlock* left = findBlock(block->left); | ||||
|     if(left && left->function) | ||||
|         return left->function; | ||||
|     BasicBlock* right = findBlock(block->right); | ||||
|     if(right && right->function) | ||||
|         return right->function; | ||||
|     for(auto start : *parents) | ||||
|     { | ||||
|         BasicBlock* parent = findBlock(start); | ||||
|         if(parent->function) | ||||
|             return parent->function; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| String ControlFlowAnalysis::blockToString(BasicBlock* block) | ||||
| { | ||||
|     if(!block) | ||||
|         return String("null"); | ||||
|     return block->toString(); | ||||
| } | ||||
| 
 | ||||
| uint ControlFlowAnalysis::GetReferenceOperand() | ||||
| { | ||||
|     for(int i = 0; i < _cp.x86().op_count; i++) | ||||
|     { | ||||
|         const cs_x86_op & operand = _cp.x86().operands[i]; | ||||
|         if(operand.type == X86_OP_IMM) | ||||
|         { | ||||
|             uint dest = (uint)operand.imm; | ||||
|             if(dest >= _base && dest < _base + _size) | ||||
|                 return dest; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| void ControlFlowAnalysis::EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback) | ||||
| { | ||||
|     if(!_functionInfoData) | ||||
|         return; | ||||
| 
 | ||||
|     // Get the table pointer and size
 | ||||
|     auto functionTable = (PRUNTIME_FUNCTION)_functionInfoData; | ||||
|     uint totalCount = (_functionInfoSize / sizeof(RUNTIME_FUNCTION)); | ||||
| 
 | ||||
|     // Enumerate each entry
 | ||||
|     for(ULONG i = 0; i < totalCount; i++) | ||||
|     { | ||||
|         if(!Callback(&functionTable[i])) | ||||
|             break; | ||||
|     } | ||||
| } | ||||
| #endif // _WIN64
 | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue