├── pythia.pdf ├── pythia.suo ├── obfuscate.h ├── write.h ├── helpers.cpp ├── pythia.sln ├── readme.txt ├── pythia.vcproj.GIBSON.sp.user ├── DFMParser.h ├── obfuscate.cpp ├── collisions.h ├── sync.h ├── pythia.dev ├── sync.cpp ├── write.cpp ├── collisions.cpp ├── VMTDir.h ├── main.cpp ├── pythia.vcproj ├── helpers.h ├── DFMParser.cpp └── VMTDir.cpp /pythia.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sporst/Pythia/HEAD/pythia.pdf -------------------------------------------------------------------------------- /pythia.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sporst/Pythia/HEAD/pythia.suo -------------------------------------------------------------------------------- /obfuscate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * obfuscate.h - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #ifndef OBFUSCATE_H 12 | #define OBFUSCATE_H 13 | 14 | #include "VMTDir.h" 15 | #include "DFMParser.h" 16 | 17 | void obfuscate(DFMData& dfmres, VMTDir& vmtdir); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /write.h: -------------------------------------------------------------------------------- 1 | /* 2 | * write.h - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #ifndef WRITE_H 12 | #define WRITE_H 13 | 14 | #include "DFMParser.h" 15 | #include "VMTDir.h" 16 | 17 | #include 18 | 19 | void store(const std::string& filename, const DFMData& dfmresources, VMTDir& vmtdir, PeLib::PeFile32& pef); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /helpers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * helpers.cpp - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | unsigned int g_recognizedVmts; 15 | 16 | /** 17 | * Prints an error message to stdout and terminates the program 18 | * returning EXIT_FAILURE to the shell. 19 | * @param error Error message to print. 20 | **/ 21 | void die(const std::string& error) 22 | { 23 | std::cout << error << std::endl; 24 | std::exit(EXIT_FAILURE); 25 | } 26 | -------------------------------------------------------------------------------- /pythia.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual Studio 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pythia", "pythia.vcproj", "{07804D92-2DB4-4E51-A5BE-8B4035719954}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {07804D92-2DB4-4E51-A5BE-8B4035719954}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {07804D92-2DB4-4E51-A5BE-8B4035719954}.Debug|Win32.Build.0 = Debug|Win32 14 | {07804D92-2DB4-4E51-A5BE-8B4035719954}.Release|Win32.ActiveCfg = Release|Win32 15 | {07804D92-2DB4-4E51-A5BE-8B4035719954}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Pythia - A Delphi obfuscator 2 | Copyright (c) 2005 Sebastian Porst 3 | 4 | 1. What license does Pythia use? 5 | Pythia uses the zlib/libpng license (http://www.opensource.org/licenses/zlib-license.php) 6 | 7 | This software is provided 'as-is', without any express or implied warranty. 8 | In no event will the authors be held liable for any damages arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, including commercial 11 | applications, and to alter it and redistribute it freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the 14 | original software. If you use this software in a product, an acknowledgment in the 15 | product documentation would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented 18 | as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | 2. What does Pythia do? 23 | Check the file pythia.pdf. 24 | 25 | 3. How to compile Pythia? 26 | I developed it using Dev-C++ 5 beta and g++ 3.4.2. The Dev-C++ project file is included. 27 | If you don't use Dev-C++ just compile all cpp files to one binary file. 28 | PeLib (http://www.pelib.com) is required to compile Pythia. -------------------------------------------------------------------------------- /pythia.vcproj.GIBSON.sp.user: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 35 | 36 | 39 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /DFMParser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * DFMParser.h - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #ifndef DFMPARSER_H 12 | #define DFMPARSER_H 13 | 14 | #include 15 | 16 | enum { DFM_VARIANT = 0, 17 | DFM_ARRAY = 1, 18 | DFM_BYTE = 2, 19 | DFM_WORD = 3, 20 | DFM_DWORD = 4, 21 | DFM_DOUBLE = 5, 22 | DFM_ENUM = 6, 23 | DFM_STRING = 7, 24 | DFM_BOOLEAN_FALSE = 8, 25 | DFM_BOOLEAN_TRUE = 9, 26 | DFM_BITMAP = 10, 27 | DFM_SET = 11, 28 | DFM_LONGSTRING2 = 12, 29 | DFM_NIL = 13, 30 | DFM_RECORD = 14, 31 | DFM_UNICODE_STRING = 0x12, 32 | DFM_LONGSTRING = 0x14 33 | }; 34 | 35 | /** 36 | * A DFM property consists of a name and a value. For simplicity's sake 37 | * the file offset of the property and whether it was already obfuscated are 38 | * also stored. 39 | **/ 40 | struct DFMProperty 41 | { 42 | unsigned int type; 43 | unsigned int offset; 44 | std::vector name; 45 | std::vector value; 46 | std::vector values; 47 | }; 48 | 49 | /** 50 | * A DFM resource consists of a class name, an object name and a number 51 | * of properties. For simplicity's sake the file offset of resource 52 | * is also stored. 53 | **/ 54 | struct DFMResource 55 | { 56 | unsigned int offset; 57 | std::string* name; 58 | std::string* classname; 59 | DFMResource* parent; 60 | 61 | std::vector properties; 62 | std::vector children; 63 | 64 | DFMResource() : name(0), classname(0), parent(0) {} 65 | }; 66 | 67 | typedef std::vector DFMData; 68 | 69 | void readDFMResources(PeLib::PeFile32& pefile, DFMData& dfmresources); 70 | bool isTopElement(const DFMData& dfmres, const std::string& name); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /obfuscate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * obfuscate.cpp - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #include "obfuscate.h" 12 | #include "helpers.h" 13 | 14 | #include 15 | 16 | /** 17 | * Replaces the name element of object x with a random string. 18 | * @param x The object with the name element. 19 | **/ 20 | template 21 | void obfuscate(T& x) 22 | { 23 | extern bool showChanges; 24 | 25 | std::string newvalue = uniqueString(static_cast(x.name->length())); 26 | 27 | if ( showChanges ) 28 | { 29 | std::cout << *x.name << " -> " << newvalue << "\n"; 30 | } 31 | 32 | *x.name = newvalue; 33 | } 34 | 35 | /** 36 | * Obfuscates the DFM and VMT data of a Delphi file. 37 | * @param dfmres The DFM data of an entire Delphi file. 38 | * @param vmtdir The VMT data of an entire Delphi file. 39 | **/ 40 | void obfuscate(DFMData& dfmres, VMTDir& vmtdir) 41 | { 42 | std::deque vmts; 43 | fill(vmtdir, vmts); 44 | 45 | extern bool showChanges; 46 | 47 | if ( showChanges ) 48 | { 49 | std::cout << "Obfuscated strings: \n\n"; 50 | } 51 | 52 | for (std::deque::iterator Iter = vmts.begin(); Iter != vmts.end(); ++Iter) 53 | { 54 | if (!isTopElement(dfmres, *(*Iter)->name)) obfuscate(**Iter); 55 | 56 | std::for_each((*Iter)->typeinfo.begin(), (*Iter)->typeinfo.end(), obfuscate); 57 | std::for_each((*Iter)->fields.begin(), (*Iter)->fields.end(), obfuscate); 58 | std::for_each((*Iter)->methods.begin(), (*Iter)->methods.end(), obfuscate); 59 | } 60 | 61 | for (unsigned int i=0;i(*dfmres[i]); 64 | } 65 | 66 | if ( showChanges ) 67 | { 68 | std::cout << "\n"; 69 | } 70 | } 71 | 72 | 73 | -------------------------------------------------------------------------------- /collisions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * collisions.h - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 - 2007 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #ifndef COLLISIONS_H 12 | #define COLLISIONS_H 13 | 14 | #include "VMTDir.h" 15 | #include "DFMParser.h" 16 | 17 | void checkStringCollisions(DFMData& dfmres, const VMTDir& vmtdir); 18 | 19 | // TODO: Add some way to stop traversal of directories. 20 | 21 | /** 22 | * This class is used to search for components with a given name. 23 | **/ 24 | class ComponentFinder : public DFMVisitor 25 | { 26 | private: 27 | /** 28 | * The name of the component to search. 29 | **/ 30 | std::string searchString; 31 | 32 | /** 33 | * Flag that indicates whether the search was successful. 34 | **/ 35 | bool foundString; 36 | 37 | /** 38 | * The found resource (or 0). 39 | **/ 40 | const DFMResource* res; 41 | 42 | protected: 43 | /** 44 | * Called for each DFMResource in the DFM directory. 45 | **/ 46 | virtual void resourceCallback(DFMResource* res); 47 | 48 | /** 49 | * Called for each DFMProperty in the DFM directory; 50 | **/ 51 | virtual void propertyCallback(DFMProperty& property); 52 | 53 | public: 54 | /** 55 | * Creates a new ComponentFinder object. 56 | **/ 57 | ComponentFinder(const std::string& searchString); 58 | 59 | /** 60 | * Flag that indicates whether the search was succesful. 61 | **/ 62 | bool found() const; 63 | 64 | /** 65 | * Found resource or 0. 66 | **/ 67 | const DFMResource* foundResource() const; 68 | }; 69 | 70 | /** 71 | * This class is used to find string collisions (see checkStringCollisions for 72 | * a description). 73 | **/ 74 | class CollisionVisitor : public DFMVisitor 75 | { 76 | private: 77 | /** 78 | * The DFM directory to traverse. 79 | **/ 80 | DFMData& dfmData; 81 | 82 | /** 83 | * The VMT Directory that's synchronized with the DFMDirectory. 84 | **/ 85 | const VMTDir& vmtDir; 86 | 87 | /** 88 | * The last traversed resource. 89 | **/ 90 | const DFMResource* lastResource; 91 | 92 | protected: 93 | /** 94 | * Called for each DFMResource in the DFM directory. 95 | **/ 96 | virtual void resourceCallback(DFMResource* res); 97 | 98 | /** 99 | * Called for each DFMProperty in the DFM directory; 100 | **/ 101 | virtual void propertyCallback(DFMProperty& property); 102 | 103 | public: 104 | 105 | /** 106 | * Creates a new CollisionVisitor object. 107 | * 108 | * @param dfmData A DFM directory. 109 | * @param vmtDir A VMT directory. 110 | **/ 111 | CollisionVisitor(DFMData& dfmData, const VMTDir& vmtDir); 112 | }; 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /sync.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sync.h - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #ifndef SYNC_H 12 | #define SYNC_H 13 | 14 | #include "DFMParser.h" 15 | #include "VMTDir.h" 16 | #include "helpers.h" 17 | 18 | #include 19 | 20 | void synchronize(DFMData& dfmres, const VMTDir& vmtdir); 21 | void synchronizeProperties(DFMResource* dfm, const std::string& classname, DFMProperty& property, const VMTDir& vmtdir, const DFMData& dfmres); 22 | 23 | /** 24 | * Used to synchronize the names of objects in the DFM tree with the 25 | * names of fields in the VMT tree. 26 | **/ 27 | class SynchronizeName 28 | { 29 | private: 30 | const VMTDir& vmtdir_; 31 | 32 | public: 33 | SynchronizeName(const VMTDir& vmtdir) : vmtdir_(vmtdir) {} 34 | 35 | void operator()(DFMResource* dfm) 36 | { 37 | if (dfm && dfm->parent) 38 | { 39 | DFMResource* parent = dfm; 40 | 41 | VMT* vmt = 0; 42 | 43 | std::string* str = 0; 44 | 45 | if (dfm) 46 | parent = parent->parent; 47 | 48 | do 49 | { 50 | vmt = find(vmtdir_, *parent->classname); 51 | 52 | parent = parent->parent; 53 | 54 | if (vmt) 55 | { 56 | str = getVMTAttribute(vmt->fields, *dfm->name); 57 | 58 | if (str) 59 | break; 60 | } 61 | } 62 | while (parent); 63 | 64 | if (!str) 65 | return; 66 | 67 | delete dfm->name; 68 | dfm->name = str; 69 | } 70 | } 71 | }; 72 | 73 | /** 74 | * Used to synchronize the class names of objects in the DFM tree with the 75 | * names of classes in the VMT tree. 76 | **/ 77 | class SynchronizeClassName 78 | { 79 | private: 80 | const VMTDir& vmtdir_; 81 | 82 | public: 83 | SynchronizeClassName(const VMTDir& vmtdir) : vmtdir_(vmtdir) {} 84 | 85 | void operator()(DFMResource* dfm) 86 | { 87 | VMT* vmt = find(vmtdir_, *dfm->classname); 88 | if (!vmt) return; 89 | 90 | delete dfm->classname; 91 | dfm->classname = vmt->name; 92 | } 93 | }; 94 | 95 | /** 96 | * Used to synchronize the names and values in the DFM tree with elements 97 | * of the VMT tree. 98 | **/ 99 | class SynchronizeProperties 100 | { 101 | private: 102 | const VMTDir& vmtdir_; 103 | const DFMData& dfmres_; 104 | 105 | public: 106 | SynchronizeProperties(const VMTDir& vmtdir, const DFMData& dfmres) 107 | : vmtdir_(vmtdir), dfmres_(dfmres) {} 108 | 109 | void operator()(DFMResource* dfm) 110 | { 111 | for (unsigned int i=0;iproperties.size();++i) 112 | { 113 | synchronizeProperties(dfm, *dfm->classname, dfm->properties[i], vmtdir_, dfmres_); 114 | } 115 | } 116 | }; 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /pythia.dev: -------------------------------------------------------------------------------- 1 | [Project] 2 | FileName=pythia.dev 3 | Name=DelphiObfuscator 4 | UnitCount=13 5 | Type=1 6 | Ver=1 7 | ObjFiles= 8 | Includes=D:\Coding\PeLib-dev\source 9 | Libs=D:\Coding\PeLib-dev\lib 10 | PrivateResource= 11 | ResourceIncludes= 12 | MakeIncludes= 13 | Compiler= 14 | CppCompiler=-Wall -W_@@_ 15 | Linker=../../PeLib-dev/lib/TlsDirectory.o_@@_../../PeLib-dev/lib/BoundImportDirectory.o_@@_../../PeLib-dev/lib/ComHeaderDirectory.o_@@_../../PeLib-dev/lib/DebugDirectory.o_@@_../../PeLib-dev/lib/ExportDirectory.o_@@_../../PeLib-dev/lib/IatDirectory.o_@@_../../PeLib-dev/lib/InputBuffer.o_@@_../../PeLib-dev/lib/MzHeader.o_@@_../../PeLib-dev/lib/OutputBuffer.o_@@_../../PeLib-dev/lib/PeFile.o_@@_../../PeLib-dev/lib/PeHeader.o_@@_../../PeLib-dev/lib/PeLibAux.o_@@_../../PeLib-dev/lib/RelocationsDirectory.o_@@_../../PeLib-dev/lib/ResourceDirectory.o_@@_ 16 | IsCpp=1 17 | Icon= 18 | ExeOutput= 19 | ObjectOutput= 20 | OverrideOutput=0 21 | OverrideOutputName=DelphiObfuscator.exe 22 | HostApplication= 23 | Folders= 24 | CommandLine=foo.exe 25 | UseCustomMakefile=0 26 | CustomMakefile= 27 | IncludeVersionInfo=0 28 | SupportXPThemes=0 29 | CompilerSet=0 30 | CompilerSettings=0000000001001000000100 31 | 32 | [Unit1] 33 | FileName=main.cpp 34 | CompileCpp=1 35 | Folder= 36 | Compile=1 37 | Link=1 38 | Priority=1000 39 | OverrideBuildCmd=0 40 | BuildCmd= 41 | 42 | [Unit2] 43 | FileName=DFMParser.h 44 | CompileCpp=1 45 | Folder= 46 | Compile=1 47 | Link=1 48 | Priority=1000 49 | OverrideBuildCmd=0 50 | BuildCmd= 51 | 52 | [Unit3] 53 | FileName=DFMParser.cpp 54 | CompileCpp=1 55 | Folder=DelphiObfuscator 56 | Compile=1 57 | Link=1 58 | Priority=1000 59 | OverrideBuildCmd=0 60 | BuildCmd= 61 | 62 | [VersionInfo] 63 | Major=0 64 | Minor=1 65 | Release=1 66 | Build=1 67 | LanguageID=1033 68 | CharsetID=1252 69 | CompanyName= 70 | FileVersion= 71 | FileDescription=Developed using the Dev-C++ IDE 72 | InternalName= 73 | LegalCopyright= 74 | LegalTrademarks= 75 | OriginalFilename= 76 | ProductName= 77 | ProductVersion= 78 | AutoIncBuildNr=0 79 | 80 | [Unit4] 81 | FileName=VMTDir.h 82 | CompileCpp=1 83 | Folder= 84 | Compile=1 85 | Link=1 86 | Priority=1000 87 | OverrideBuildCmd=0 88 | BuildCmd= 89 | 90 | [Unit5] 91 | FileName=VMTDir.cpp 92 | CompileCpp=1 93 | Folder= 94 | Compile=1 95 | Link=1 96 | Priority=1000 97 | OverrideBuildCmd=0 98 | BuildCmd= 99 | 100 | [Unit6] 101 | FileName=helpers.h 102 | CompileCpp=1 103 | Folder= 104 | Compile=1 105 | Link=1 106 | Priority=1000 107 | OverrideBuildCmd=0 108 | BuildCmd= 109 | 110 | [Unit7] 111 | FileName=helpers.cpp 112 | CompileCpp=1 113 | Folder= 114 | Compile=1 115 | Link=1 116 | Priority=1000 117 | OverrideBuildCmd=0 118 | BuildCmd= 119 | 120 | [Unit10] 121 | FileName=obfuscate.cpp 122 | CompileCpp=1 123 | Folder=DelphiObfuscator 124 | Compile=1 125 | Link=1 126 | Priority=1000 127 | OverrideBuildCmd=0 128 | BuildCmd= 129 | 130 | [Unit11] 131 | FileName=write.cpp 132 | CompileCpp=1 133 | Folder=DelphiObfuscator 134 | Compile=1 135 | Link=1 136 | Priority=1000 137 | OverrideBuildCmd=0 138 | BuildCmd= 139 | 140 | [Unit8] 141 | FileName=write.h 142 | CompileCpp=1 143 | Folder= 144 | Compile=1 145 | Link=1 146 | Priority=1000 147 | OverrideBuildCmd=0 148 | BuildCmd= 149 | 150 | [Unit9] 151 | FileName=obfuscate.h 152 | CompileCpp=1 153 | Folder=DelphiObfuscator 154 | Compile=1 155 | Link=1 156 | Priority=1000 157 | OverrideBuildCmd=0 158 | BuildCmd= 159 | 160 | [Unit12] 161 | FileName=sync.h 162 | CompileCpp=1 163 | Folder= 164 | Compile=1 165 | Link=1 166 | Priority=1000 167 | OverrideBuildCmd=0 168 | BuildCmd= 169 | 170 | [Unit13] 171 | FileName=sync.cpp 172 | CompileCpp=1 173 | Folder= 174 | Compile=1 175 | Link=1 176 | Priority=1000 177 | OverrideBuildCmd=0 178 | BuildCmd= 179 | 180 | -------------------------------------------------------------------------------- /sync.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * sync.cpp - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #include "sync.h" 12 | 13 | #include 14 | #include 15 | 16 | /** 17 | * Synchronizes a DFM tree with a VMT tree. 18 | * @param dfmres DFM tree. 19 | * @param vmtdir VMT tree. 20 | **/ 21 | void synchronize(DFMData& dfmres, const VMTDir& vmtdir) 22 | { 23 | std::vector objectnames; 24 | 25 | std::deque dfms; 26 | fill(dfmres, dfms); 27 | 28 | std::for_each(dfms.begin(), dfms.end(), SynchronizeName(vmtdir)); 29 | std::for_each(dfms.begin(), dfms.end(), SynchronizeClassName(vmtdir)); 30 | std::for_each(dfms.begin(), dfms.end(), SynchronizeProperties(vmtdir, dfmres)); 31 | } 32 | 33 | /** 34 | * Synchronizes one element of a DFM tree with an element of a VMT tree. 35 | * @param classname Class of the element the property belongs to. 36 | * @param value Name of value of a property. 37 | * @param vmtdir VMT tree. 38 | * @param dfmres DFM tree. 39 | **/ 40 | void synchronizePropertyValue(const std::string& classname, std::vector& value, const VMTDir& vmtdir, const DFMData& dfmres) 41 | { 42 | splitName(value); 43 | 44 | VMT* vmt = handleCollections(find(vmtdir, classname), vmtdir); 45 | if (!vmt) return; 46 | 47 | for (unsigned int i=0;isize()) continue; 50 | 51 | VMT* vmt2; 52 | if (vmt2 = findVMT(vmt, *value[i])) 53 | { 54 | std::string* y = getVMTAttribute(vmt2->typeinfo, *value[i]); 55 | if (!y) break; 56 | delete value[i]; 57 | value[i] = y; 58 | 59 | std::string* x = getAttributeType(vmt2, *value[i], vmtdir); 60 | if (!x) break; 61 | 62 | // Special handling. Figure out a better way. 63 | if (*x == "TCustomActionBarColorMap") 64 | { 65 | x = new std::string("TXPColorMap"); 66 | } 67 | 68 | vmt2 = find(vmtdir, *x); 69 | if (!vmt2) break; 70 | } 71 | else if (vmt2 = findVMT(vmt, *value[i])) 72 | { 73 | std::string* x = getValue(vmt2->methods, *value[i], true); 74 | delete value[i]; 75 | value[i] = x; 76 | } 77 | else if (vmt2 = findVMT(vmt, *value[i])) 78 | { 79 | std::string* x = getValue(vmt2->fields, *value[i]); 80 | delete value[i]; 81 | value[i] = x; 82 | } 83 | else if (DFMResource* res = find(dfmres, *value[i])) 84 | { 85 | delete value[i]; 86 | value[i] = res->name; 87 | vmt2 = find(vmtdir, *res->classname); 88 | } 89 | else if (vmt2 = find(vmtdir, *value[i])) 90 | { 91 | // This last if-branch is required for bitmaps. 92 | // value[i] should be TBitmap or TIcon here. 93 | delete value[i]; 94 | value[i] = vmt2->name; 95 | } 96 | else 97 | { 98 | // std::cout << "Couldn't find " << *value[i] << std::endl; 99 | } 100 | 101 | vmt = vmt2; 102 | 103 | if (!vmt) break; 104 | } 105 | } 106 | 107 | /** 108 | * Synchronizes the properties of a DFM tree with elements of a VMT tree. 109 | **/ 110 | void synchronizeProperties(DFMResource* dfm, const std::string& classname, DFMProperty& property, const VMTDir& vmtdir, const DFMData& dfmres) 111 | { 112 | while (dfm && dfm->parent) dfm = dfm->parent; 113 | 114 | // Order is important. 115 | synchronizePropertyValue(*dfm->classname, property.value, vmtdir, dfmres); 116 | synchronizePropertyValue(classname, property.name, vmtdir, dfmres); 117 | 118 | for (unsigned int i=0;i(vmtdir, classname), vmtdir); 123 | if (!vmt) continue; 124 | std::string* x = getAttributeType(vmt, *property.name.front(), vmtdir); 125 | if (!x) continue; 126 | vmt = find(vmtdir, *x); 127 | if (!vmt) continue; 128 | synchronizeProperties(dfm, *vmt->name, property.values[i], vmtdir, dfmres); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /write.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * write.cpp - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #include "write.h" 12 | 13 | #include 14 | 15 | /** 16 | * Used write the name elements of objects to a file. 17 | **/ 18 | template 19 | class WriteName 20 | { 21 | std::fstream& file_; 22 | 23 | public: 24 | WriteName(std::fstream& file) : file_(file) {} 25 | 26 | void operator()(T& x) 27 | { 28 | file_.seekp(x.nameoffset + 1); 29 | file_.write(x.name->c_str(), static_cast(x.name->length())); 30 | if (!file_) throw new std::string("Error: Couldn't write file."); 31 | } 32 | }; 33 | 34 | /** 35 | * Stores the obfuscated data back to the file. 36 | * @param filename Name of the file where data is written to. 37 | * @param dfmresources Obfuscated DFM data 38 | * @param vmtdir Obfuscated VMT data. 39 | **/ 40 | void store(const std::string& filename, const DFMData& dfmresources, VMTDir& vmtdir, PeLib::PeFile32& pef) 41 | { 42 | std::fstream file(filename.c_str(), std::ios::in | std::ios::out | std::ios::binary); 43 | 44 | PeLib::PeHeader32& peh = pef.peHeader(); 45 | 46 | if (!file) throw new std::string("Error: Couldn't open file."); 47 | 48 | std::deque vmts; 49 | fill(vmtdir, vmts); 50 | 51 | for (std::deque::iterator Iter = vmts.begin(); Iter != vmts.end(); ++Iter) 52 | { 53 | file.seekp((*Iter)->nameoffset + 1); 54 | file.write((*Iter)->name->c_str(), static_cast((*Iter)->name->length())); 55 | if (!file) throw new std::string("Error: Couldn't write file."); 56 | 57 | if ((*Iter)->vmtTypeInfo) 58 | { 59 | file.seekp(peh.vaToOffset((*Iter)->vmtTypeInfo) + 2); 60 | file.write((*Iter)->name->c_str(), static_cast((*Iter)->name->length())); 61 | if (!file) throw new std::string("Error: Couldn't write file."); 62 | } 63 | 64 | std::for_each((*Iter)->typeinfo.begin(), (*Iter)->typeinfo.end(), WriteName(file)); 65 | std::for_each((*Iter)->fields.begin(), (*Iter)->fields.end(), WriteName(file)); 66 | std::for_each((*Iter)->methods.begin(), (*Iter)->methods.end(), WriteName(file)); 67 | } 68 | 69 | std::deque dfms; 70 | fill(dfmresources, dfms); 71 | 72 | for (std::deque::iterator Iter = dfms.begin(); Iter != dfms.end(); ++Iter) 73 | { 74 | DFMResource* dfm = *Iter; 75 | 76 | file.seekp(dfm->offset + 1); 77 | file.write(dfm->classname->c_str(), static_cast(dfm->classname->length())); 78 | file.seekp(1, std::ios_base::cur); 79 | file.write(dfm->name->c_str(), static_cast(dfm->name->length())); 80 | 81 | std::deque dfmps(dfm->properties.begin(), dfm->properties.end()); 82 | 83 | while (dfmps.size()) 84 | { 85 | DFMProperty property = dfmps[0]; 86 | dfmps.pop_front(); 87 | 88 | file.seekp(property.offset + 1); 89 | 90 | if (property.name.size()) 91 | { 92 | for (unsigned int j=0;jc_str(), static_cast(property.name[j]->length())); 95 | file.write(".", 1); 96 | } 97 | 98 | file.write(property.name.back()->c_str(), static_cast(property.name.back()->length())); 99 | } 100 | 101 | if (property.value.size()) 102 | { 103 | file.seekp(property.offset + propertyNameLength(property.name) + 3); 104 | 105 | if (property.type == DFM_BITMAP) 106 | { 107 | file.seekp(4, std::ios_base::cur); 108 | } 109 | 110 | for (unsigned int i=0;ic_str(), static_cast(property.value[i]->length())); 113 | file.write(".", 1); 114 | } 115 | 116 | file.write(property.value.back()->c_str(), static_cast(property.value.back()->length())); 117 | } 118 | 119 | std::copy(property.values.begin(), property.values.end(), std::back_inserter(dfmps)); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /collisions.cpp: -------------------------------------------------------------------------------- 1 | #include "collisions.h" 2 | #include "helpers.h" 3 | #include "sync.h" 4 | 5 | /** 6 | * Creates a new ComponentFinder object. 7 | * 8 | * @param searchString String to search for. 9 | **/ 10 | ComponentFinder::ComponentFinder(const std::string& searchString) 11 | : searchString(searchString), foundString(false) 12 | { 13 | } 14 | 15 | /** 16 | * Updates the states of the object if the resource was found. 17 | **/ 18 | void ComponentFinder::resourceCallback(DFMResource* res) 19 | { 20 | if (*res->name == searchString) 21 | { 22 | foundString = true; 23 | res = res; 24 | } 25 | } 26 | 27 | /** 28 | * Unused 29 | **/ 30 | void ComponentFinder::propertyCallback(DFMProperty& property) 31 | { 32 | } 33 | 34 | /** 35 | * Returns a flag that indicates whether the search was succesful or not. 36 | * 37 | * @return A flag that indicates whether the search was succesful or not. 38 | **/ 39 | bool ComponentFinder::found() const { return foundString; } 40 | 41 | /** 42 | * Returns the located resource if the search was succesful. 43 | * 44 | * @return The located resource or 0. 45 | **/ 46 | const DFMResource* ComponentFinder::foundResource() const { return res; } 47 | 48 | /** 49 | * Creates a new CollisionVisitor object. 50 | **/ 51 | CollisionVisitor::CollisionVisitor(DFMData& dfmData, const VMTDir& vmtDir) 52 | : dfmData(dfmData), vmtDir(vmtDir), lastResource(0) 53 | { 54 | } 55 | 56 | void CollisionVisitor::resourceCallback(DFMResource* res) 57 | { 58 | // Keep track of what resource is currently traversed. 59 | lastResource = res; 60 | } 61 | 62 | void CollisionVisitor::propertyCallback(DFMProperty& property) 63 | { 64 | // At this point we're trying to find the property values which also 65 | // appear as component names. These values are necessarily Strings. 66 | // The type of these values is not limited to DFM_STRING though. 67 | 68 | extern bool verboseMode; 69 | 70 | if (property.value.size() == 0) 71 | { 72 | // If there's no value, then the value can't possible be the name 73 | // of a component. 74 | return; 75 | } 76 | 77 | VERBOSE_PRINT("Collision check: " << concatStringVector(property.value) 78 | << " in resource " << *lastResource->classname << " " << *lastResource->name); 79 | 80 | if (property.type != DFM_ENUM 81 | && property.type != DFM_STRING 82 | && property.type != DFM_LONGSTRING 83 | && property.type != DFM_LONGSTRING2) 84 | { 85 | // If it's none of those types, the value can't possibly be the name 86 | // of a component. 87 | return; 88 | } 89 | 90 | // Create a deep copy of the property name vector. 91 | std::vector value = deepCopy(property.name); 92 | 93 | // Find the VCL type of the property. 94 | const std::string* type = findType(*lastResource->classname, value, vmtDir, dfmData); 95 | 96 | if (!type) 97 | { 98 | std::cout << "Error: Can't find type of property " << *value[0] << std::endl; 99 | return; 100 | } 101 | 102 | VERBOSE_PRINT("Type found: " << *type); 103 | 104 | if ( 105 | *type != "String" && 106 | *type != "WideString" && 107 | *type != "TCaption" && 108 | *type != "TFontName" 109 | ) 110 | { 111 | // TODO: Add TFontName? 112 | 113 | // Only these VCL types can cause conflicts. 114 | return; 115 | } 116 | 117 | // At this point we have the value of a String property. Now 118 | // we need to check if a component with this name exists. 119 | // TODO: Method names, Property Names, Field Names, ... 120 | 121 | // TODO: value[0] should be value[all] ? 122 | ComponentFinder finder(*property.value[0]); 123 | finder.visit(dfmData); 124 | 125 | if (!finder.found()) 126 | { 127 | // We're in the clear here. No conflict exists for that property. 128 | return; 129 | } 130 | 131 | // A conflict exists. Mark this property value as "Do not obfuscate" 132 | property.obfuscateValue = false; 133 | 134 | VERBOSE_PRINT("String conflict: " << concatStringVector(property.name) << " has value \"" << *property.value[0] << "\". A component has the same name."); 135 | } 136 | 137 | /** 138 | * String properties that have the same value as the name of a component should 139 | * not be obfuscated. It's assumed that the value of the string is a coincidence 140 | * and does not reference the component's name. 141 | * 142 | * This function searches for these situations and marks the found string values 143 | * with a flag that says that the values should not be obfuscated. 144 | * 145 | * @param dfmres A DFM Resource. 146 | * @param VMTDir A VMT directory. 147 | **/ 148 | void checkStringCollisions(DFMData& dfmres, const VMTDir& vmtdir) 149 | { 150 | // TODO: Don't just check component names but property names, method 151 | // names and field names too. 152 | CollisionVisitor(dfmres, vmtdir).visit(dfmres); 153 | } 154 | 155 | -------------------------------------------------------------------------------- /VMTDir.h: -------------------------------------------------------------------------------- 1 | /* 2 | * vmtdir.h - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #ifndef VMTPARSER_H 12 | #define VMTPARSER_H 13 | 14 | #include "helpers.h" 15 | 16 | #include 17 | 18 | template 19 | bool cmpncs(T s1, T s2); 20 | 21 | /** 22 | * Stores the property info of a VMT. 23 | **/ 24 | struct PropInfo 25 | { 26 | unsigned int PropType; 27 | unsigned int GetProc; 28 | unsigned int SetProc; 29 | unsigned int StoredProc; 30 | int Index; 31 | int Default; 32 | short int NameIndex; 33 | 34 | std::string* name; 35 | unsigned int nameoffset; 36 | 37 | std::string* type; 38 | unsigned int typeoffset; 39 | 40 | PropInfo() 41 | { 42 | name = 0; 43 | type = 0; 44 | } 45 | }; 46 | 47 | /** 48 | * Stores the method info of a VMT. 49 | **/ 50 | struct MethodInfo 51 | { 52 | unsigned short int id; 53 | unsigned int va; 54 | std::string* name; 55 | unsigned int nameoffset; 56 | 57 | MethodInfo() 58 | { 59 | name = 0; 60 | } 61 | }; 62 | 63 | struct FieldInfo 64 | { 65 | unsigned int nameoffset; 66 | std::string* name; 67 | 68 | FieldInfo() 69 | { 70 | name = 0; 71 | } 72 | }; 73 | 74 | /** 75 | * Stores information about a virtual method table. 76 | **/ 77 | struct VMT 78 | { 79 | unsigned int offset; 80 | unsigned int nameoffset; 81 | std::string* name; 82 | unsigned int parentvmt; 83 | 84 | VMT* parent; 85 | std::vector children; 86 | std::vector typeinfo; 87 | std::vector methods; 88 | std::vector fields; 89 | 90 | unsigned int vmtSelfPtr; 91 | unsigned int vmtIntfTable; 92 | unsigned int vmtAutoTable; 93 | unsigned int vmtInitTable; 94 | unsigned int vmtTypeInfo; 95 | unsigned int vmtFieldTable; 96 | unsigned int vmtMethodTable; 97 | unsigned int vmtDynamicTable; 98 | unsigned int vmtClassName; 99 | unsigned int vmtInstanceSize; 100 | unsigned int vmtParent; 101 | unsigned int vmtSafeCallException; 102 | unsigned int vmtAfterConstruction; 103 | unsigned int vmtBeforeDestruction; 104 | unsigned int vmtDispatch; 105 | unsigned int vmtDefaultHandler; 106 | unsigned int vmtNewInstance; 107 | unsigned int vmtFreeInstance; 108 | unsigned int vmtDestroy; 109 | 110 | VMT() 111 | { 112 | name = 0; 113 | parent = 0; 114 | } 115 | 116 | ~VMT() 117 | { 118 | for (unsigned int i=0;i VMTDir; 126 | 127 | void readVMTs(PeLib::PeFile32& pefile, VMTDir& vmtparser); 128 | VMT* handleCollections(VMT* vmt, const VMTDir& vmtdir); 129 | std::string* getAttributeType(const VMT* vmt, const std::string& name, const VMTDir& vmtdir); 130 | 131 | /** 132 | * Used when searching VMTs by method name. 133 | **/ 134 | struct FindByMethodName 135 | { 136 | static VMT* find(VMT* vmt, const std::string& methodname) 137 | { 138 | for (unsigned int i=0;imethods.size();i++) 139 | { 140 | if (cmpncs(*vmt->methods[i].name, methodname)) 141 | { 142 | return vmt; 143 | } 144 | } 145 | return 0; 146 | } 147 | }; 148 | 149 | /** 150 | * Used when searching VMTs by property name. 151 | **/ 152 | struct FindByPropertyName 153 | { 154 | static VMT* find(VMT* vmt, const std::string& propertyname) 155 | { 156 | for (unsigned int i=0;itypeinfo.size();i++) 157 | { 158 | if (*vmt->typeinfo[i].name == propertyname) 159 | { 160 | return vmt; 161 | } 162 | } 163 | return 0; 164 | } 165 | }; 166 | 167 | /** 168 | * Used when searching VMTs by field name. 169 | **/ 170 | struct FindByFieldName 171 | { 172 | static VMT* find(VMT* vmt, const std::string& fieldname) 173 | { 174 | for (unsigned int i=0;ifields.size();i++) 175 | { 176 | if (*vmt->fields[i].name == fieldname) 177 | { 178 | return vmt; 179 | } 180 | } 181 | return 0; 182 | } 183 | }; 184 | 185 | /** 186 | * Searches upwards through the VMT hierarchy for a VMT with a given value. 187 | * @param vmt The VMT where the search begins. 188 | * @param value The value to search for. 189 | * @return The VMT with the given value. If no such VMT was found the 190 | * return value is 0. 191 | **/ 192 | template 193 | VMT* findVMT(VMT* vmt, const std::string& value) 194 | { 195 | VMT* vmt2 = T::find(vmt, value); 196 | if (vmt2) return vmt2; 197 | else if (vmt->parent) return findVMT(vmt->parent, value); 198 | else return 0; 199 | } 200 | 201 | /** 202 | * Searches through a vector and returns the found element. 203 | * @param v The vector. 204 | * @param value The string value of the element to search for. 205 | * @return The found element or 0 if no element was found. 206 | **/ 207 | template 208 | std::string* getVMTAttribute(const std::vector& v, const std::string& value) 209 | { 210 | for (unsigned int i=0;i 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | extern unsigned int g_recognizedVmts; 28 | 29 | void printUsage() 30 | { 31 | std::cout << "Usage: pythia.exe [options] file\n\n"; 32 | std::cout << "Options:\n"; 33 | std::cout << " -i Prints information about the file (does not modify the file)\n"; 34 | std::cout << " -c Show changes (Prints the obfuscated strings)\n"; 35 | } 36 | 37 | void printStats() 38 | { 39 | std::cout << "Recognized VMTs: " << g_recognizedVmts << "\n\n"; 40 | } 41 | 42 | void printVMT(const VMT* vmt, std::string pad = "") 43 | { 44 | std::cout << pad << "Name: " << *vmt->name << "\n"; 45 | std::cout << pad << "Offset: 0x" << std::uppercase << std::hex << vmt->offset << "\n"; 46 | std::cout << pad << "Properties: " << std::dec << vmt->typeinfo.size() << "\n"; 47 | 48 | for (unsigned int i=0;itypeinfo.size();i++) 49 | { 50 | std::cout << pad << " " << *vmt->typeinfo[i].type << " " << *vmt->typeinfo[i].name << "\n"; 51 | std::cout << pad << " GetProc: " << std::hex << vmt->typeinfo[i].GetProc << "\n"; 52 | std::cout << pad << " SetProc: " << std::hex << vmt->typeinfo[i].SetProc << "\n"; 53 | std::cout << pad << " StoredProc: " << std::hex << vmt->typeinfo[i].StoredProc << "\n"; 54 | } 55 | 56 | std::cout << pad << "Methods: " << std::dec << vmt->methods.size() << "\n"; 57 | 58 | for (unsigned int i=0;imethods.size();i++) 59 | { 60 | std::cout << pad << " Name: " << *vmt->methods[i].name << " ( 0x" << std::hex << vmt->methods[i].va << " )\n"; 61 | } 62 | 63 | std::cout << pad << "Fields: " << std::dec << vmt->fields.size() << "\n"; 64 | 65 | for (unsigned int i=0;ifields.size();i++) 66 | { 67 | std::cout << pad << " Name: " << *vmt->fields[i].name << "\n"; 68 | } 69 | 70 | std::cout << "\n"; 71 | 72 | for (unsigned int i=0;ichildren.size();i++) 73 | printVMT(vmt->children[i], pad + " "); 74 | } 75 | 76 | void printDfm(DFMResource* dfm, std::string pad = "") 77 | { 78 | std::cout << pad << *dfm->classname << " " << *dfm->name << "\n"; 79 | 80 | std::cout << pad << "Properties: " << std::dec << dfm->properties.size() << "\n"; 81 | 82 | for (unsigned int i=0;iproperties.size();i++) 83 | { 84 | for (unsigned int j=0;jproperties[i].name.size();j++) 85 | { 86 | std::cout << pad << " " << *dfm->properties[i].name[j] << "\n"; 87 | } 88 | 89 | // for (unsigned int j=0;jproperties[i].value.size();j++) 90 | // { 91 | // std::cout << pad << " " << *dfm->properties[i].value[j] << "\n"; 92 | // } 93 | } 94 | 95 | std::cout << "\n"; 96 | 97 | for (unsigned int i=0;ichildren.size();i++) 98 | printDfm(dfm->children[i], pad + " "); 99 | } 100 | 101 | bool printInformation = false; 102 | bool showChanges = false; 103 | 104 | int main(int argc, char *argv[]) 105 | { 106 | std::cout << "Pythia 1.1 - Author: Sebastian Porst (webmaster@the-interweb.com)\n\n"; 107 | 108 | srand(static_cast(time(0))); 109 | 110 | if (argc < 2) 111 | { 112 | printUsage(); 113 | return 1; 114 | } 115 | 116 | for (int i=1;i::iterator Iter = vmtdir.begin(); Iter != vmtdir.end(); ++Iter) 145 | { 146 | printVMT(*Iter); 147 | } 148 | // std::for_each(vmtdir.begin(), vmtdir.end(), printVMT); 149 | } 150 | 151 | DFMData dfmresources; 152 | 153 | try 154 | { 155 | readDFMResources(pefile, dfmresources); 156 | 157 | if ( printInformation ) 158 | { 159 | std::cout << "Recognized DFMs\n\n"; 160 | 161 | for (std::vector::iterator Iter = dfmresources.begin(); Iter != dfmresources.end(); ++Iter) 162 | { 163 | printDfm(*Iter); 164 | } 165 | 166 | // std::for_each(dfmresources.begin(), dfmresources.end(), printDfm); 167 | } 168 | else 169 | { 170 | synchronize(dfmresources, vmtdir); 171 | obfuscate(dfmresources, vmtdir); 172 | store(filename, dfmresources, vmtdir, pefile); 173 | } 174 | } 175 | catch(const std::string& e) 176 | { 177 | die(e); 178 | } 179 | 180 | if ( !printInformation ) 181 | { 182 | std::cout << "Everything seems to have worked. Try to start the obfuscated file now." << std::endl; 183 | } 184 | 185 | return EXIT_SUCCESS; 186 | } 187 | else 188 | { 189 | die("Error: File does not seem to be a valid Delphi file."); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /pythia.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 25 | 28 | 31 | 34 | 37 | 40 | 54 | 57 | 60 | 63 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 96 | 97 | 105 | 108 | 111 | 114 | 117 | 120 | 130 | 133 | 136 | 139 | 150 | 153 | 156 | 159 | 162 | 165 | 168 | 171 | 174 | 175 | 176 | 177 | 178 | 179 | 184 | 187 | 188 | 191 | 192 | 195 | 196 | 199 | 200 | 203 | 204 | 207 | 208 | 211 | 212 | 213 | 218 | 221 | 222 | 225 | 226 | 229 | 230 | 233 | 234 | 237 | 238 | 241 | 242 | 243 | 248 | 249 | 250 | 251 | 252 | 253 | -------------------------------------------------------------------------------- /helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * helpers.h - Proof of concept for a Delphi Obfuscator 3 | * 4 | * Copyright (c) 2005 Sebastian Porst (webmaster@the-interweb.com) 5 | * All rights reserved. 6 | * 7 | * This software is licensed under the zlib/libpng License. 8 | * For more details see http://www.opensource.org/licenses/zlib-license.php 9 | */ 10 | 11 | #ifndef HELPERS_H 12 | #define HELPERS_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "VMTDir.h" 21 | 22 | /// Prints an error message and terminates the program. 23 | void die(const std::string& error); 24 | 25 | /** 26 | * Performs non-case sensitive string comparison. 27 | * @param s1 The first string. 28 | * @param s2 The second string. 29 | * @return Indicates whether or not the strings were equal. 30 | **/ 31 | template 32 | bool cmpncs(T s1, T s2) 33 | { 34 | std::transform(s1.begin(), s1.end(), s1.begin(), (int(*)(int)) toupper); 35 | std::transform(s2.begin(), s2.end(), s2.begin(), (int(*)(int)) toupper); 36 | 37 | return s1 == s2; 38 | } 39 | 40 | /** 41 | * Returns the complete length of a property name. 42 | * @param name The name. 43 | * @return The length of the name. 44 | **/ 45 | template 46 | unsigned int propertyNameLength(const T& name) 47 | { 48 | // Names of n segments are separated by n - 1 period characters. 49 | unsigned int ret = name.size() ? static_cast(name.size()) - 1 : 0; 50 | 51 | for (size_t i=0;i(name[i]->length()); 54 | } 55 | 56 | return ret; 57 | } 58 | 59 | /** 60 | * Used to determine whether or not a character is a character that can 61 | * appear in a Pascal string. 62 | **/ 63 | struct ValidCharacter 64 | { 65 | static bool isInvalid(unsigned char c) 66 | { 67 | return std::isalnum(c) == false && c != '.' && c != '_'; 68 | } 69 | }; 70 | 71 | /** 72 | * Determines whether a string only contains valid characters. 73 | * @param str The string to check. 74 | * @return True if the string contains only valid characters. 75 | **/ 76 | template 77 | bool verifyPascalString(const std::string& str) 78 | { 79 | return std::find_if(str.begin(), str.end(), T::isInvalid) == str.end(); 80 | } 81 | 82 | /** 83 | * Reads a Pascal-style string from a buffer. 84 | * @param beg Pointer to the beginning of a P-String. 85 | * @return The data of the P-String. 86 | **/ 87 | template 88 | std::string readPascalString(const unsigned char* beg) 89 | { 90 | std::stringstream ss; 91 | T len = *(T*)beg; 92 | beg += sizeof(T); 93 | for (unsigned int i=0;i 107 | std::string toHexString(T x) 108 | { 109 | std::stringstream ss; 110 | ss << std::hex << std::uppercase << x; 111 | return ss.str(); 112 | } 113 | 114 | /** 115 | * Produces a random letter or number. 116 | **/ 117 | struct RandomCharacterGenerator 118 | { 119 | char operator()() 120 | { 121 | unsigned int randValue = rand() % 62; 122 | 123 | if (randValue <= 9) return '0' + randValue; 124 | else if (randValue <= 35) return 'A' + randValue - 10; 125 | else return 'a' + randValue - 36; 126 | } 127 | }; 128 | 129 | /** 130 | * Generates a random string of the given size. It's guaranteed that the first 131 | * character of the string is a letter. 132 | * @param maxsize Size of the string. 133 | * @return A random string 134 | **/ 135 | template 136 | std::string randomString(unsigned int size) 137 | { 138 | if (!size) return ""; 139 | 140 | std::string ret(size, (char)('A' + rand() % 26)); 141 | 142 | std::generate(ret.begin() + 1, ret.end(), T()); 143 | 144 | return ret; 145 | } 146 | 147 | /** 148 | * Makes sure that all generated random strings are unique. 149 | * @param Size of the random string to generate. 150 | * @return A random string of the given size. 151 | **/ 152 | template 153 | std::string uniqueString(unsigned int size) 154 | { 155 | if (size == 0) return ""; 156 | 157 | static std::set strings; 158 | 159 | // Make 20 attempts to generate a unique string. 160 | for (unsigned int i=0;i<20;++i) 161 | { 162 | std::string retstr = randomString(size); 163 | 164 | if (strings.find(retstr) == strings.end()) 165 | { 166 | strings.insert(retstr); 167 | return retstr; 168 | } 169 | } 170 | 171 | throw std::string("Error: Cannot create enough unique strings."); 172 | } 173 | #include 174 | template 175 | struct FindByName 176 | { 177 | static bool compare(T val, const std::string& classname) 178 | { 179 | // std::cout << "Comparing to " << *val->name << std::endl; 180 | return *val->name == classname; 181 | } 182 | }; 183 | 184 | /** 185 | * Searches through a container. 186 | * @param cont The container. 187 | * @param value The value to find. 188 | * @param The value if the search was succesful. 0 otherwise. 189 | **/ 190 | template