├── bin ├── vulnapp-input-normal.txt ├── msvcr71.dll ├── ropguard.exe ├── ropguard.pdb ├── vulnapp.exe ├── vulnapp.pdb ├── ropguarddll.dll ├── ropguarddll.pdb ├── vulnapp-input-rop.txt ├── ropsettings-frames.txt └── ropsettings.txt ├── doc ├── ropguard.doc └── ropguard.pdf ├── ropguard ├── ropguard.suo ├── stdafx.cpp ├── stdafx.h ├── targetver.h ├── ropguard.sln ├── ReadMe.txt ├── ropguard.cpp └── ropguard.vcproj ├── vulnapp ├── vulnapp.suo ├── stdafx.cpp ├── stdafx.h ├── targetver.h ├── vulnapp.sln ├── vulnapp.cpp ├── ReadMe.txt └── vulnapp.vcproj ├── common ├── patching.h ├── patchentrypoint.h ├── ropcheck.h ├── x86opcodes.h ├── createprocess.h ├── ropsettings.h ├── patchentrypoint.cpp ├── patching.cpp ├── createprocess.cpp ├── ropsettings.cpp ├── ropcheck.cpp └── x86opcodes.cpp ├── ropguarddll ├── ropguarddll.suo ├── stdafx.cpp ├── stdafx.h ├── ropguarddll.sln ├── ropguarddll.cpp ├── targetver.h ├── ReadMe.txt └── ropguarddll.vcproj └── README.txt /bin/vulnapp-input-normal.txt: -------------------------------------------------------------------------------- 1 | test 123 -------------------------------------------------------------------------------- /bin/msvcr71.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/bin/msvcr71.dll -------------------------------------------------------------------------------- /bin/ropguard.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/bin/ropguard.exe -------------------------------------------------------------------------------- /bin/ropguard.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/bin/ropguard.pdb -------------------------------------------------------------------------------- /bin/vulnapp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/bin/vulnapp.exe -------------------------------------------------------------------------------- /bin/vulnapp.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/bin/vulnapp.pdb -------------------------------------------------------------------------------- /doc/ropguard.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/doc/ropguard.doc -------------------------------------------------------------------------------- /doc/ropguard.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/doc/ropguard.pdf -------------------------------------------------------------------------------- /bin/ropguarddll.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/bin/ropguarddll.dll -------------------------------------------------------------------------------- /bin/ropguarddll.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/bin/ropguarddll.pdb -------------------------------------------------------------------------------- /ropguard/ropguard.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/ropguard/ropguard.suo -------------------------------------------------------------------------------- /vulnapp/vulnapp.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/vulnapp/vulnapp.suo -------------------------------------------------------------------------------- /bin/vulnapp-input-rop.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/bin/vulnapp-input-rop.txt -------------------------------------------------------------------------------- /common/patching.h: -------------------------------------------------------------------------------- 1 | //patches all critical functions as defined in the configuration 2 | int PatchFunctions(); -------------------------------------------------------------------------------- /ropguarddll/ropguarddll.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanfratric/ropguard/HEAD/ropguarddll/ropguarddll.suo -------------------------------------------------------------------------------- /common/patchentrypoint.h: -------------------------------------------------------------------------------- 1 | //patches the entry point of the main thread to go into infinite loop 2 | //dll is injected when this loop is reached, 3 | //after which the old entry point data is restored 4 | int PatchEntryPoint(HANDLE proc, HANDLE thread, char *dllName); -------------------------------------------------------------------------------- /ropguard/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ropguard.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /vulnapp/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // vulnapp.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /ropguarddll/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ropguarddll.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /ropguard/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | -------------------------------------------------------------------------------- /vulnapp/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | -------------------------------------------------------------------------------- /ropguarddll/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | 15 | 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /common/ropcheck.h: -------------------------------------------------------------------------------- 1 | #define EXEC_PROTECTION (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) 2 | 3 | 4 | // the main function that performs the check, called in the prologue of every critical function 5 | // functionAddress - the original address of the critical function, used to determine what function are we in 6 | // registers - an array containing the register values in the moment of critical function call 7 | void __stdcall ROPCheck(unsigned long functionAddress, unsigned long *registers); 8 | 9 | //creates the executable memory cache and a mutex which guards it 10 | void InitCacheData(); 11 | -------------------------------------------------------------------------------- /ropguard/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // The following macros define the minimum required platform. The minimum required platform 4 | // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 5 | // your application. The macros work by enabling all features available on platform versions up to and 6 | // including the version specified. 7 | 8 | // Modify the following defines if you have to target a platform prior to the ones specified below. 9 | // Refer to MSDN for the latest info on corresponding values for different platforms. 10 | #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. 11 | #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /vulnapp/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // The following macros define the minimum required platform. The minimum required platform 4 | // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 5 | // your application. The macros work by enabling all features available on platform versions up to and 6 | // including the version specified. 7 | 8 | // Modify the following defines if you have to target a platform prior to the ones specified below. 9 | // Refer to MSDN for the latest info on corresponding values for different platforms. 10 | #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. 11 | #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /vulnapp/vulnapp.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vulnapp", "vulnapp.vcproj", "{E47F5020-1455-49F9-A2A6-69F430D8588F}" 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 | {E47F5020-1455-49F9-A2A6-69F430D8588F}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {E47F5020-1455-49F9-A2A6-69F430D8588F}.Debug|Win32.Build.0 = Debug|Win32 14 | {E47F5020-1455-49F9-A2A6-69F430D8588F}.Release|Win32.ActiveCfg = Release|Win32 15 | {E47F5020-1455-49F9-A2A6-69F430D8588F}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /ropguard/ropguard.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ropguard", "ropguard.vcproj", "{708B7403-940B-4950-BC16-B2AB2BEF8D8A}" 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 | {708B7403-940B-4950-BC16-B2AB2BEF8D8A}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {708B7403-940B-4950-BC16-B2AB2BEF8D8A}.Debug|Win32.Build.0 = Debug|Win32 14 | {708B7403-940B-4950-BC16-B2AB2BEF8D8A}.Release|Win32.ActiveCfg = Release|Win32 15 | {708B7403-940B-4950-BC16-B2AB2BEF8D8A}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /common/x86opcodes.h: -------------------------------------------------------------------------------- 1 | 2 | //decodes the instruction pointed to by eip and increases the eip accordingly 3 | //returns 0 on failure 4 | //instructions should be NULL (used for debugging only) 5 | int FollowInstruction(unsigned char *instructions, unsigned long *eip); 6 | 7 | //decodes the instruction pointed to by eip and simulates all changes made to the esp register 8 | //instructions should be NULL (used for debugging only) 9 | //retparam will contain a parameter value of RETN n instruction 10 | //returns 1 on success, 0 on failure and 2 if RETN instruction is encountered 11 | int SimulateStackInstruction(unsigned char *instructions, unsigned long *eip, unsigned long *esp, unsigned long *retparam); 12 | 13 | //checks if the target of indirect call instruction at callAddress is the same as functionAddres^key 14 | int CheckCallArguments(unsigned long functionAddress, unsigned long callAddress, unsigned long *registers, unsigned long returnAddress, unsigned long key); 15 | -------------------------------------------------------------------------------- /ropguarddll/ropguarddll.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ropguarddll", "ropguarddll.vcproj", "{D4CD253D-0224-44A8-9A99-157D5D38A40C}" 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 | {D4CD253D-0224-44A8-9A99-157D5D38A40C}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {D4CD253D-0224-44A8-9A99-157D5D38A40C}.Debug|Win32.Build.0 = Debug|Win32 14 | {D4CD253D-0224-44A8-9A99-157D5D38A40C}.Release|Win32.ActiveCfg = Release|Win32 15 | {D4CD253D-0224-44A8-9A99-157D5D38A40C}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /vulnapp/vulnapp.cpp: -------------------------------------------------------------------------------- 1 | // vulnapp.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include 5 | #include 6 | 7 | //reads file into buffer and prints it 8 | void printfile(char *filename) { 9 | char buf[64]; 10 | FILE *fp; 11 | int filesize; 12 | 13 | fp = fopen(filename,"r"); 14 | if(!fp) { 15 | printf("Error opening %s\n", filename); 16 | return; 17 | } 18 | 19 | fseek(fp, 0, SEEK_END); 20 | filesize = ftell(fp); 21 | fseek(fp, 0, SEEK_SET); 22 | 23 | //buffer overflow happens here 24 | fgets(buf, filesize+1, fp); 25 | 26 | fclose(fp); 27 | 28 | puts(buf); 29 | } 30 | 31 | int main(int argc, char* argv[]) 32 | { 33 | char buf[200]; //some local variables, making sure there is enough place on the stack for the paylaod 34 | for(int i=0;i<200;i++) buf[i] = 'b'; //use local variables so compiler won't remove them 35 | 36 | if(argc!=2) { 37 | printf("Usage: %s \n", argv[0]); 38 | return 0; 39 | } 40 | 41 | //needed for the rop payload 42 | if(!LoadLibrary("msvcr71.dll")) { 43 | printf("msvcr71.dll not found\n"); 44 | return 0; 45 | } 46 | 47 | //buffer overflow happens in this function 48 | printfile(argv[1]); 49 | 50 | if(buf[199]) { //use local variables so compiler won't remove them 51 | return 0; 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /ropguarddll/ropguarddll.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "stdafx.h" 3 | 4 | #include 5 | 6 | #include "ropsettings.h" 7 | #include "ropcheck.h" 8 | #include "patching.h" 9 | 10 | BOOL APIENTRY DllMain( HMODULE hModule, 11 | DWORD ul_reason_for_call, 12 | LPVOID lpReserved) 13 | { 14 | switch (ul_reason_for_call) 15 | { 16 | case DLL_PROCESS_ATTACH: 17 | case DLL_THREAD_ATTACH: 18 | case DLL_THREAD_DETACH: 19 | case DLL_PROCESS_DETACH: 20 | break; 21 | } 22 | return TRUE; 23 | } 24 | 25 | //-------------------------------------------------------------------------- 26 | class ROPGuard 27 | { 28 | public: 29 | //this code gets called when ROPGuard's dll is injected into a process 30 | ROPGuard() 31 | { 32 | // read settings 33 | ReadROPSettings(); 34 | 35 | // create executable memory cache if needed 36 | if (GetROPSettings()->executableModuleCache) 37 | InitCacheData(); 38 | 39 | // patch all critical functions 40 | PatchFunctions(); 41 | 42 | if (GetROPSettings()->showMessageBoxOnLoaded) 43 | MessageBoxA(NULL, "Successfully loaded ROPGuard dll into target process", "ROPGuard", MB_OK); 44 | } 45 | }; 46 | 47 | //-------------------------------------------------------------------------- 48 | //ROPGuard object 49 | ROPGuard h; 50 | -------------------------------------------------------------------------------- /vulnapp/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : vulnapp Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this vulnapp application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your vulnapp application. 9 | 10 | 11 | vulnapp.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | vulnapp.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named vulnapp.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /ropguard/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : ropguard Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this ropguard application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your ropguard application. 9 | 10 | 11 | ropguard.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | ropguard.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named ropguard.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /ropguarddll/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // The following macros define the minimum required platform. The minimum required platform 4 | // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 5 | // your application. The macros work by enabling all features available on platform versions up to and 6 | // including the version specified. 7 | 8 | // Modify the following defines if you have to target a platform prior to the ones specified below. 9 | // Refer to MSDN for the latest info on corresponding values for different platforms. 10 | #ifndef WINVER // Specifies that the minimum required platform is Windows Vista. 11 | #define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. 12 | #endif 13 | 14 | #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. 15 | #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. 16 | #endif 17 | 18 | #ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. 19 | #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. 20 | #endif 21 | 22 | #ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. 23 | #define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. 24 | #endif 25 | -------------------------------------------------------------------------------- /common/createprocess.h: -------------------------------------------------------------------------------- 1 | #ifndef __CREATEPROCESS__INC__ 2 | #define __CREATEPROCESS__INC__ 3 | 4 | // a function that will replace CreateProcessInternalW 5 | // needs to have the same prototype 6 | DWORD WINAPI CreateProcessInternalGuarded( 7 | __in DWORD unknown1, // always (?) NULL 8 | __in_opt LPCTSTR lpApplicationName, 9 | __inout_opt LPTSTR lpCommandLine, 10 | __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, 11 | __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, 12 | __in BOOL bInheritHandles, 13 | __in DWORD dwCreationFlags, 14 | __in_opt LPVOID lpEnvironment, 15 | __in_opt LPCTSTR lpCurrentDirectory, 16 | __in LPSTARTUPINFO lpStartupInfo, 17 | __out LPPROCESS_INFORMATION lpProcessInformation, 18 | __in DWORD unknown2 // always (?) NULL 19 | ); 20 | 21 | //stores the original address of CreateProcessInternalW 22 | void SetCreateProcessInternalOriginalPtr(unsigned long address); 23 | 24 | // DLL injection using CreateRemoteThread method 25 | // injects a DLL with path dllName into a process with handle proc 26 | int InjectDLL(HANDLE proc, char *dllName); 27 | 28 | // creates a new process with command given in commandLine and injects dll whose path is dllName into it 29 | int CreateProcessWithDll(char *commandLine, char *dllName, bool patchEntryPoint); 30 | 31 | // injects dll whose path is given in dllName into proces with PID pid 32 | int GuardExistingProcess(int pid, char *dllName); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | RUNTIME PREVENTION OF RETURN-ORIENTED PROGRAMMING ATTACKS 2 | 3 | ROPGuard is a system for runtime detection and prevention of return-oriented programming (ROP) attacks. It works by defining a set of checks that are performed when certain OS functions are called to determine if those functions are called from the ROP code or as a result of normal program execution. The system can be applied at runtime to any process and has a low CPU and memory overhead. The detailed project documentation can be found in the doc folder. 4 | 5 | ROPGuard won the second prize at the Microsoft's BlueHat Prize contest at Black Hat USA 2012 (https://www.microsoft.com/security/bluehatprize/). 6 | 7 | The code and other project files provided here are for educational purposes only. If you are interested in running ROPGuard to protect your computer, I recommend you download Microsoft EMET instead (http://www.microsoft.com/emet), as it implements protection mechanisms from ROPGuard (see: http://www.microsoft.com/en-us/news/Press/2012/Jul12/07-25BlueHatPrizePR.aspx), but also contains many reliability improvements and is actively maintained. I'd like to thank Elias Bachaalany of Microsoft for not only implementing ROPGuard technology into EMET but also improving it in every way. 8 | 9 | .\doc folder contains the documentation in .doc and .pdf format 10 | 11 | .\bin folders contains all executables and other files needed to run the prototype. Prototype usage is described in the documentation. 12 | 13 | .\ropguard, .\ropguarddll and .\common folders contain all the source and project files of the prototype 14 | 15 | .\vulnapp folder contains the source and the project files of an example vulnerable application used during the evaluation 16 | -------------------------------------------------------------------------------- /ropguarddll/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | DYNAMIC LINK LIBRARY : ropguarddll Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this ropguarddll DLL for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your ropguarddll application. 9 | 10 | 11 | ropguarddll.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | ropguarddll.cpp 18 | This is the main DLL source file. 19 | 20 | When created, this DLL does not export any symbols. As a result, it 21 | will not produce a .lib file when it is built. If you wish this project 22 | to be a project dependency of some other project, you will either need to 23 | add code to export some symbols from the DLL so that an export library 24 | will be produced, or you can set the Ignore Input Library property to Yes 25 | on the General propert page of the Linker folder in the project's Property 26 | Pages dialog box. 27 | 28 | ///////////////////////////////////////////////////////////////////////////// 29 | Other standard files: 30 | 31 | StdAfx.h, StdAfx.cpp 32 | These files are used to build a precompiled header (PCH) file 33 | named ropguarddll.pch and a precompiled types file named StdAfx.obj. 34 | 35 | ///////////////////////////////////////////////////////////////////////////// 36 | Other notes: 37 | 38 | AppWizard uses "TODO:" comments to indicate parts of the source code you 39 | should add to or customize. 40 | 41 | ///////////////////////////////////////////////////////////////////////////// 42 | -------------------------------------------------------------------------------- /ropguard/ropguard.cpp: -------------------------------------------------------------------------------- 1 | // ropguard.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | #include 7 | #include 8 | #include "createprocess.h" 9 | #include "ropsettings.h" 10 | 11 | #pragma warning(disable : 4996) 12 | 13 | //-------------------------------------------------------------------------- 14 | // prints the usage information 15 | void PrintUsage() 16 | { 17 | printf("Usage: ropguard \n"); 18 | printf(" ropguard \"\"\n"); 19 | } 20 | 21 | //-------------------------------------------------------------------------- 22 | // returns true if string is numeric 23 | bool IsNumeric(char *str) 24 | { 25 | int i, n = strlen(str); 26 | for(i=0;i'9')) 29 | return false; 30 | } 31 | return true; 32 | } 33 | 34 | extern ROPSettings *ropSettings; 35 | 36 | //-------------------------------------------------------------------------- 37 | // main program 38 | int _tmain(int argc, _TCHAR* argv[]) 39 | { 40 | if (argc<2) 41 | { 42 | PrintUsage(); 43 | return 0; 44 | } 45 | 46 | // get the full path of ropguarddll.dll 47 | char dllpath[1000]; 48 | char *filename; 49 | if (!GetModuleFileName(NULL, dllpath, 980)) 50 | { 51 | printf("Error: could not obtain current executable path\n"); 52 | return 0; 53 | } 54 | filename = strrchr(dllpath,'\\'); 55 | if(!filename) { 56 | printf("Error: could not obtain current executable path\n"); 57 | return 0; 58 | } 59 | filename++; 60 | strcpy(filename, "ropsettings.txt"); 61 | ropSettings = new ROPSettings(); 62 | ReadROPSettings(dllpath); 63 | strcpy(filename, "ropguarddll.dll"); 64 | 65 | 66 | //if the first argument is a number it's considered to be a PID 67 | if (IsNumeric(argv[1])) 68 | { 69 | //protect existing process 70 | GuardExistingProcess(atol(argv[1]), dllpath); 71 | } 72 | else 73 | { 74 | // create new protected process 75 | if (GetROPSettings()->waitEntryPoint) 76 | { 77 | CreateProcessWithDll(argv[1], dllpath, true); 78 | } 79 | else 80 | { 81 | CreateProcessWithDll(argv[1], dllpath, false); 82 | } 83 | } 84 | 85 | return 0; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /common/ropsettings.h: -------------------------------------------------------------------------------- 1 | #define ADDR_SCRAMBLE_KEY 0x55555555 2 | 3 | //stores information about a critical function 4 | struct ROPGuardedFunction { 5 | char moduleName[32]; //name of the module in which the function is implemented 6 | char functionName[64]; //name of the critical function to guard 7 | unsigned long originalAddress; //original address of the function in the module 8 | unsigned long patchedAddress; //address of the corresponding guarded function; 9 | int stackIncrement; 10 | bool criticalFunction; 11 | bool clearCache; 12 | }; 13 | 14 | //contains ROPGuard's configuration 15 | class ROPSettings { 16 | public: 17 | ROPSettings() { 18 | waitEntryPoint = true; 19 | 20 | showMessageBoxOnLoaded = true; 21 | 22 | executableModuleCache = true; 23 | 24 | checkFunctionAddressOnStack = true; 25 | preserveStack = 4; 26 | checkStackPointer = true; 27 | checkReturnAddress = true; 28 | checkCallTarget = false; 29 | allowIndirectCFCalls = true; 30 | allowFarCFCalls = true; 31 | checkStackFrames = false; 32 | maxStackFrames = 10; 33 | simulateProgramFlow = true; 34 | maxInstructionsToSimulate = 10; 35 | 36 | requireFramePointers = false; 37 | 38 | guardChildProcesses = true; 39 | 40 | preventLoadLibraryFromSMB = true; 41 | preventVirtualProtectOnStack = true; 42 | 43 | guardedFunctions = 0; 44 | numGuardedFunctions = 0; 45 | } 46 | 47 | //see example configuration file for explanation of different options 48 | bool showMessageBoxOnLoaded; 49 | bool executableModuleCache; 50 | 51 | bool checkFunctionAddressOnStack; 52 | unsigned long preserveStack; 53 | bool checkStackPointer; 54 | bool checkReturnAddress; 55 | bool checkCallTarget; 56 | bool allowIndirectCFCalls; 57 | bool allowFarCFCalls; 58 | bool checkStackFrames; 59 | bool requireFramePointers; 60 | unsigned long maxStackFrames; 61 | bool simulateProgramFlow; 62 | unsigned long maxInstructionsToSimulate; 63 | 64 | bool guardChildProcesses; 65 | bool preventLoadLibraryFromSMB; 66 | bool preventVirtualProtectOnStack; 67 | 68 | bool waitEntryPoint; 69 | 70 | ROPGuardedFunction *GetGuardedFunctions() { return guardedFunctions; } 71 | int GetNumGuardedFunctions() { return numGuardedFunctions; } 72 | 73 | //adds a critical function 74 | //moduleName : name of the module that contains the critical function 75 | //functionName : name of the critical function 76 | //stackIncrement : how many DWORDS does function take from the stack (-1 if don't know) 77 | //protect : if true, ROPCheck will be called whenever the function is called 78 | //clearCache : if true, when this function gets called, executable module cache will be cleared 79 | void AddFunction(const char *moduleName, const char *functionName, int stackIncrement, bool protect, bool clearCache); 80 | private: 81 | ROPGuardedFunction *guardedFunctions; 82 | int numGuardedFunctions; 83 | }; 84 | 85 | //reads and parses the settings file 86 | int ReadROPSettings(char *filename); 87 | 88 | //reads the settings from 'ropsettings.txt' file in the same folder as the loaded 'ropguarddll.dll' 89 | int ReadROPSettings(); 90 | 91 | //returns the number of critical functions 92 | int GetNumGuardedFunctions(); 93 | 94 | //returns the pointer to the array of ROPGuardedFunction objects that contain information about critical functions 95 | ROPGuardedFunction *GetGuardedFunctions(); 96 | 97 | //returns the ropSettings object 98 | ROPSettings *GetROPSettings(); 99 | -------------------------------------------------------------------------------- /common/patchentrypoint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "createprocess.h" 7 | 8 | //-------------------------------------------------------------------------- 9 | typedef NTSTATUS (NTAPI *pfnNtQueryInformationProcess)( 10 | IN HANDLE ProcessHandle, 11 | IN PROCESSINFOCLASS ProcessInformationClass, 12 | OUT PVOID ProcessInformation, 13 | IN ULONG ProcessInformationLength, 14 | OUT PULONG ReturnLength OPTIONAL); 15 | 16 | pfnNtQueryInformationProcess myNtQueryInformationProcess; 17 | 18 | //-------------------------------------------------------------------------- 19 | // Load NTDLL Library and get entry address 20 | // for NtQueryInformationProcess 21 | int LoadNTDLLFunctions() 22 | { 23 | HMODULE hNtDll = LoadLibrary("ntdll.dll"); 24 | if (hNtDll == NULL) 25 | return 0; 26 | 27 | myNtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess"); 28 | return myNtQueryInformationProcess == NULL ? 0 : 1; 29 | } 30 | 31 | //-------------------------------------------------------------------------- 32 | // helper functions and macros for parsing PE headers 33 | #define SIZE_OF_NT_SIGNATURE (sizeof(DWORD)) 34 | #define OPTHDROFFSET(ptr) ((LPVOID)((BYTE *)(ptr)+((PIMAGE_DOS_HEADER)(ptr))->e_lfanew+SIZE_OF_NT_SIGNATURE+sizeof(IMAGE_FILE_HEADER))) 35 | 36 | LPVOID WINAPI GetModuleEntryPoint( 37 | LPVOID lpFile) 38 | { 39 | PIMAGE_OPTIONAL_HEADER poh; 40 | poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile); 41 | return poh == NULL ? NULL :(LPVOID)poh->AddressOfEntryPoint; 42 | } 43 | 44 | //-------------------------------------------------------------------------- 45 | //returns the entry point of the main module of the process proc 46 | DWORD GetEntryPoint(HANDLE proc) 47 | { 48 | NTSTATUS ntret; 49 | PROCESS_BASIC_INFORMATION pbi; 50 | DWORD imagebase; 51 | DWORD enrypoint; 52 | 53 | //load NtQueryInformationProcess 54 | if(!LoadNTDLLFunctions()) 55 | return 0; 56 | 57 | //get peb address 58 | ntret = (*myNtQueryInformationProcess)(proc, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); 59 | if (ntret!=0) 60 | return 0; 61 | 62 | // get base address of module 63 | if (!ReadProcessMemory(proc, (LPCVOID)((DWORD)(pbi.PebBaseAddress) + 8),&imagebase, sizeof(imagebase), NULL)) 64 | return 0; 65 | 66 | //read PE header 67 | unsigned char *pe = new unsigned char[4096]; //whole memory page should be quite enough 68 | if (!ReadProcessMemory(proc, (LPCVOID)(imagebase),pe, 4096, NULL)) 69 | { 70 | delete [] pe; 71 | return 0; 72 | } 73 | 74 | enrypoint = imagebase + (DWORD)(GetModuleEntryPoint((LPVOID)pe)); 75 | delete [] pe; 76 | 77 | return enrypoint; 78 | } 79 | 80 | //-------------------------------------------------------------------------- 81 | // patches the entry point of the main thread to go into infinite loop 82 | // dll is injected when this loop is reached, 83 | // after which the old entry point data is restored 84 | int PatchEntryPoint(HANDLE proc, HANDLE thread, char *dllName) 85 | { 86 | DWORD entryPoint; 87 | DWORD oldProtect1,oldProtect2; 88 | unsigned char oldHeader[2]; 89 | unsigned char newHeader[2]; 90 | CONTEXT context; 91 | 92 | entryPoint = GetEntryPoint(proc); 93 | 94 | if (!entryPoint) 95 | { 96 | printf("Error getting entry point\n"); 97 | return 0; 98 | } 99 | 100 | // make entry point writeable 101 | VirtualProtectEx(proc, (LPVOID)entryPoint, 2, PAGE_EXECUTE_READWRITE, &oldProtect1); 102 | 103 | //store 2 bytes from entry point 104 | if (!ReadProcessMemory(proc, (LPCVOID)(entryPoint),oldHeader, 2, NULL)) 105 | { 106 | printf("Error reading data from entry point"); 107 | return 0; 108 | } 109 | 110 | // JMP -2 111 | newHeader[0] = 0xEB; 112 | newHeader[1] = 0xFE; 113 | 114 | // patch entry point to go into infinite loop 115 | if (!WriteProcessMemory(proc, (LPVOID)(entryPoint),newHeader, 2, NULL)) 116 | { 117 | printf("Error writing to entry point"); 118 | return 0; 119 | } 120 | 121 | ResumeThread(thread); 122 | 123 | // wait until entry point is reached 124 | while (true) 125 | { 126 | Sleep(100); 127 | 128 | context.ContextFlags = CONTEXT_CONTROL; 129 | GetThreadContext(thread, &context); 130 | 131 | if (context.Eip == entryPoint) 132 | break; 133 | } 134 | 135 | InjectDLL(proc, dllName); 136 | 137 | SuspendThread(thread); 138 | 139 | // return original code to entry point 140 | if (!WriteProcessMemory(proc, (LPVOID)(entryPoint),oldHeader, 2, NULL)) 141 | { 142 | printf("Error writing to entry point"); 143 | return 0; 144 | } 145 | 146 | // restore protection 147 | VirtualProtectEx(proc, (LPVOID)entryPoint, 2, oldProtect1, &oldProtect2); 148 | 149 | return 1; 150 | } 151 | -------------------------------------------------------------------------------- /vulnapp/vulnapp.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 54 | 57 | 60 | 63 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 92 | 100 | 103 | 106 | 109 | 112 | 115 | 128 | 131 | 134 | 137 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 168 | 169 | 170 | 171 | 172 | 177 | 180 | 181 | 184 | 185 | 186 | 191 | 194 | 195 | 198 | 199 | 200 | 205 | 206 | 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /bin/ropsettings-frames.txt: -------------------------------------------------------------------------------- 1 | #Show message box once ROPguard has been loaded into target process and protection enabled 2 | ShowMessageBoxOnLoaded = true 3 | 4 | #checks if the stack pointer points to the stack of the current thread 5 | CheckStackPointer = true 6 | 7 | #looks for the address of of the guarded function on stack just above its return address 8 | CheckFunctionAddressOnStack = false 9 | 10 | #the amount of stack in bytes to preserve for the checkFunctionAddressOnStack (should be multiple of 4) 11 | PreserveStack = 4 12 | 13 | #checks if the return address is executable and if the return address is preceeded with a call instruction 14 | CheckReturnAddress = true 15 | 16 | #Checks if the target of call instruction preceeding the current return address is the same as the address of current critical function 17 | CheckCallTarget = false 18 | 19 | #Allows indirect calls to critical functions 20 | AllowIndirectCFCalls = true 21 | 22 | #Allows far calls to critical functions 23 | AllowFarCFCalls = true 24 | 25 | #performs a series of checks for each stack frame, see documentation 26 | CheckStackFrames = true 27 | 28 | #requires that the frame pointers are used throughout the code 29 | #if at some point EBP is not used as a frame pointer, an alert will be raised 30 | RequireFramePointers = false 31 | 32 | #maximum number of stack frames to traverse 33 | MaxStackFrames = 10 34 | 35 | #Simulate program flow after the RETN from critical function 36 | SimulateProgramFlow = true 37 | 38 | #How many instructions to simulate 39 | MaxInstructionsToSimulate = 10 40 | 41 | #if a guarded process spawns a child process, guard this process as well 42 | GuardChildProcesses = true 43 | 44 | #Prevents loading a library over SMB 45 | PreventLoadLibraryFromSMB = true 46 | 47 | #Prevents changing access rights of the stack 48 | PreventVirtualProtectOnStack = true 49 | 50 | #functions that will be guarded in the form of module_name:function_name:stackIncrement 51 | #stackIncrement indicates for how many DWORDS will the function increment stack pointer before returning 52 | #For functions where the callee cleans the stack, this number is usually the number of functions Parameters 53 | #For functions where the caller cleans the stack, this number is usually 0 54 | #By putting -1 as stackIncrement (or just using module_name:function_name) you will skip simulation for that instruction 55 | ProtectFunction = kernel32.dll:VirtualProtect:4 56 | ProtectFunction = kernel32.dll:VirtualProtectEx:5 57 | ProtectFunction = kernel32.dll:VirtualAlloc:4 58 | ProtectFunction = kernel32.dll:VirtualAllocEx:5 59 | ProtectFunction = kernel32.dll:HeapCreate:3 60 | ProtectFunction = ntdll.dll:RtlCreateHeap:6 61 | ProtectFunction = kernel32.dll:CreateProcessInternalW:12 62 | ProtectFunction = kernel32.dll:LoadLibraryExW:3 63 | ProtectFunction = kernel32.dll:CreateRemoteThread:7 64 | ProtectFunction = kernel32.dll:WriteProcessMemory:5 65 | 66 | #filesystem functions 67 | ProtectFunction = kernel32.dll:CreateFileW:7 68 | ProtectFunction = kernel32.dll:WriteFile:5 69 | ProtectFunction = kernel32.dll:WriteFileEx:5 70 | 71 | #registry functions 72 | ProtectFunction = advapi32.dll:RegOpenKeyA:3 73 | ProtectFunction = advapi32.dll:RegOpenKeyW:3 74 | ProtectFunction = advapi32.dll:RegOpenKeyExA:5 75 | ProtectFunction = advapi32.dll:RegOpenKeyExW:5 76 | ProtectFunction = advapi32.dll:RegCreateKeyA:3 77 | ProtectFunction = advapi32.dll:RegCreateKeyW:3 78 | ProtectFunction = advapi32.dll:RegCreateKeyExA:9 79 | ProtectFunction = advapi32.dll:RegCreateKeyExW:9 80 | ProtectFunction = advapi32.dll:RegSetValueA:5 81 | ProtectFunction = advapi32.dll:RegSetValueW:5 82 | ProtectFunction = advapi32.dll:RegSetValueExA:6 83 | ProtectFunction = advapi32.dll:RegSetValueExW:6 84 | 85 | #the functions below could also be considered critical, 86 | #however they do not exist prior to Windows 7 (CreateRemoteThreadEx) or Vista (RegSetKeyValue) 87 | #so they have been commented out for compatibility reasons (otherwise, a warning will be shown on older systems) 88 | #If you are running ROPGuard on Windows 7, uncomment the lines below 89 | #ProtectFunction = kernel32.dll:CreateRemoteThreadEx:8 90 | #ProtectFunction = advapi32.dll:RegSetKeyValueA:6 91 | #ProtectFunction = advapi32.dll:RegSetKeyValueW:6 92 | 93 | 94 | #Enable caching of executable module addresses 95 | #By caching executable module information, 96 | #calling VirtualQuery on each critical function is avioded 97 | #and the overall performance is increased 98 | ExecutableModuleCache = true 99 | 100 | #When one of these functions gets called, executable module cache is cleared 101 | ClearCache = kernel32.dll:VirtualFree 102 | ClearCache = kernel32.dll:VirtualFreeEx 103 | ClearCache = kernel32.dll:HeapDestroy 104 | ClearCache = ntdll.dll:RtlDestroyHeap 105 | ClearCache = kernel32.dll:VirtualProtect 106 | ClearCache = kernel32.dll:VirtualProtectEx 107 | 108 | 109 | #Controls the dll injection method when starting a new protected process 110 | #If false, process is created in suspended state after which the dll is immediately injected 111 | #If true, process is created in suspended state, its entry point is patched to be stuck in infinite loop 112 | #After the entry point is reached the dll is injected and the entry point is "unstuck" thus resuming the normal execution 113 | #The 'false' option is simpler but fails when starting a GUI application on some older systems 114 | WaitEntryPoint = true 115 | -------------------------------------------------------------------------------- /ropguard/ropguard.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 69 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 91 | 99 | 102 | 105 | 108 | 111 | 114 | 126 | 129 | 132 | 135 | 144 | 147 | 150 | 153 | 156 | 159 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 175 | 178 | 179 | 182 | 183 | 186 | 187 | 190 | 191 | 194 | 195 | 196 | 201 | 204 | 205 | 208 | 209 | 212 | 213 | 216 | 217 | 220 | 221 | 222 | 227 | 228 | 231 | 232 | 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /bin/ropsettings.txt: -------------------------------------------------------------------------------- 1 | #Show message box once ROPguard has been loaded into target process and protection enabled 2 | ShowMessageBoxOnLoaded = true 3 | 4 | #checks if the stack pointer points to the stack of the current thread 5 | CheckStackPointer = true 6 | 7 | #looks for the address of of the guarded function on stack just above its return address 8 | CheckFunctionAddressOnStack = false 9 | 10 | #the amount of stack in bytes to preserve for the checkFunctionAddressOnStack (should be multiple of 4) 11 | PreserveStack = 4 12 | 13 | #checks if the return address is executable and if the return address is preceeded with a call instruction 14 | CheckReturnAddress = true 15 | 16 | #Checks if the target of call instruction preceeding the current return address is the same as the address of current critical function 17 | CheckCallTarget = false 18 | 19 | #Allows indirect calls to critical functions 20 | AllowIndirectCFCalls = true 21 | 22 | #Allows far calls to critical functions 23 | AllowFarCFCalls = true 24 | 25 | #performs a series of checks for each stack frame, see documentation 26 | CheckStackFrames = false 27 | 28 | #requires that the frame pointers are used throughout the code 29 | #if at some point EBP is not used as a frame pointer, an alert will be raised 30 | RequireFramePointers = false 31 | 32 | #maximum number of stack frames to traverse 33 | MaxStackFrames = 10 34 | 35 | #Simulate program flow after the RETN from critical function 36 | SimulateProgramFlow = true 37 | 38 | #How many instructions to simulate 39 | MaxInstructionsToSimulate = 10 40 | 41 | #if a guarded process spawns a child process, guard this process as well 42 | GuardChildProcesses = true 43 | 44 | #Prevents loading a library over SMB 45 | PreventLoadLibraryFromSMB = true 46 | 47 | #Prevents changing access rights of the stack 48 | PreventVirtualProtectOnStack = true 49 | 50 | #functions that will be guarded in the form of module_name:function_name:stackIncrement 51 | #stackIncrement indicates for how many DWORDS will the function increment stack pointer before returning 52 | #For functions where the callee cleans the stack, this number is usually the number of functions Parameters 53 | #For functions where the caller cleans the stack, this number is usually 0 54 | #By putting -1 as stackIncrement (or just using module_name:function_name) you will skip simulation for that instruction 55 | ProtectFunction = kernel32.dll:VirtualProtect:4 56 | ProtectFunction = kernel32.dll:VirtualProtectEx:5 57 | ProtectFunction = kernel32.dll:VirtualAlloc:4 58 | ProtectFunction = kernel32.dll:VirtualAllocEx:5 59 | ProtectFunction = kernel32.dll:HeapCreate:3 60 | ProtectFunction = ntdll.dll:RtlCreateHeap:6 61 | ProtectFunction = kernel32.dll:CreateProcessA:10 62 | ProtectFunction = kernel32.dll:CreateProcessW:10 63 | ProtectFunction = kernel32.dll:CreateProcessInternalA:12 64 | ProtectFunction = kernel32.dll:CreateProcessInternalW:12 65 | ProtectFunction = kernel32.dll:LoadLibraryA:1 66 | ProtectFunction = kernel32.dll:LoadLibraryW:1 67 | ProtectFunction = kernel32.dll:LoadLibraryExA:3 68 | ProtectFunction = kernel32.dll:LoadLibraryExW:3 69 | ProtectFunction = kernel32.dll:CreateRemoteThread:7 70 | ProtectFunction = kernel32.dll:WriteProcessMemory:5 71 | 72 | #filesystem functions 73 | ProtectFunction = kernel32.dll:CreateFileA:7 74 | ProtectFunction = kernel32.dll:CreateFileW:7 75 | ProtectFunction = kernel32.dll:WriteFile:5 76 | ProtectFunction = kernel32.dll:WriteFileEx:5 77 | 78 | #registry functions 79 | ProtectFunction = advapi32.dll:RegOpenKeyA:3 80 | ProtectFunction = advapi32.dll:RegOpenKeyW:3 81 | ProtectFunction = advapi32.dll:RegOpenKeyExA:5 82 | ProtectFunction = advapi32.dll:RegOpenKeyExW:5 83 | ProtectFunction = advapi32.dll:RegCreateKeyA:3 84 | ProtectFunction = advapi32.dll:RegCreateKeyW:3 85 | ProtectFunction = advapi32.dll:RegCreateKeyExA:9 86 | ProtectFunction = advapi32.dll:RegCreateKeyExW:9 87 | ProtectFunction = advapi32.dll:RegSetValueA:5 88 | ProtectFunction = advapi32.dll:RegSetValueW:5 89 | ProtectFunction = advapi32.dll:RegSetValueExA:6 90 | ProtectFunction = advapi32.dll:RegSetValueExW:6 91 | 92 | #the functions below could also be considered critical, 93 | #however they do not exist prior to Windows 7 (CreateRemoteThreadEx) or Vista (RegSetKeyValue) 94 | #so they have been commented out for compatibility reasons (otherwise, a warning will be shown on older systems) 95 | #If you are running ROPGuard on Windows 7, uncomment the lines below 96 | #ProtectFunction = kernel32.dll:CreateRemoteThreadEx:8 97 | #ProtectFunction = advapi32.dll:RegSetKeyValueA:6 98 | #ProtectFunction = advapi32.dll:RegSetKeyValueW:6 99 | 100 | 101 | #Enable caching of executable module addresses 102 | #By caching executable module information, 103 | #calling VirtualQuery on each critical function is avioded 104 | #and the overall performance is increased 105 | ExecutableModuleCache = true 106 | 107 | #When one of these functions gets called, executable module cache is cleared 108 | ClearCache = kernel32.dll:VirtualFree 109 | ClearCache = kernel32.dll:VirtualFreeEx 110 | ClearCache = kernel32.dll:HeapDestroy 111 | ClearCache = ntdll.dll:RtlDestroyHeap 112 | ClearCache = kernel32.dll:VirtualProtect 113 | ClearCache = kernel32.dll:VirtualProtectEx 114 | 115 | 116 | #Controls the dll injection method when starting a new protected process 117 | #If false, process is created in suspended state after which the dll is immediately injected 118 | #If true, process is created in suspended state, its entry point is patched to be stuck in infinite loop 119 | #After the entry point is reached the dll is injected and the entry point is "unstuck" thus resuming the normal execution 120 | #The 'false' option is simpler but fails when starting a GUI application on some older systems 121 | WaitEntryPoint = true 122 | -------------------------------------------------------------------------------- /ropguarddll/ropguarddll.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 54 | 57 | 60 | 63 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 92 | 100 | 103 | 106 | 109 | 112 | 115 | 128 | 131 | 134 | 137 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 168 | 169 | 170 | 171 | 172 | 177 | 180 | 181 | 184 | 185 | 188 | 189 | 192 | 193 | 196 | 197 | 200 | 201 | 204 | 207 | 211 | 212 | 215 | 219 | 220 | 221 | 224 | 225 | 226 | 231 | 234 | 235 | 238 | 239 | 242 | 243 | 246 | 247 | 250 | 251 | 254 | 255 | 258 | 259 | 262 | 263 | 264 | 269 | 270 | 273 | 274 | 275 | 276 | 277 | 278 | -------------------------------------------------------------------------------- /common/patching.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ropsettings.h" 5 | #include "x86opcodes.h" 6 | #include "ropcheck.h" 7 | #include "createprocess.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | //-------------------------------------------------------------------------- 16 | // patch a critical function, replacing its prologue with the jump to patch prologue that calls ROPCheck 17 | // moduleName : name of the module that contains the critical function 18 | // functionName : name of the critical function 19 | // originalAddress : here the original address of critical function will be stored 20 | // patchcode : a pointer to executable memory that will contain the patched function prologue 21 | int PatchFunction(char *moduleName, char *functionName, unsigned long *originalAddress, unsigned char *patchcode) 22 | { 23 | unsigned long functionAddress, patchHeaderEnd; 24 | unsigned int i; 25 | DWORD oldProtect, newProtect; 26 | 27 | //get the address of function to be patched 28 | functionAddress = (unsigned long)GetProcAddress(GetModuleHandle(moduleName), functionName); 29 | if (!functionAddress) 30 | { 31 | stringstream errorreport; 32 | errorreport << "Warning: Could not get address of " << moduleName << ":" << functionName; 33 | MessageBoxA(NULL, errorreport.str().c_str(), "ROPGuard", MB_OK); 34 | return 0; 35 | } 36 | 37 | //don't patch same function twice 38 | unsigned int numFunctions = GetNumGuardedFunctions(); 39 | ROPGuardedFunction *guardedFunctions = GetGuardedFunctions(); 40 | for (i=0;ipreserveStack; 71 | patchcode[6] = 0x60; //PUSHAD 72 | patchcode[7] = 0x54; //PUSH ESP 73 | patchcode[8] = 0x68; //PUSH functionAddress 74 | *((unsigned long *)(&(patchcode[9]))) = functionAddress^ADDR_SCRAMBLE_KEY; //scramble functionAddress so that it wouldn't confuse ropcheck later 75 | patchcode[13] = 0xE8; //CALL ROPCheck 76 | *((unsigned long *)(&(patchcode[14]))) = (unsigned long)(&ROPCheck) - (unsigned long)(&(patchcode[18])); 77 | patchcode[18] = 0x81; //ADD ESP, PRESERVE_STACK + space taken by PUSHAD 78 | patchcode[19] = 0xC4; 79 | *((unsigned long *)(&(patchcode[20]))) = (GetROPSettings()->preserveStack + 8*4); 80 | 81 | if ( (strcmp(functionName, "CreateProcessInternalW") !=0 ) || (!GetROPSettings()->guardChildProcesses) ) 82 | { 83 | for (i=0;iexecutableModuleCache)&&(!guardedFunctions[i].criticalFunction)) continue; 155 | 156 | //patch function 157 | ret = PatchFunction(guardedFunctions[i].moduleName, 158 | guardedFunctions[i].functionName, 159 | &(guardedFunctions[i].originalAddress), 160 | &(patchcode[patchsizeused])); 161 | if (ret) 162 | { 163 | guardedFunctions[i].originalAddress = guardedFunctions[i].originalAddress^ADDR_SCRAMBLE_KEY; 164 | guardedFunctions[i].patchedAddress = (unsigned long)(&(patchcode[patchsizeused])); 165 | patchsizeused += 100; 166 | } 167 | else 168 | { 169 | guardedFunctions[i].originalAddress = 0; 170 | } 171 | } 172 | 173 | // protect the patch code from writing 174 | VirtualProtect(patchcode, patchcodesize, PAGE_EXECUTE_READ, &oldProtect); 175 | 176 | // enable protection 177 | protectionEnabled = true; 178 | 179 | return 1; 180 | }; 181 | -------------------------------------------------------------------------------- /common/createprocess.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "createprocess.h" 4 | #include "patchentrypoint.h" 5 | #include "ropsettings.h" 6 | 7 | //-------------------------------------------------------------------------- 8 | // function pointer to unpatched CreateProcessInternalW 9 | typedef DWORD (WINAPI *proto_CreateProcessInternalOriginal)( 10 | __in DWORD unknown1, // always (?) NULL 11 | __in_opt LPCTSTR lpApplicationName, 12 | __inout_opt LPTSTR lpCommandLine, 13 | __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, 14 | __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, 15 | __in BOOL bInheritHandles, 16 | __in DWORD dwCreationFlags, 17 | __in_opt LPVOID lpEnvironment, 18 | __in_opt LPCTSTR lpCurrentDirectory, 19 | __in LPSTARTUPINFO lpStartupInfo, 20 | __out LPPROCESS_INFORMATION lpProcessInformation, 21 | __in DWORD unknown2 // always (?) NULL 22 | ); 23 | 24 | proto_CreateProcessInternalOriginal CreateProcessInternalOriginal; 25 | 26 | //-------------------------------------------------------------------------- 27 | //stores the original address of CreateProcessInternalW 28 | void SetCreateProcessInternalOriginalPtr(unsigned long address) 29 | { 30 | CreateProcessInternalOriginal = (proto_CreateProcessInternalOriginal)address; 31 | } 32 | 33 | //-------------------------------------------------------------------------- 34 | //DLL injection using CreateRemoteThread method 35 | //injects a DLL with path dllName into a process with handle proc 36 | int InjectDLL(HANDLE proc, char *dllName) 37 | { 38 | LPVOID RemoteString, LoadLibAddy; 39 | 40 | if (!proc) 41 | return 0; 42 | 43 | LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); 44 | 45 | RemoteString = (LPVOID)VirtualAllocEx(proc, NULL, strlen(dllName)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 46 | WriteProcessMemory(proc, (LPVOID)RemoteString, dllName, strlen(dllName)+1, NULL); 47 | HANDLE hThread = CreateRemoteThread( 48 | proc, 49 | NULL, 50 | NULL, 51 | (LPTHREAD_START_ROUTINE)LoadLibAddy, 52 | (LPVOID)RemoteString, 53 | NULL, 54 | NULL); 55 | 56 | if (hThread == INVALID_HANDLE_VALUE) 57 | { 58 | MessageBoxA(NULL, "Error creating remote thread", "ROPGuard", MB_OK); 59 | return 0; 60 | } 61 | 62 | WaitForSingleObject(hThread, INFINITE); 63 | 64 | // Cleanup 65 | VirtualFreeEx(proc, RemoteString, strlen(dllName)+1, MEM_RELEASE); 66 | CloseHandle(hThread); 67 | 68 | return 1; 69 | } 70 | 71 | //-------------------------------------------------------------------------- 72 | // injects dll whose path is given in dllName into process with PID pid 73 | int GuardExistingProcess(int pid, char *dllName) 74 | { 75 | HANDLE proc; 76 | 77 | proc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_READ |PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION , FALSE, pid); 78 | if (!proc) 79 | { 80 | printf("Error opening process %d, error code %d\n", pid, GetLastError()); 81 | return 0; 82 | } 83 | 84 | BOOL parent64,child64; 85 | IsWow64Process(GetCurrentProcess(),&parent64); 86 | IsWow64Process(proc, &child64); 87 | if(parent64 != child64) 88 | { 89 | MessageBoxA(NULL, "Current version of ROPGuard cannot protect 64-bit processes.\nThe process will NOT be protected.", "ROPGuard", MB_OK); 90 | } 91 | else 92 | { 93 | InjectDLL(proc, dllName); 94 | } 95 | 96 | CloseHandle(proc); 97 | 98 | return 1; 99 | } 100 | 101 | //-------------------------------------------------------------------------- 102 | // creates a new process with command given in commandLine and injects dll whose path is dllName into it 103 | int CreateProcessWithDll( 104 | char *commandLine, 105 | char *dllName, 106 | bool patchEntryPoint) 107 | { 108 | STARTUPINFO startupinfo; 109 | PROCESS_INFORMATION processinfo; 110 | 111 | ZeroMemory(&startupinfo, sizeof(startupinfo)); 112 | startupinfo.cb = sizeof(startupinfo); 113 | ZeroMemory(&processinfo, sizeof(processinfo)); 114 | 115 | if (!CreateProcess(NULL, commandLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupinfo, &processinfo)) 116 | { 117 | printf("Error creating process (%d)\n", GetLastError()); 118 | return 0; 119 | } 120 | 121 | BOOL parent64,child64; 122 | IsWow64Process(GetCurrentProcess(), &parent64); 123 | IsWow64Process(processinfo.hProcess, &child64); 124 | if (parent64 != child64) 125 | { 126 | MessageBoxA(NULL, 127 | "Current version of ROPGuard cannot protect 64-bit processes.\n" 128 | "The process will NOT be protected.", 129 | "ROPGuard", MB_OK); 130 | } 131 | else 132 | { 133 | if (patchEntryPoint) 134 | PatchEntryPoint(processinfo.hProcess, processinfo.hThread, dllName); 135 | else 136 | InjectDLL(processinfo.hProcess, dllName); 137 | } 138 | 139 | // resume normal execution 140 | ResumeThread(processinfo.hThread); 141 | 142 | // cleanup 143 | CloseHandle(processinfo.hThread); 144 | CloseHandle(processinfo.hProcess); 145 | 146 | return 1; 147 | } 148 | 149 | #ifndef STDALONE 150 | //-------------------------------------------------------------------------- 151 | // a function that will replace CreateProcessInternalW 152 | // gets called whenever a process creates a child process 153 | DWORD WINAPI CreateProcessInternalGuarded( 154 | __in DWORD unknown1, // always (?) NULL 155 | __in_opt LPCTSTR lpApplicationName, 156 | __inout_opt LPTSTR lpCommandLine, 157 | __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, 158 | __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, 159 | __in BOOL bInheritHandles, 160 | __in DWORD dwCreationFlags, 161 | __in_opt LPVOID lpEnvironment, 162 | __in_opt LPCTSTR lpCurrentDirectory, 163 | __in LPSTARTUPINFO lpStartupInfo, 164 | __out LPPROCESS_INFORMATION lpProcessInformation, 165 | __in DWORD unknown2 // always (?) NULL 166 | ) 167 | { 168 | DWORD ret; 169 | DWORD newCreationFlags; 170 | //MessageBoxA(NULL, "Creating new process", "ROPGuard", MB_OK); 171 | 172 | //start new process in suspended state to inject dll into it 173 | newCreationFlags = dwCreationFlags | CREATE_SUSPENDED; 174 | 175 | ret = (*CreateProcessInternalOriginal)(unknown1, 176 | lpApplicationName, 177 | lpCommandLine, 178 | lpProcessAttributes, 179 | lpThreadAttributes, 180 | bInheritHandles, 181 | newCreationFlags, 182 | lpEnvironment, 183 | lpCurrentDirectory, 184 | lpStartupInfo, 185 | lpProcessInformation, 186 | unknown2); 187 | 188 | if(!ret) 189 | return ret; 190 | 191 | BOOL parent64,child64; 192 | IsWow64Process(GetCurrentProcess(),&parent64); 193 | IsWow64Process(lpProcessInformation->hProcess,&child64); 194 | if (parent64 != child64) 195 | { 196 | //MessageBoxA(NULL, "Current version of ROPGuard cannot protect 64-bit processes.\nThe process will NOT be protected.", "ROPGuard", MB_OK); 197 | if((dwCreationFlags&CREATE_SUSPENDED)==0) 198 | ResumeThread(lpProcessInformation->hThread); 199 | return ret; 200 | } 201 | 202 | //get the path of the ropguard dll 203 | char dllpath[1000]; 204 | HMODULE dllhandle; 205 | dllhandle = GetModuleHandle("ropguarddll.dll"); 206 | if((!dllhandle) || (!GetModuleFileName(dllhandle, dllpath, _countof(dllpath)-1))) 207 | { 208 | MessageBoxA(NULL, "Warning: could not obtain ropguarddll path", "ROPGuard", MB_OK); 209 | if((dwCreationFlags&CREATE_SUSPENDED)==0) ResumeThread(lpProcessInformation->hThread); 210 | return ret; 211 | } 212 | //MessageBoxA(NULL, dllpath, "ROPGuard", MB_OK); 213 | 214 | // inject ropguard dll into the newly created process 215 | if (((dwCreationFlags&CREATE_SUSPENDED)==0)&&(GetROPSettings()->waitEntryPoint)) 216 | { 217 | PatchEntryPoint(lpProcessInformation->hProcess, lpProcessInformation->hThread, dllpath); 218 | } 219 | else 220 | { 221 | InjectDLL(lpProcessInformation->hProcess, dllpath); 222 | } 223 | 224 | //resume process if necessary 225 | if((dwCreationFlags&CREATE_SUSPENDED)==0) 226 | ResumeThread(lpProcessInformation->hThread); 227 | 228 | return ret; 229 | } 230 | #endif -------------------------------------------------------------------------------- /common/ropsettings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ropsettings.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | #pragma warning(disable : 4996) 12 | 13 | //-------------------------------------------------------------------------- 14 | //contains ROPGuard's configuration 15 | ROPSettings *ropSettings; 16 | 17 | //-------------------------------------------------------------------------- 18 | //returns the ropSettings object 19 | ROPSettings *GetROPSettings() 20 | { 21 | return ropSettings; 22 | } 23 | 24 | //-------------------------------------------------------------------------- 25 | int GetNumGuardedFunctions() 26 | { 27 | //return sizeof(guardedFunctions)/sizeof(ROPGuardedFunction); 28 | return ropSettings->GetNumGuardedFunctions(); 29 | } 30 | 31 | ROPGuardedFunction *GetGuardedFunctions() 32 | { 33 | //return guardedFunctions; 34 | return ropSettings->GetGuardedFunctions(); 35 | } 36 | 37 | //adds a critical function 38 | //moduleName : name of the module that contains the critical function 39 | //functionName : name of the critical function 40 | //stackIncrement : how many DWORDS does function take from the stack (-1 if don't know) 41 | //protect : if true, ROPCheck will be called whenever the function is called 42 | //clearCache : if true, when this function gets called, executable module cache will be cleared 43 | void ROPSettings::AddFunction(const char *moduleName, const char *functionName, int stackIncrement, bool protect, bool clearCache) 44 | { 45 | for(int i=0;i> result)) result = 0; 80 | return result; 81 | } 82 | 83 | //-------------------------------------------------------------------------- 84 | //converts string to boolean value 85 | bool ParseBool(string &s) 86 | { 87 | if(s == "true") return true; 88 | return false; 89 | } 90 | 91 | //-------------------------------------------------------------------------- 92 | //erases spaces from the beginning and the end of a string 93 | void trim(string &s) 94 | { 95 | s.erase(0,s.find_first_not_of(" \n\r\t")); 96 | s.erase(s.find_last_not_of(" \n\r\t")+1); 97 | } 98 | 99 | //-------------------------------------------------------------------------- 100 | //parse settings file 101 | int ReadROPSettings(char *filename) 102 | { 103 | string line, varname, varvalue, errorreport; 104 | int pos; 105 | ifstream settingsfile (filename); 106 | if (!settingsfile.is_open()) 107 | { 108 | MessageBoxA(NULL, "Could not read settings file, protection will NOT be enabled", "ROPGuard", MB_OK); 109 | return 0; 110 | } 111 | 112 | while (settingsfile.good()) 113 | { 114 | getline(settingsfile, line); 115 | 116 | // skip empty and comment lines 117 | if (line.empty() || line[0] == '#') 118 | continue; 119 | 120 | pos = line.find_first_of('='); 121 | if (pos == -1) 122 | continue; 123 | 124 | varname = line.substr(0,pos); 125 | varvalue = line.substr(pos+1); 126 | trim(varname); 127 | trim(varvalue); 128 | 129 | if (varname == "ShowMessageBoxOnLoaded") 130 | ropSettings->showMessageBoxOnLoaded = ParseBool(varvalue); 131 | else if (varname == "WaitEntryPoint") ropSettings->waitEntryPoint = ParseBool(varvalue); 132 | else if(varname == "ExecutableModuleCache") ropSettings->executableModuleCache = ParseBool(varvalue); 133 | else if(varname == "CheckFunctionAddressOnStack") 134 | ropSettings->checkFunctionAddressOnStack = ParseBool(varvalue); 135 | else if(varname == "CheckStackPointer") ropSettings->checkStackPointer = ParseBool(varvalue); 136 | else if(varname == "CheckReturnAddress") ropSettings->checkReturnAddress = ParseBool(varvalue); 137 | else if(varname == "CheckCallTarget") ropSettings->checkCallTarget = ParseBool(varvalue); 138 | else if(varname == "AllowIndirectCFCalls") ropSettings->allowIndirectCFCalls = ParseBool(varvalue); 139 | else if(varname == "AllowFarCFCalls") ropSettings->allowFarCFCalls = ParseBool(varvalue); 140 | else if(varname == "CheckStackFrames") ropSettings->checkStackFrames = ParseBool(varvalue); 141 | else if(varname == "RequireFramePointers") 142 | ropSettings->requireFramePointers = ParseBool(varvalue); 143 | else if(varname == "SimulateProgramFlow") 144 | ropSettings->simulateProgramFlow = ParseBool(varvalue); 145 | else if(varname == "PreserveStack") 146 | ropSettings->preserveStack = ParseInt(varvalue); 147 | else if(varname == "MaxStackFrames") 148 | ropSettings->maxStackFrames = ParseInt(varvalue); 149 | else if(varname == "MaxInstructionsToSimulate") 150 | ropSettings->maxInstructionsToSimulate = ParseInt(varvalue); 151 | else if(varname == "GuardChildProcesses") 152 | ropSettings->guardChildProcesses = ParseBool(varvalue); 153 | else if(varname == "PreventLoadLibraryFromSMB") 154 | ropSettings->preventLoadLibraryFromSMB = ParseBool(varvalue); 155 | else if(varname == "PreventVirtualProtectOnStack") 156 | ropSettings->preventVirtualProtectOnStack = ParseBool(varvalue); 157 | else if((varname == "ProtectFunction")||(varname == "ClearCache")) 158 | { 159 | string moduleName, functionName; 160 | int stackIncrement = -1; 161 | bool protect = false; 162 | bool cache = false; 163 | 164 | pos = varvalue.find_first_of(':'); 165 | if (pos == -1) 166 | { 167 | errorreport = "Error parsing line in the configuration file: " + line; 168 | MessageBoxA(NULL, errorreport.c_str(), "ROPGuard", MB_OK); 169 | continue; 170 | } 171 | 172 | moduleName = varvalue.substr(0,pos); 173 | functionName = varvalue.substr(pos+1); 174 | trim(moduleName); 175 | trim(functionName); 176 | 177 | pos = functionName.find_first_of(':'); 178 | if (pos>=0) 179 | { 180 | string stackIncrementStr; 181 | stackIncrementStr = functionName.substr(pos+1); 182 | functionName.erase(pos); 183 | trim(functionName); 184 | trim(stackIncrementStr); 185 | stackIncrement = ParseInt(stackIncrementStr); 186 | } 187 | 188 | if (moduleName.length() > 31) 189 | { 190 | MessageBoxA(NULL, "Error parsing configuration file: Module name must have less than 32 characters", "ROPGuard", MB_OK); 191 | continue; 192 | } 193 | 194 | if (functionName.length() > 63) 195 | { 196 | MessageBoxA(NULL, "Error parsing configuration file: Function name must have less than 64 characters", "ROPGuard", MB_OK); 197 | continue; 198 | } 199 | 200 | if (varname == "ProtectFunction") 201 | protect = true; 202 | if (varname == "ClearCache") 203 | cache = true; 204 | ropSettings->AddFunction(moduleName.c_str(), functionName.c_str(), stackIncrement, protect, cache); 205 | } 206 | else 207 | { 208 | errorreport = "Error parsing line in the configuration file: " + line; 209 | MessageBoxA(NULL, errorreport.c_str(), "ROPGuard", MB_OK); 210 | continue; 211 | } 212 | } 213 | 214 | settingsfile.close(); 215 | return 1; 216 | } 217 | 218 | //-------------------------------------------------------------------------- 219 | //read ropsettings.txt file in the same folder as ropguarddll.dll 220 | int ReadROPSettings() 221 | { 222 | //create ROPSettings object 223 | ropSettings = new ROPSettings(); 224 | 225 | //get the path of the ropguard dll 226 | char fullpath[1000]; 227 | char *filename; 228 | HMODULE dllhandle; 229 | dllhandle = GetModuleHandle("ropguarddll.dll"); 230 | if((!dllhandle) || (!GetModuleFileName(dllhandle, fullpath, 999))) 231 | { 232 | MessageBoxA(NULL, "Warning: could not obtain ropguarddll path", "ROPGuard", MB_OK); 233 | return 0; 234 | } 235 | 236 | filename = strrchr(fullpath,'\\'); 237 | 238 | if(!filename) { 239 | MessageBoxA(NULL, "Warning: could not obtain ropsettings path", "ROPGuard", MB_OK); 240 | return 0; 241 | } 242 | 243 | filename++; 244 | 245 | strcpy(filename, "ropsettings.txt"); 246 | 247 | return ReadROPSettings(fullpath); 248 | } 249 | -------------------------------------------------------------------------------- /common/ropcheck.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ropsettings.h" 5 | #include "x86opcodes.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | #include "ropcheck.h" 13 | #include 14 | 15 | //-------------------------------------------------------------------------- 16 | //contains a beginning and an end address of an executable part of memory 17 | struct ExecutableModule 18 | { 19 | unsigned long start; 20 | unsigned long end; 21 | }; 22 | 23 | //-------------------------------------------------------------------------- 24 | // executable memory cache 25 | vector *executableModules; 26 | CRITICAL_SECTION cacheMutex; 27 | 28 | //-------------------------------------------------------------------------- 29 | // creates the executable memory cache and a mutex which guards it 30 | void InitCacheData() 31 | { 32 | executableModules = new vector; 33 | InitializeCriticalSection(&cacheMutex); 34 | } 35 | 36 | //-------------------------------------------------------------------------- 37 | // Shows a message box to the user informing him of possible attack 38 | // The user can either terminate the process or continue the execution normally 39 | void ReportPossibleROP(string &report) 40 | { 41 | string messageboxtext; 42 | messageboxtext = "ROPGuard has detected a possible threat.\n" 43 | "Press OK to terminate the current process.\n" 44 | "Press Cancel or ESC key to continue the execution normally\n\n" 45 | "Problem details:\n" + report; 46 | 47 | if(MessageBoxA(NULL, messageboxtext.c_str(), "ROPGuard", MB_OKCANCEL) == IDOK) 48 | { 49 | exit(0); 50 | } 51 | } 52 | 53 | //-------------------------------------------------------------------------- 54 | // Gets the top and bottom address of the stack 55 | void GetStackInfo(unsigned long *stackBottom, unsigned long *stackTop) 56 | { 57 | char *TIB = (char *) __readfsdword(0x18); 58 | *stackTop = *((unsigned long *)(TIB+4)); 59 | *stackBottom = *((unsigned long *)(TIB+8)); 60 | } 61 | 62 | //-------------------------------------------------------------------------- 63 | //checks if a memory address is executable 64 | int IsAddressExecutable(LPCVOID address) 65 | { 66 | bool cache = GetROPSettings()->executableModuleCache; 67 | 68 | if (cache) 69 | { 70 | EnterCriticalSection(&cacheMutex); 71 | for (unsigned int i=0; isize(); i++) 72 | { 73 | ExecutableModule &em = (*executableModules)[i]; 74 | if ((((unsigned long)address)>=em.start)&&(((unsigned long)address)push_back(newmodule); 96 | LeaveCriticalSection(&cacheMutex); 97 | } 98 | return 1; 99 | } 100 | 101 | return 0; 102 | } 103 | 104 | //-------------------------------------------------------------------------- 105 | // checks if the instruction preceding the one pointed by address is a call instruction 106 | int PrecededByCall(unsigned char *address) 107 | { 108 | int i; 109 | 110 | // check for call opcodes 111 | if (*(address-5) == 0xE8) 112 | return 1; 113 | 114 | if (*(address-3) == 0xE8) 115 | return 1; 116 | 117 | if(*(address-5) == 0x9A) 118 | return 1; 119 | 120 | if (*(address-7) == 0x9A) 121 | return 1; 122 | 123 | // FF opcode 124 | for (i=2;i<8;i++) 125 | { 126 | if ((*(address-i) == 0xFF) && (((*(address-i+1))&0x38)==0x10)) 127 | return 1; 128 | } 129 | 130 | for (i=2;i<10;i++) 131 | { 132 | if ((*(address-i) == 0xFF) && (((*(address-i+1))&0x38)==0x18)) 133 | return 1; 134 | } 135 | 136 | return 0; 137 | } 138 | 139 | //-------------------------------------------------------------------------- 140 | // checks if the instruction preceding the one pointed by address is a call instruction 141 | // unlike PrecededByCall, this function can disallow dome forms of call 142 | int CFPrecededByCall(unsigned char *address) 143 | { 144 | int i; 145 | 146 | //check for call opcodes 147 | if (*(address-5) == 0xE8) 148 | return 1; 149 | 150 | if (*(address-3) == 0xE8) 151 | return 1; 152 | 153 | if (GetROPSettings()->allowFarCFCalls) 154 | { 155 | if (*(address-5) == 0x9A) 156 | return 1; 157 | if (*(address-7) == 0x9A) 158 | return 1; 159 | } 160 | 161 | // FF opcode 162 | if(GetROPSettings()->allowIndirectCFCalls) 163 | { 164 | for(i=2;i<8;i++) 165 | { 166 | if((*(address-i) == 0xFF) && (((*(address-i+1))&0x38)==0x10)) 167 | return 1; 168 | } 169 | 170 | if(GetROPSettings()->allowFarCFCalls) 171 | { 172 | for(i=2;i<10;i++) 173 | { 174 | if((*(address-i) == 0xFF) && (((*(address-i+1))&0x38)==0x18)) 175 | return 1; 176 | } 177 | } 178 | } 179 | 180 | return 0; 181 | } 182 | 183 | //-------------------------------------------------------------------------- 184 | //checks if the target of the call instruction preceding returnAddress is the same as cfAddress^ADDR_SCRAMBLE_KEY 185 | int CheckCallTarget( 186 | unsigned char *returnAddress, 187 | unsigned long *registers, unsigned long cfAddress) 188 | { 189 | int i; 190 | 191 | // direct call 192 | unsigned long callAddress; 193 | if (*(returnAddress-5) == 0xE8) 194 | { 195 | callAddress = (long)(returnAddress) + *((long *)(returnAddress-4)); 196 | if(callAddress == (cfAddress^ADDR_SCRAMBLE_KEY)) 197 | return 1; 198 | 199 | if (IsAddressExecutable((LPCVOID)callAddress)) 200 | { 201 | if((*((unsigned char *)(callAddress)) == 0xFF)&&(*((unsigned char *)(callAddress+1)) == 0x25)) 202 | { 203 | callAddress = *((unsigned long *)(callAddress+2)); 204 | callAddress = *((unsigned long *)(callAddress)); 205 | if(callAddress == (cfAddress^ADDR_SCRAMBLE_KEY)) 206 | return 1; 207 | } 208 | } 209 | } 210 | 211 | if (*(returnAddress-3) == 0xE8) 212 | { 213 | callAddress = (long)(returnAddress) + *((short *)(returnAddress-2)); 214 | if(callAddress == (cfAddress^ADDR_SCRAMBLE_KEY)) 215 | return 1; 216 | 217 | if (IsAddressExecutable((LPCVOID)callAddress)) 218 | { 219 | if ((*((unsigned char *)(callAddress)) == 0xFF) && (*((unsigned char *)(callAddress+1)) == 0x25)) 220 | { 221 | callAddress = *((unsigned long *)(callAddress+2)); 222 | callAddress = *((unsigned long *)(callAddress)); 223 | if(callAddress == (cfAddress^ADDR_SCRAMBLE_KEY)) 224 | return 1; 225 | } 226 | } 227 | } 228 | 229 | // direct far call 230 | if(GetROPSettings()->allowFarCFCalls) 231 | { 232 | if(*(returnAddress-5) == 0x9A) 233 | return 1; 234 | if(*(returnAddress-7) == 0x9A) 235 | return 1; 236 | } 237 | 238 | // indirect call 239 | if (GetROPSettings()->allowIndirectCFCalls) 240 | { 241 | for(i=2;i<8;i++) 242 | { 243 | if (CheckCallArguments(cfAddress, (unsigned long)(returnAddress-i), registers, (unsigned long)(returnAddress), ADDR_SCRAMBLE_KEY) == 1) 244 | { 245 | return 1; 246 | } 247 | } 248 | 249 | //indirect far call 250 | if(GetROPSettings()->allowFarCFCalls) 251 | { 252 | for (i=2;i<10;i++) 253 | { 254 | if ((*(returnAddress-i) == 0xFF) && (((*(returnAddress-i+1))&0x38)==0x18)) 255 | return 1; 256 | } 257 | } 258 | } 259 | 260 | return 0; 261 | } 262 | 263 | //-------------------------------------------------------------------------- 264 | // Performs checks on the return address of the critical function 265 | int CFCheckReturnAddress(DWORD returnAddress, DWORD functionAddress, DWORD *registers) 266 | { 267 | // Is return address executable? 268 | if (!IsAddressExecutable((LPCVOID)returnAddress)) 269 | { 270 | stringstream errorreport; 271 | errorreport << "Return address is not executable.\nReturn address: "; 272 | errorreport << std::hex << returnAddress; 273 | ReportPossibleROP(errorreport.str()); 274 | return 0; 275 | } 276 | 277 | // is return address preceded by call? 278 | if (!CFPrecededByCall((unsigned char *)returnAddress)) 279 | { 280 | stringstream errorreport; 281 | errorreport << "Return address not preceded by call.\nReturn address: "; 282 | errorreport << std::hex << returnAddress; 283 | ReportPossibleROP(errorreport.str()); 284 | return 0; 285 | } 286 | 287 | // is the target of call instruction preceeding the return address the same as the address of critical function? 288 | if ( (GetROPSettings()->checkCallTarget) 289 | && (!CheckCallTarget((unsigned char *)returnAddress, registers, functionAddress))) 290 | { 291 | stringstream errorreport; 292 | errorreport << "Call target is not the same as the function address.\nReturn address: "; 293 | errorreport << std::hex << returnAddress; 294 | ReportPossibleROP(errorreport.str()); 295 | return 0; 296 | } 297 | return 1; 298 | } 299 | 300 | //-------------------------------------------------------------------------- 301 | // performs checks on the return address of any function 302 | int CheckReturnAddress(DWORD returnAddress) 303 | { 304 | //is return address executable? 305 | if (!IsAddressExecutable((LPCVOID)returnAddress)) 306 | { 307 | stringstream errorreport; 308 | errorreport << "Return address is not executable.\n" 309 | "Return address: "; 310 | errorreport << std::hex << returnAddress; 311 | ReportPossibleROP(errorreport.str()); 312 | return 0; 313 | } 314 | 315 | // is return address preceded by call? 316 | if (!PrecededByCall((unsigned char *)returnAddress)) 317 | { 318 | stringstream errorreport; 319 | errorreport << "Return address not preceded by call.\n" 320 | "Return address: "; 321 | errorreport << std::hex << returnAddress; 322 | ReportPossibleROP(errorreport.str()); 323 | return 0; 324 | } 325 | return 1; 326 | } 327 | 328 | //-------------------------------------------------------------------------- 329 | // performs the checks on the stack frames below the frame of the critical function 330 | int CheckStackFrames(DWORD *stackPtr, DWORD *framePtr) 331 | { 332 | DWORD *returnAddress; 333 | DWORD *newFramePtr; 334 | DWORD *originalFramePtr; 335 | 336 | unsigned long stackBottom, stackTop; 337 | GetStackInfo(&stackBottom, &stackTop); 338 | 339 | originalFramePtr = framePtr; 340 | 341 | //frame pointer must point to the stack 342 | if (((unsigned long)framePtrstackTop)) 343 | { 344 | if (GetROPSettings()->requireFramePointers) 345 | { 346 | stringstream errorreport; 347 | errorreport << "Return address not preceded by call. Frame pointer:\n"; 348 | errorreport << std::hex << (unsigned long)framePtr; 349 | ReportPossibleROP(errorreport.str()); 350 | return 0; 351 | } 352 | else 353 | { 354 | return 1; 355 | } 356 | } 357 | 358 | // frame pointer must be "below" the stack pointer 359 | if (((unsigned long)framePtr)<((unsigned long)stackPtr)) 360 | { 361 | stringstream errorreport; 362 | errorreport << "Frame pointer is above stack pointer on stack"; 363 | errorreport << " Stack pointer: " << std::hex << (unsigned long)stackPtr; 364 | errorreport << " Frame pointer: " << std::hex << (unsigned long)framePtr; 365 | ReportPossibleROP(errorreport.str()); 366 | return 0; 367 | } 368 | 369 | for (unsigned int i=0; imaxStackFrames; i++) 370 | { 371 | newFramePtr = (DWORD *)(*(framePtr)); 372 | returnAddress = (DWORD *)(*(framePtr+1)); 373 | 374 | if(!returnAddress) 375 | break; 376 | 377 | // is return address executable? 378 | if (!IsAddressExecutable(returnAddress)) 379 | { 380 | stringstream errorreport; 381 | errorreport << "Return address is not executable."; 382 | errorreport << " Return address: " << std::hex << (unsigned long)returnAddress; 383 | errorreport << " Frame pointer: " << std::hex << (unsigned long)framePtr; 384 | errorreport << " Original frame pointer: " << std::hex << (unsigned long)originalFramePtr; 385 | ReportPossibleROP(errorreport.str()); 386 | return 0; 387 | } 388 | 389 | // is return address preceded by call? 390 | if(!PrecededByCall((unsigned char *)returnAddress)) 391 | { 392 | stringstream errorreport; 393 | errorreport << "Return address not preceded by call."; 394 | errorreport << " Return address: " << std::hex << (unsigned long)returnAddress; 395 | errorreport << " Frame pointer: " << std::hex << (unsigned long)framePtr; 396 | errorreport << " Original frame pointer: " << std::hex << (unsigned long)originalFramePtr; 397 | ReportPossibleROP(errorreport.str()); 398 | return 0; 399 | } 400 | 401 | // is the new frame pointer on stack? 402 | if (((unsigned long)newFramePtrstackTop)) 403 | { 404 | if(GetROPSettings()->requireFramePointers) 405 | { 406 | stringstream errorreport; 407 | errorreport << "Frame pointer is outside of stack."; 408 | errorreport << " Frame pointer: " << std::hex << (unsigned long)framePtr; 409 | errorreport << " Original frame pointer: " << std::hex << (unsigned long)originalFramePtr; 410 | ReportPossibleROP(errorreport.str()); 411 | return 0; 412 | } 413 | else 414 | { 415 | return 1; 416 | } 417 | } 418 | 419 | //is the new frame pointer "below" the old one? 420 | if((unsigned long)newFramePtr <= (unsigned long)framePtr) { 421 | if(GetROPSettings()->requireFramePointers) { 422 | stringstream errorreport; 423 | errorreport << "Next frame pointer is not below the previous one on stack."; 424 | errorreport << " Frame pointer: " << std::hex << (unsigned long)framePtr; 425 | errorreport << " Original frame pointer: " << std::hex << (unsigned long)originalFramePtr; 426 | ReportPossibleROP(errorreport.str()); 427 | return 0; 428 | } else { 429 | return 1; 430 | } 431 | } 432 | 433 | framePtr = newFramePtr; 434 | } 435 | 436 | return 1; 437 | } 438 | 439 | //-------------------------------------------------------------------------- 440 | //check if the current stack pointer is in a valid location, as indicated by thread information block 441 | int CheckStackPointer(unsigned long stackPtr) 442 | { 443 | unsigned long stackBottom, stackTop; 444 | GetStackInfo(&stackBottom, &stackTop); 445 | 446 | if ((stackPtrstackTop)) 447 | { 448 | stringstream errorreport; 449 | errorreport << "Stack pointer is outside of stack. Stack address:\n"; 450 | errorreport << std::hex << stackPtr; 451 | ReportPossibleROP(errorreport.str()); 452 | return 0; 453 | } 454 | 455 | return 1; 456 | } 457 | 458 | //-------------------------------------------------------------------------- 459 | // checks if the address of protected function is on the stack just above the current return address 460 | // if it is, this could mean that we "returned into" the beginning of critical function instead of calling it 461 | int CheckFunctionAddressOnStack( 462 | unsigned long functionAddress, 463 | unsigned long *stack) 464 | { 465 | int i,n; 466 | n = (GetROPSettings()->preserveStack)/sizeof(unsigned long); 467 | 468 | for (i=0;imaxInstructionsToSimulate; 493 | 494 | returnAddress = *((unsigned long *)stackPtr); 495 | stackPtr += stackIncrement + 4; 496 | 497 | eip = returnAddress; 498 | for (int i=0; iexecutableModuleCache) 568 | { 569 | if (currentFunction->clearCache) 570 | { 571 | EnterCriticalSection(&cacheMutex); 572 | executableModules->clear(); 573 | LeaveCriticalSection(&cacheMutex); 574 | } 575 | if (!currentFunction->criticalFunction) 576 | return; 577 | } 578 | 579 | /* 580 | if(strcmp(currentFunction->functionName,"CreateProcessInternalW")==0) 581 | { 582 | MessageBoxA(NULL, "Creating new process", "ROPGuard", MB_OK); 583 | } 584 | */ 585 | 586 | if (GetROPSettings()->checkFunctionAddressOnStack) 587 | { 588 | if (!CheckFunctionAddressOnStack( 589 | functionAddress, 590 | (unsigned long *)stackPointer)) 591 | { 592 | return; 593 | } 594 | } 595 | 596 | // Check if ESP is in the thread's original stack space (defined in the TIB) 597 | if (GetROPSettings()->checkStackPointer) 598 | { 599 | if (!CheckStackPointer(stackPointer + GetROPSettings()->preserveStack)) 600 | return; 601 | } 602 | 603 | // Check if return address is proceeded by a call (to the target) 604 | if (GetROPSettings()->checkReturnAddress) 605 | { 606 | DWORD returnAddress = *((DWORD *)(stackPointer + GetROPSettings()->preserveStack)); 607 | if (!CFCheckReturnAddress(returnAddress, functionAddress, registers)) 608 | return; 609 | } 610 | 611 | // Check stack frames 612 | if (GetROPSettings()->checkStackFrames) 613 | { 614 | if (!CheckStackFrames( 615 | (DWORD *)(stackPointer + GetROPSettings()->preserveStack), 616 | (DWORD *)framePointer)) 617 | { 618 | return; 619 | } 620 | } 621 | 622 | // Simulate program flow 623 | if ((GetROPSettings()->simulateProgramFlow) && (currentFunction->stackIncrement>=0)) 624 | { 625 | SimulateProgramFlow( 626 | stackPointer + GetROPSettings()->preserveStack, 627 | currentFunction->stackIncrement * 4); 628 | } 629 | 630 | // 631 | // function-specific protections 632 | // 633 | 634 | // prevent loading a library over SMB 635 | if ( (GetROPSettings()->preventLoadLibraryFromSMB) 636 | && (strcmp(currentFunction->functionName, "LoadLibraryExW")==0)) 637 | { 638 | char *dllname = (char *)(*((DWORD *)(stackPointer + GetROPSettings()->preserveStack + 4))); 639 | if ((dllname[0] == '\\')&&(dllname[2] == '\\')) 640 | { 641 | if (!((dllname[4] == '?') && (dllname[6] == '\\'))) 642 | { 643 | stringstream errorreport; 644 | errorreport << "Program attempted to load a DLL over SMB\n"; 645 | errorreport << "Stack pointer: " << std::hex << stackPointer << "\n"; 646 | errorreport << "Function address: " << std::hex << (functionAddress^ADDR_SCRAMBLE_KEY) << "\n"; 647 | 648 | int dllnamesize = wcslen((LPCWSTR)dllname); 649 | char * dllname2 = new char[dllnamesize+1]; 650 | WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)dllname, dllnamesize, dllname2, dllnamesize, NULL, NULL); 651 | dllname2[dllnamesize] = 0; 652 | errorreport << "Library name: " << dllname2; 653 | delete [] dllname2; 654 | 655 | ReportPossibleROP(errorreport.str()); 656 | return; 657 | } 658 | } 659 | } 660 | 661 | // prevent changing access rights of stack 662 | if (GetROPSettings()->preventVirtualProtectOnStack) do 663 | { 664 | DWORD address; 665 | if (strcmp(currentFunction->functionName,"VirtualProtect")==0) 666 | address = *((DWORD *)(stackPointer + GetROPSettings()->preserveStack + 4)); 667 | else if (strcmp(currentFunction->functionName, "VirtualProtectEx")==0) 668 | address = address = *((DWORD *)(stackPointer + GetROPSettings()->preserveStack + 8)); 669 | else 670 | break; 671 | 672 | DWORD stackBottom, stackTop; 673 | GetStackInfo(&stackBottom, &stackTop); 674 | if ((address>=stackBottom) && (address 2 | 3 | //-------------------------------------------------------------------------- 4 | // contains informations on the x86 instructions 5 | struct x86opcode 6 | { 7 | unsigned char opcode; 8 | char type; //instruction type, 1:register or memoty operands (mod/reg/r/m field), 2:prefix 9 | char jump; //determins if it is a call or jump instruction, 0:no, 1:call(or other functions to be ignored), 2:conditional jump, 3:unconditional jump 10 | char argSize; //size of the function's arguments 11 | char stackChange; //stack increment/decrement done by the instruction 12 | }; 13 | 14 | //-------------------------------------------------------------------------- 15 | // info on all x86 instructions 16 | x86opcode opcodes[] = 17 | { 18 | {0x00, 1, 0, 0, 0}, //add 19 | {0x01, 1, 0, 0, 0}, //add 20 | {0x02, 1, 0, 0, 0}, //add 21 | {0x03, 1, 0, 0, 0}, //add 22 | {0x04, 0, 0, 1, 0}, //add 23 | {0x05, 0, 0, 4, 0}, //add 24 | {0x06, 0, 0, 0, -1}, //push 25 | {0x07, 0, 0, 0, +1}, //pop 26 | {0x08, 1, 0, 0, 0}, //or 27 | {0x09, 1, 0, 0, 0}, //or 28 | {0x0A, 1, 0, 0, 0}, //or 29 | {0x0B, 1, 0, 0, 0}, //or 30 | {0x0C, 0, 0, 1, 0}, //or 31 | {0x0D, 0, 0, 4, 0}, //or 32 | {0x0E, 0, 0, 0, -1}, //push 33 | {0x0F, 0, 0, 0, 0}, //two-byte instruction prefix 34 | 35 | {0x10, 1, 0, 0, 0}, //adc 36 | {0x11, 1, 0, 0, 0}, //adc 37 | {0x12, 1, 0, 0, 0}, //adc 38 | {0x13, 1, 0, 0, 0}, //adc 39 | {0x14, 0, 0, 1, 0}, //adc 40 | {0x15, 0, 0, 4, 0}, //adc 41 | {0x16, 0, 0, 0, -1}, //push 42 | {0x17, 0, 0, 0, +1}, //pop 43 | {0x18, 1, 0, 0, 0}, //sbb 44 | {0x19, 1, 0, 0, 0}, //sbb 45 | {0x1A, 1, 0, 0, 0}, //sbb 46 | {0x1B, 1, 0, 0, 0}, //sbb 47 | {0x1C, 0, 0, 1, 0}, //sbb 48 | {0x1D, 0, 0, 4, 0}, //sbb 49 | {0x1E, 0, 0, 0, -1}, //push 50 | {0x1F, 0, 0, 0, +1}, //pop 51 | 52 | {0x20, 1, 0, 0, 0}, //and 53 | {0x21, 1, 0, 0, 0}, //and 54 | {0x22, 1, 0, 0, 0}, //and 55 | {0x23, 1, 0, 0, 0}, //and 56 | {0x24, 0, 0, 1, 0}, //and 57 | {0x25, 0, 0, 4, 0}, //and 58 | {0x26, 2, 0, 0, 0}, //ES segment override prefix 59 | {0x27, 0, 0, 0, 0}, //Decimal Adjust AL after Addition 60 | {0x28, 1, 0, 0, 0}, //sub 61 | {0x29, 1, 0, 0, 0}, //sub 62 | {0x2A, 1, 0, 0, 0}, //sub 63 | {0x2B, 1, 0, 0, 0}, //sub 64 | {0x2C, 0, 0, 1, 0}, //sub 65 | {0x2D, 0, 0, 4, 0}, //sub 66 | {0x2E, 2, 0, 0, 0}, //CS segment override prefix 67 | {0x2F, 0, 0, 0, 0}, //Decimal Adjust AL after Subtraction 68 | 69 | {0x30, 1, 0, 0, 0}, //xor 70 | {0x31, 1, 0, 0, 0}, //xor 71 | {0x32, 1, 0, 0, 0}, //xor 72 | {0x33, 1, 0, 0, 0}, //xor 73 | {0x34, 0, 0, 1, 0}, //xor 74 | {0x35, 0, 0, 4, 0}, //xor 75 | {0x36, 2, 0, 0, 0}, //SS segment override prefix 76 | {0x37, 0, 0, 0, 0}, //aaa 77 | {0x38, 1, 0, 0, 0}, //cmp 78 | {0x39, 1, 0, 0, 0}, //cmp 79 | {0x3A, 1, 0, 0, 0}, //cmp 80 | {0x3B, 1, 0, 0, 0}, //cmp 81 | {0x3C, 0, 0, 1, 0}, //cmp 82 | {0x3D, 0, 0, 4, 0}, //cmp 83 | {0x3E, 2, 0, 0, 0}, //DS segment override prefix 84 | {0x3F, 0, 0, 0, 0}, //aas 85 | 86 | {0x40, 0, 0, 0, 0}, //inc 87 | {0x41, 0, 0, 0, 0}, //inc 88 | {0x42, 0, 0, 0, 0}, //inc 89 | {0x43, 0, 0, 0, 0}, //inc 90 | {0x44, 0, 0, 0, 0}, //inc 91 | {0x45, 0, 0, 0, 0}, //inc 92 | {0x46, 0, 0, 0, 0}, //inc 93 | {0x47, 0, 0, 0, 0}, //inc 94 | {0x48, 0, 0, 0, 0}, //dec 95 | {0x49, 0, 0, 0, 0}, //dec 96 | {0x4A, 0, 0, 0, 0}, //dec 97 | {0x4B, 0, 0, 0, 0}, //dec 98 | {0x4C, 0, 0, 0, 0}, //dec 99 | {0x4D, 0, 0, 0, 0}, //dec 100 | {0x4E, 0, 0, 0, 0}, //dec 101 | {0x4F, 0, 0, 0, 0}, //dec 102 | 103 | {0x50, 0, 0, 0, -1}, //push 104 | {0x51, 0, 0, 0, -1}, //push 105 | {0x52, 0, 0, 0, -1}, //push 106 | {0x53, 0, 0, 0, -1}, //push 107 | {0x54, 0, 0, 0, -1}, //push 108 | {0x55, 0, 0, 0, -1}, //push 109 | {0x56, 0, 0, 0, -1}, //push 110 | {0x57, 0, 0, 0, -1}, //push 111 | {0x58, 0, 0, 0, +1}, //pop 112 | {0x59, 0, 0, 0, +1}, //pop 113 | {0x5A, 0, 0, 0, +1}, //pop 114 | {0x5B, 0, 0, 0, +1}, //pop 115 | {0x5C, 0, 0, 0, +1}, //pop 116 | {0x5D, 0, 0, 0, +1}, //pop 117 | {0x5E, 0, 0, 0, +1}, //pop 118 | {0x5F, 0, 0, 0, +1}, //pop 119 | 120 | {0x60, 0, 0, 0, -8}, //pusha 121 | {0x61, 0, 0, 0, +8}, //popa 122 | {0x62, 1, 0, 0, 0}, //BOUND 123 | {0x63, 1, 0, 0, 0}, //ARPL 124 | {0x64, 2, 0, 0, 0}, //prefix 125 | {0x65, 2, 0, 0, 0}, //prefix 126 | {0x66, 2, 0, 0, 0}, //prefix 127 | {0x67, 2, 0, 0, 0}, //prefix 128 | {0x68, 0, 0, 4, -1}, //push 129 | {0x69, 1, 0, 4, 0}, //imul 130 | {0x6A, 0, 0, 1, -1}, //push 131 | {0x6B, 1, 0, 1, 0}, //imul 132 | {0x6C, 0, 0, 0, 0}, //ins 133 | {0x6D, 0, 0, 0, 0}, //ins 134 | {0x6E, 0, 0, 0, 0}, //outs 135 | {0x6F, 0, 0, 0, 0}, //outs 136 | 137 | {0x70, 0, 2, 1, 0}, //jump 138 | {0x71, 0, 2, 1, 0}, //jump 139 | {0x72, 0, 2, 1, 0}, //jump 140 | {0x73, 0, 2, 1, 0}, //jump 141 | {0x74, 0, 2, 1, 0}, //jump 142 | {0x75, 0, 2, 1, 0}, //jump 143 | {0x76, 0, 2, 1, 0}, //jump 144 | {0x77, 0, 2, 1, 0}, //jump 145 | {0x78, 0, 2, 1, 0}, //jump 146 | {0x79, 0, 2, 1, 0}, //jump 147 | {0x7A, 0, 2, 1, 0}, //jump 148 | {0x7B, 0, 2, 1, 0}, //jump 149 | {0x7C, 0, 2, 1, 0}, //jump 150 | {0x7D, 0, 2, 1, 0}, //jump 151 | {0x7E, 0, 2, 1, 0}, //jump 152 | {0x7F, 0, 2, 1, 0}, //jump 153 | 154 | {0x80, 1, 0, 1, 0}, 155 | {0x81, 1, 0, 4, 0}, 156 | {0x82, 1, 0, 1, 0}, 157 | {0x83, 1, 0, 1, 0}, 158 | {0x84, 1, 0, 0, 0}, 159 | {0x85, 1, 0, 0, 0}, 160 | {0x86, 1, 0, 0, 0}, 161 | {0x87, 1, 0, 0, 0}, 162 | {0x88, 1, 0, 0, 0}, //mov 163 | {0x89, 1, 0, 0, 0}, 164 | {0x8A, 1, 0, 0, 0}, 165 | {0x8B, 1, 0, 0, 0}, 166 | {0x8C, 1, 0, 0, 0}, 167 | {0x8D, 1, 0, 0, 0}, 168 | {0x8E, 1, 0, 0, 0}, 169 | {0x8F, 1, 0, 0, +1}, //pop 170 | 171 | {0x90, 0, 0, 0, 0}, //nop 172 | {0x91, 0, 0, 0, 0}, 173 | {0x92, 0, 0, 0, 0}, 174 | {0x93, 0, 0, 0, 0}, 175 | {0x94, 0, 0, 0, 0}, 176 | {0x95, 0, 0, 0, 0}, 177 | {0x96, 0, 0, 0, 0}, 178 | {0x97, 0, 0, 0, 0}, 179 | {0x98, 0, 0, 0, 0}, //CBW 180 | {0x99, 0, 0, 0, 0}, 181 | {0x9A, 0, 1, 6, 0}, //callf 182 | {0x9B, 0, 0, 0, 0}, 183 | {0x9C, 0, 0, 0, -1}, 184 | {0x9D, 0, 0, 0, +1}, 185 | {0x9E, 0, 0, 0, 0}, 186 | {0x9F, 0, 0, 0, 0}, 187 | 188 | {0xA0, 0, 0, 4, 0}, //mov 189 | {0xA1, 0, 0, 4, 0}, //mov 190 | {0xA2, 0, 0, 4, 0}, //mov 191 | {0xA3, 0, 0, 4, 0}, //mov 192 | {0xA4, 0, 0, 0, 0}, 193 | {0xA5, 0, 0, 0, 0}, 194 | {0xA6, 0, 0, 0, 0}, 195 | {0xA7, 0, 0, 0, 0}, 196 | {0xA8, 0, 0, 1, 0}, //test 197 | {0xA9, 0, 0, 4, 0}, 198 | {0xAA, 0, 0, 0, 0}, 199 | {0xAB, 0, 0, 0, 0}, 200 | {0xAC, 0, 0, 0, 0}, 201 | {0xAD, 0, 0, 0, 0}, 202 | {0xAE, 0, 0, 0, 0}, 203 | {0xAF, 0, 0, 0, 0}, 204 | 205 | {0xB0, 0, 0, 1, 0}, //mov 206 | {0xB1, 0, 0, 1, 0}, 207 | {0xB2, 0, 0, 1, 0}, 208 | {0xB3, 0, 0, 1, 0}, 209 | {0xB4, 0, 0, 1, 0}, 210 | {0xB5, 0, 0, 1, 0}, 211 | {0xB6, 0, 0, 1, 0}, 212 | {0xB7, 0, 0, 1, 0}, 213 | {0xB8, 0, 0, 4, 0}, 214 | {0xB9, 0, 0, 4, 0}, 215 | {0xBA, 0, 0, 4, 0}, 216 | {0xBB, 0, 0, 4, 0}, 217 | {0xBC, 0, 0, 4, 0}, 218 | {0xBD, 0, 0, 4, 0}, 219 | {0xBE, 0, 0, 4, 0}, 220 | {0xBF, 0, 0, 4, 0}, 221 | 222 | {0xC0, 1, 0, 1, 0}, 223 | {0xC1, 1, 0, 1, 0}, 224 | {0xC2, 0, 0, 2, 0}, //retn 225 | {0xC3, 0, 0, 0, 0}, //retn 226 | {0xC4, 1, 0, 0, 0}, 227 | {0xC5, 1, 0, 0, 0}, 228 | {0xC6, 1, 0, 1, 0}, 229 | {0xC7, 1, 0, 4, 0}, 230 | {0xC8, 0, 1, 3, 0}, //enter 231 | {0xC9, 0, 1, 0, 0}, //leave 232 | {0xCA, 0, 0, 2, 0}, //retn 233 | {0xCB, 0, 0, 0, 0}, //retn 234 | {0xCC, 0, 1, 0, 0}, 235 | {0xCD, 0, 1, 1, 0}, 236 | {0xCE, 0, 1, 0, 0}, 237 | {0xCF, 0, 1, 0, 0}, 238 | 239 | {0xD0, 1, 0, 0, 0}, 240 | {0xD1, 1, 0, 0, 0}, 241 | {0xD2, 1, 0, 0, 0}, 242 | {0xD3, 1, 0, 0, 0}, 243 | {0xD4, 0, 0, 1, 0}, 244 | {0xD5, 0, 0, 1, 0}, 245 | {0xD6, 0, 0, 0, 0}, 246 | {0xD7, 0, 0, 0, 0}, 247 | {0xD8, 1, 0, 0, 0}, 248 | {0xD9, 1, 0, 0, 0}, 249 | {0xDA, 1, 0, 0, 0}, 250 | {0xDB, 1, 0, 0, 0}, 251 | {0xDC, 1, 0, 0, 0}, 252 | {0xDD, 1, 0, 0, 0}, 253 | {0xDE, 1, 0, 0, 0}, 254 | {0xDF, 1, 0, 0, 0}, 255 | 256 | {0xE0, 0, 2, 1, 0}, 257 | {0xE1, 0, 2, 1, 0}, 258 | {0xE2, 0, 2, 1, 0}, 259 | {0xE3, 0, 2, 1, 0}, 260 | {0xE4, 0, 0, 1, 0}, 261 | {0xE5, 0, 0, 1, 0}, 262 | {0xE6, 0, 0, 1, 0}, 263 | {0xE7, 0, 0, 1, 0}, 264 | {0xE8, 0, 1, 4, 0}, 265 | {0xE9, 0, 3, 4, 0}, 266 | {0xEA, 0, 3, 6, 0}, 267 | {0xEB, 0, 3, 1, 0}, 268 | {0xEC, 0, 0, 0, 0}, 269 | {0xED, 0, 0, 0, 0}, 270 | {0xEE, 0, 0, 0, 0}, 271 | {0xEF, 0, 0, 0, 0}, 272 | 273 | {0xF0, 2, 0, 0, 0}, //lock 274 | {0xF1, 0, 1, 0, 0}, 275 | {0xF2, 2, 0, 0, 0}, 276 | {0xF3, 2, 0, 0, 0}, 277 | {0xF4, 0, 0, 0, 0}, 278 | {0xF5, 0, 0, 0, 0}, 279 | {0xF6, 1, 0, 0, 0}, 280 | {0xF7, 1, 0, 0, 0}, 281 | {0xF8, 0, 0, 0, 0}, 282 | {0xF9, 0, 0, 0, 0}, 283 | {0xFA, 0, 0, 0, 0}, 284 | {0xFB, 0, 0, 0, 0}, 285 | {0xFC, 0, 0, 0, 0}, 286 | {0xFD, 0, 0, 0, 0}, 287 | {0xFE, 1, 0, 0, 0}, 288 | {0xFF, 1, 0, 0, 0}, 289 | 290 | //2-byte opcodes 291 | {0x00, 1, 0, 0, 0}, 292 | {0x01, 1, 1, 0, 0}, 293 | {0x02, 1, 0, 0, 0}, 294 | {0x03, 1, 0, 0, 0}, 295 | {0x04, 0, 0, 0, 0}, 296 | {0x05, 0, 0, 0, 0}, 297 | {0x06, 0, 0, 0, 0}, 298 | {0x07, 0, 0, 0, 0}, 299 | {0x08, 0, 0, 0, 0}, 300 | {0x09, 0, 0, 0, 0}, 301 | {0x0A, 0, 0, 0, 0}, 302 | {0x0B, 0, 0, 0, 0}, 303 | {0x0C, 0, 0, 0, 0}, 304 | {0x0D, 1, 0, 0, 0}, 305 | {0x0E, 1, 0, 0, 0}, 306 | {0x0F, 1, 0, 0, 0}, 307 | 308 | {0x10, 1, 0, 0, 0}, 309 | {0x11, 1, 0, 0, 0}, 310 | {0x12, 1, 0, 0, 0}, 311 | {0x13, 1, 0, 0, 0}, 312 | {0x14, 1, 0, 0, 0}, 313 | {0x15, 1, 0, 0, 0}, 314 | {0x16, 1, 0, 0, 0}, 315 | {0x17, 1, 0, 0, 0}, 316 | {0x18, 1, 0, 0, 0}, 317 | {0x19, 1, 0, 0, 0}, 318 | {0x1A, 1, 0, 0, 0}, 319 | {0x1B, 1, 0, 0, 0}, 320 | {0x1C, 1, 0, 0, 0}, 321 | {0x1D, 1, 0, 0, 0}, 322 | {0x1E, 1, 0, 0, 0}, 323 | {0x1F, 1, 0, 0, 0}, 324 | 325 | {0x20, 1, 0, 0, 0}, 326 | {0x21, 1, 0, 0, 0}, 327 | {0x22, 1, 0, 0, 0}, 328 | {0x23, 1, 0, 0, 0}, 329 | {0x24, 1, 0, 0, 0}, 330 | {0x25, 1, 0, 0, 0}, 331 | {0x26, 1, 0, 0, 0}, 332 | {0x27, 1, 0, 0, 0}, 333 | {0x28, 1, 0, 0, 0}, 334 | {0x29, 1, 0, 0, 0}, 335 | {0x2A, 1, 0, 0, 0}, 336 | {0x2B, 1, 0, 0, 0}, 337 | {0x2C, 1, 0, 0, 0}, 338 | {0x2D, 1, 0, 0, 0}, 339 | {0x2E, 1, 0, 0, 0}, 340 | {0x2F, 1, 0, 0, 0}, 341 | 342 | {0x30, 0, 0, 0, 0}, 343 | {0x31, 0, 0, 0, 0}, 344 | {0x32, 0, 0, 0, 0}, 345 | {0x33, 0, 0, 0, 0}, 346 | {0x34, 0, 1, 0, 0}, 347 | {0x35, 0, 1, 0, 0}, 348 | {0x36, 0, 0, 0, 0}, 349 | {0x37, 0, 0, 0, 0}, 350 | {0x38, 0, 1, 0, 0}, 351 | {0x39, 0, 1, 0, 0}, 352 | {0x3A, 0, 1, 0, 0}, 353 | {0x3B, 0, 1, 0, 0}, 354 | {0x3C, 0, 1, 0, 0}, 355 | {0x3D, 0, 1, 0, 0}, 356 | {0x3E, 0, 1, 0, 0}, 357 | {0x3F, 0, 1, 0, 0}, 358 | 359 | {0x40, 1, 0, 0, 0}, 360 | {0x41, 1, 0, 0, 0}, 361 | {0x42, 1, 0, 0, 0}, 362 | {0x43, 1, 0, 0, 0}, 363 | {0x44, 1, 0, 0, 0}, 364 | {0x45, 1, 0, 0, 0}, 365 | {0x46, 1, 0, 0, 0}, 366 | {0x47, 1, 0, 0, 0}, 367 | {0x48, 1, 0, 0, 0}, 368 | {0x49, 1, 0, 0, 0}, 369 | {0x4A, 1, 0, 0, 0}, 370 | {0x4B, 1, 0, 0, 0}, 371 | {0x4C, 1, 0, 0, 0}, 372 | {0x4D, 1, 0, 0, 0}, 373 | {0x4E, 1, 0, 0, 0}, 374 | {0x4F, 1, 0, 0, 0}, 375 | 376 | {0x50, 1, 0, 0, 0}, 377 | {0x51, 1, 0, 0, 0}, 378 | {0x52, 1, 0, 0, 0}, 379 | {0x53, 1, 0, 0, 0}, 380 | {0x54, 1, 0, 0, 0}, 381 | {0x55, 1, 0, 0, 0}, 382 | {0x56, 1, 0, 0, 0}, 383 | {0x57, 1, 0, 0, 0}, 384 | {0x58, 1, 0, 0, 0}, 385 | {0x59, 1, 0, 0, 0}, 386 | {0x5A, 1, 0, 0, 0}, 387 | {0x5B, 1, 0, 0, 0}, 388 | {0x5C, 1, 0, 0, 0}, 389 | {0x5D, 1, 0, 0, 0}, 390 | {0x5E, 1, 0, 0, 0}, 391 | {0x5F, 1, 0, 0, 0}, 392 | 393 | {0x60, 1, 0, 0, 0}, 394 | {0x61, 1, 0, 0, 0}, 395 | {0x62, 1, 0, 0, 0}, 396 | {0x63, 1, 0, 0, 0}, 397 | {0x64, 1, 0, 0, 0}, 398 | {0x65, 1, 0, 0, 0}, 399 | {0x66, 1, 0, 0, 0}, 400 | {0x67, 1, 0, 0, 0}, 401 | {0x68, 1, 0, 0, 0}, 402 | {0x69, 1, 0, 0, 0}, 403 | {0x6A, 1, 0, 0, 0}, 404 | {0x6B, 1, 0, 0, 0}, 405 | {0x6C, 1, 0, 0, 0}, 406 | {0x6D, 1, 0, 0, 0}, 407 | {0x6E, 1, 0, 0, 0}, 408 | {0x6F, 1, 0, 0, 0}, 409 | 410 | {0x70, 1, 0, 1, 0}, 411 | {0x71, 1, 0, 1, 0}, 412 | {0x72, 1, 0, 1, 0}, 413 | {0x73, 1, 0, 1, 0}, 414 | {0x74, 1, 0, 0, 0}, 415 | {0x75, 1, 0, 0, 0}, 416 | {0x76, 1, 0, 0, 0}, 417 | {0x77, 0, 0, 0, 0}, 418 | {0x78, 1, 0, 0, 0}, 419 | {0x79, 1, 0, 0, 0}, 420 | {0x7A, 1, 0, 0, 0}, 421 | {0x7B, 1, 0, 0, 0}, 422 | {0x7C, 1, 0, 0, 0}, 423 | {0x7D, 1, 0, 0, 0}, 424 | {0x7E, 1, 0, 0, 0}, 425 | {0x7F, 1, 0, 0, 0}, 426 | 427 | {0x80, 0, 2, 4, 0}, 428 | {0x81, 0, 2, 4, 0}, 429 | {0x82, 0, 2, 4, 0}, 430 | {0x83, 0, 2, 4, 0}, 431 | {0x84, 0, 2, 4, 0}, 432 | {0x85, 0, 2, 4, 0}, 433 | {0x86, 0, 2, 4, 0}, 434 | {0x87, 0, 2, 4, 0}, 435 | {0x88, 0, 2, 4, 0}, 436 | {0x89, 0, 2, 4, 0}, 437 | {0x8A, 0, 2, 4, 0}, 438 | {0x8B, 0, 2, 4, 0}, 439 | {0x8C, 0, 2, 4, 0}, 440 | {0x8D, 0, 2, 4, 0}, 441 | {0x8E, 0, 2, 4, 0}, 442 | {0x8F, 0, 2, 4, 0}, 443 | 444 | {0x90, 1, 0, 0, 0}, 445 | {0x91, 1, 0, 0, 0}, 446 | {0x92, 1, 0, 0, 0}, 447 | {0x93, 1, 0, 0, 0}, 448 | {0x94, 1, 0, 0, 0}, 449 | {0x95, 1, 0, 0, 0}, 450 | {0x96, 1, 0, 0, 0}, 451 | {0x97, 1, 0, 0, 0}, 452 | {0x98, 1, 0, 0, 0}, 453 | {0x99, 1, 0, 0, 0}, 454 | {0x9A, 1, 0, 0, 0}, 455 | {0x9B, 1, 0, 0, 0}, 456 | {0x9C, 1, 0, 0, 0}, 457 | {0x9D, 1, 0, 0, 0}, 458 | {0x9E, 1, 0, 0, 0}, 459 | {0x9F, 1, 0, 0, 0}, 460 | 461 | {0xA0, 0, 0, 0, -1}, 462 | {0xA1, 0, 0, 0, +1}, 463 | {0xA2, 0, 0, 0, 0}, 464 | {0xA3, 1, 0, 0, 0}, 465 | {0xA4, 1, 0, 1, 0}, 466 | {0xA5, 1, 0, 0, 0}, 467 | {0xA6, 0, 1, 0, 0}, 468 | {0xA7, 0, 1, 0, 0}, 469 | {0xA8, 0, 0, 0, -1}, 470 | {0xA9, 0, 0, 0, +1}, 471 | {0xAA, 0, 0, 0, 0}, 472 | {0xAB, 1, 0, 0, 0}, 473 | {0xAC, 1, 0, 1, 0}, 474 | {0xAD, 1, 0, 0, 0}, 475 | {0xAE, 1, 0, 0, 0}, 476 | {0xAF, 1, 0, 0, 0}, 477 | 478 | {0xB0, 1, 0, 0, 0}, 479 | {0xB1, 1, 0, 0, 0}, 480 | {0xB2, 1, 0, 0, 0}, 481 | {0xB3, 1, 0, 0, 0}, 482 | {0xB4, 1, 0, 0, 0}, 483 | {0xB5, 1, 0, 0, 0}, 484 | {0xB6, 1, 0, 0, 0}, 485 | {0xB7, 1, 0, 0, 0}, 486 | {0xB8, 1, 0, 0, 0}, 487 | {0xB9, 1, 0, 0, 0}, 488 | {0xBA, 1, 0, 1, 0}, 489 | {0xBB, 1, 0, 0, 0}, 490 | {0xBC, 1, 0, 0, 0}, 491 | {0xBD, 1, 0, 0, 0}, 492 | {0xBE, 1, 0, 0, 0}, 493 | {0xBF, 1, 0, 0, 0}, 494 | 495 | {0xC0, 1, 0, 0, 0}, 496 | {0xC1, 1, 0, 0, 0}, 497 | {0xC2, 1, 0, 1, 0}, 498 | {0xC3, 1, 0, 1, 0}, 499 | {0xC4, 1, 0, 1, 0}, 500 | {0xC5, 1, 0, 1, 0}, 501 | {0xC6, 1, 0, 1, 0}, 502 | {0xC7, 1, 0, 0, 0}, 503 | {0xC8, 0, 0, 0, 0}, 504 | {0xC9, 0, 0, 0, 0}, 505 | {0xCA, 0, 0, 0, 0}, 506 | {0xCB, 0, 0, 0, 0}, 507 | {0xCC, 0, 0, 0, 0}, 508 | {0xCD, 0, 0, 0, 0}, 509 | {0xCE, 0, 0, 0, 0}, 510 | {0xCF, 0, 0, 0, 0}, 511 | 512 | {0xD0, 1, 0, 0, 0}, 513 | {0xD1, 1, 0, 0, 0}, 514 | {0xD2, 1, 0, 0, 0}, 515 | {0xD3, 1, 0, 0, 0}, 516 | {0xD4, 1, 0, 0, 0}, 517 | {0xD5, 1, 0, 0, 0}, 518 | {0xD6, 1, 0, 0, 0}, 519 | {0xD7, 1, 0, 0, 0}, 520 | {0xD8, 1, 0, 0, 0}, 521 | {0xD9, 1, 0, 0, 0}, 522 | {0xDA, 1, 0, 0, 0}, 523 | {0xDB, 1, 0, 0, 0}, 524 | {0xDC, 1, 0, 0, 0}, 525 | {0xDD, 1, 0, 0, 0}, 526 | {0xDE, 1, 0, 0, 0}, 527 | {0xDF, 1, 0, 0, 0}, 528 | 529 | {0xE0, 1, 0, 0, 0}, 530 | {0xE1, 1, 0, 0, 0}, 531 | {0xE2, 1, 0, 0, 0}, 532 | {0xE3, 1, 0, 0, 0}, 533 | {0xE4, 1, 0, 0, 0}, 534 | {0xE5, 1, 0, 0, 0}, 535 | {0xE6, 1, 0, 0, 0}, 536 | {0xE7, 1, 0, 0, 0}, 537 | {0xE8, 1, 0, 0, 0}, 538 | {0xE9, 1, 0, 0, 0}, 539 | {0xEA, 1, 0, 0, 0}, 540 | {0xEB, 1, 0, 0, 0}, 541 | {0xEC, 1, 0, 0, 0}, 542 | {0xED, 1, 0, 0, 0}, 543 | {0xEE, 1, 0, 0, 0}, 544 | {0xEF, 1, 0, 0, 0}, 545 | 546 | {0xF0, 1, 0, 0, 0}, 547 | {0xF1, 1, 0, 0, 0}, 548 | {0xF2, 1, 0, 0, 0}, 549 | {0xF3, 1, 0, 0, 0}, 550 | {0xF4, 1, 0, 0, 0}, 551 | {0xF5, 1, 0, 0, 0}, 552 | {0xF6, 1, 0, 0, 0}, 553 | {0xF7, 1, 0, 0, 0}, 554 | {0xF8, 1, 0, 0, 0}, 555 | {0xF9, 1, 0, 0, 0}, 556 | {0xFA, 1, 0, 0, 0}, 557 | {0xFB, 1, 0, 0, 0}, 558 | {0xFC, 1, 0, 0, 0}, 559 | {0xFD, 1, 0, 0, 0}, 560 | {0xFE, 1, 0, 0, 0}, 561 | {0xFF, 0, 1, 0, 0} 562 | }; 563 | 564 | //-------------------------------------------------------------------------- 565 | //decodes the instruction pointed to by eip and increases the eip accordingly 566 | //returns 0 on failure 567 | //instructions should be NULL (used for debugging only) 568 | int FollowInstruction(unsigned char *instructions, unsigned long *eip) 569 | { 570 | unsigned char modregrm, sib; 571 | unsigned short opcode = 0; 572 | bool operandOverridePrefix = false; 573 | bool addressOverridePrefix = false; 574 | long displacement; 575 | long argsize = 0; 576 | 577 | //handle prefixes 578 | while(1) 579 | { 580 | if(opcodes[instructions[*eip]].type == 2) 581 | { 582 | if(instructions[*eip] == 0x66) operandOverridePrefix = true; 583 | if(instructions[*eip] == 0x67) addressOverridePrefix = true; 584 | (*eip)++; 585 | continue; 586 | } 587 | break; 588 | } 589 | 590 | // load the opcode 591 | opcode = instructions[*eip]; 592 | (*eip)++; 593 | if (opcode == 0x0F) 594 | { 595 | opcode = 0x0100 + instructions[*eip]; 596 | (*eip)++; 597 | } 598 | 599 | if (addressOverridePrefix&&((opcode == 0x00)||(opcode == 0x20))) 600 | return 0; //can't handle such instructions currently 601 | 602 | //handle register-based instructions (mod/reg/rm byte, sib byte, displacement etc) 603 | if (opcodes[opcode].type == 1) 604 | { 605 | modregrm = instructions[*eip]; 606 | (*eip)++; 607 | 608 | //hack, fix for test instruction 609 | if ((opcode == 0xF6)&&((modregrm&0x30)==0)) 610 | { 611 | argsize ++; 612 | } 613 | else if((opcode == 0xF7)&&((modregrm&0x30)==0)) 614 | { 615 | if (operandOverridePrefix) 616 | argsize += 2; 617 | else 618 | argsize += 4; 619 | } 620 | 621 | if ((modregrm&0xC0) == 0x40) 622 | displacement = 1; 623 | else if((modregrm&0xC0) == 0x80) 624 | { 625 | if (addressOverridePrefix) 626 | displacement = 2; 627 | else 628 | displacement = 4; 629 | } else if((modregrm&0xC7) == 0x05) 630 | { 631 | //displacement-only addressing mode 632 | if(addressOverridePrefix) 633 | displacement = 2; 634 | else 635 | displacement = 4; 636 | } 637 | else 638 | displacement = 0; 639 | 640 | if (((modregrm&0x07) == 0x04)&&((modregrm&0xC0) != 0xC0)) 641 | { 642 | sib = instructions[*eip]; 643 | (*eip)++; 644 | 645 | if (((modregrm&0xC0) == 0x00)&&((sib&07)==0x05)) 646 | displacement = 4; 647 | } 648 | 649 | (*eip) += displacement; 650 | } 651 | 652 | // increase eip by operand size 653 | if ((opcode == 0xA0)||(opcode == 0xA1)||(opcode == 0xA2)||(opcode == 0xA3)) 654 | { 655 | //hack, fix for certain types of mov instruction 656 | if(addressOverridePrefix) 657 | argsize+=2; 658 | else 659 | argsize+=4; 660 | } 661 | else if(operandOverridePrefix && (opcodes[opcode].argSize == 4)) 662 | argsize += 2; 663 | else if(operandOverridePrefix && (opcodes[opcode].argSize == 6)) 664 | argsize += 4; 665 | else 666 | argsize += opcodes[opcode].argSize; 667 | 668 | (*eip) += argsize; 669 | 670 | return 1; 671 | } 672 | 673 | //-------------------------------------------------------------------------- 674 | // decodes the instruction pointed to by eip and simulates all changes made to the esp register 675 | // instructions should be NULL (used for debugging only) 676 | // retparam will contain a parameter value of RETN n instruction 677 | // returns 1 on success, 0 on failure and 2 if RETN instruction is encountered 678 | int SimulateStackInstruction( 679 | unsigned char *instructions, 680 | unsigned long *eip, 681 | unsigned long *esp, 682 | unsigned long *retparam) 683 | { 684 | unsigned char modregrm, sib; 685 | unsigned short opcode = 0; 686 | bool operandOverridePrefix = false; 687 | bool addressOverridePrefix = false; 688 | long displacement; 689 | long argsize = 0; 690 | 691 | // handle prefixes 692 | while (true) 693 | { 694 | if (opcodes[instructions[*eip]].type == 2) 695 | { 696 | if (instructions[*eip] == 0x66) 697 | operandOverridePrefix = true; 698 | 699 | if (instructions[*eip] == 0x67) 700 | addressOverridePrefix = true; 701 | 702 | (*eip)++; 703 | continue; 704 | } 705 | break; 706 | } 707 | 708 | // Load the opcode 709 | opcode = instructions[*eip]; 710 | (*eip)++; 711 | if (opcode == 0x0F) 712 | { 713 | opcode = 0x0100 + instructions[*eip]; 714 | (*eip)++; 715 | } 716 | 717 | // can't handle such instructions currently 718 | if (addressOverridePrefix&&((opcode == 0x00)||(opcode == 0x20))) 719 | return 0; 720 | 721 | // don't handle jump/call functions (and similar) 722 | if (opcodes[opcode].jump) 723 | return 0; 724 | 725 | if (opcode==0xFF) 726 | { 727 | modregrm = instructions[*eip]; 728 | // indirect CALL 729 | if ((modregrm&0x38) == 0x10) 730 | return 0; 731 | if ((modregrm&0x38) == 0x18) 732 | return 0; //indirect CALL 733 | if ((modregrm&0x38) == 0x20) 734 | return 0; //indirect JUMP 735 | if ((modregrm&0x38) == 0x28) 736 | return 0; //indirect JUMP 737 | } 738 | 739 | // handle register-based instructions (mod/reg/rm byte, sib byte, displacement etc) 740 | if (opcodes[opcode].type == 1) 741 | { 742 | modregrm = instructions[*eip]; 743 | (*eip)++; 744 | 745 | // hack, fix for test instruction 746 | if ((opcode == 0xF6)&&((modregrm&0x30)==0)) 747 | { 748 | argsize++; 749 | } 750 | else if ((opcode == 0xF7)&&((modregrm&0x30)==0)) 751 | { 752 | if (operandOverridePrefix) 753 | argsize += 2; 754 | else 755 | argsize += 4; 756 | } 757 | 758 | if ((modregrm&0xC0) == 0x40) 759 | { 760 | displacement = 1; 761 | } 762 | else if ((modregrm&0xC0) == 0x80) 763 | { 764 | if(addressOverridePrefix) 765 | displacement = 2; 766 | else 767 | displacement = 4; 768 | } 769 | else if ((modregrm&0xC7) == 0x05) 770 | { 771 | // displacement-only addressing mode 772 | if (addressOverridePrefix) 773 | displacement = 2; 774 | else 775 | displacement = 4; 776 | } 777 | else 778 | { 779 | displacement = 0; 780 | } 781 | 782 | if (((modregrm&0x07) == 0x04) && ((modregrm&0xC0) != 0xC0)) 783 | { 784 | sib = instructions[*eip]; 785 | (*eip)++; 786 | 787 | if (((modregrm&0xC0) == 0x00)&&((sib&07)==0x05)) 788 | displacement = 4; 789 | } 790 | 791 | (*eip) += displacement; 792 | } 793 | 794 | // increase eip by operand size 795 | if ((opcode == 0xA0)||(opcode == 0xA1)||(opcode == 0xA2)||(opcode == 0xA3)) 796 | { 797 | // hack, fix for certain types of mov instruction 798 | argsize += addressOverridePrefix ? 2 : 4; 799 | } 800 | else if (operandOverridePrefix && (opcodes[opcode].argSize == 4)) 801 | argsize += 2; 802 | else if (operandOverridePrefix && (opcodes[opcode].argSize == 6)) 803 | argsize += 4; 804 | else 805 | argsize += opcodes[opcode].argSize; 806 | 807 | (*eip) += argsize; 808 | 809 | // modify stack pointer 810 | (*esp) += opcodes[opcode].stackChange * 4; 811 | if (opcode == 0xFF) 812 | { 813 | if ((modregrm&0x38) == 0x30) 814 | (*esp) -= 4; 815 | } 816 | 817 | // handle add esp,const and sub esp,const instructions 818 | if (opcode==0x81) 819 | { 820 | size_t delta = operandOverridePrefix ? 2 : 4; 821 | unsigned short stackoffset = *((unsigned short *)(&instructions[(*eip)-delta])); 822 | if (modregrm == 0xC4) 823 | (*esp) += stackoffset; 824 | else if (modregrm==0xEC) 825 | (*esp) -= stackoffset; 826 | } 827 | 828 | if (opcode==0x83) 829 | { 830 | unsigned char stackoffset = ((unsigned char *)instructions)[(*eip)-1]; 831 | if (modregrm==0xC4) 832 | (*esp) += stackoffset; 833 | else if (modregrm==0xEC) 834 | (*esp) -= stackoffset; 835 | } 836 | 837 | // check if we reached the return instruction 838 | if ((opcode == 0xC2) || (opcode == 0xCA)) 839 | { 840 | *retparam = *((unsigned short *)(&instructions[(*eip)-2])); 841 | return 2; 842 | } 843 | else if ((opcode == 0xC3) || (opcode == 0xCB)) 844 | { 845 | *retparam = 0; 846 | return 2; 847 | } 848 | return 1; 849 | } 850 | 851 | //-------------------------------------------------------------------------- 852 | // checks if the target of indirect call instruction at callAddress is the same as functionAddres^key 853 | int CheckCallArguments( 854 | unsigned long functionAddress, 855 | unsigned long callAddress, 856 | unsigned long *registers, 857 | unsigned long returnAddress, 858 | unsigned long key) 859 | { 860 | unsigned char *eip = (unsigned char *)callAddress; 861 | unsigned long targetAddr = 0; 862 | unsigned char modregrm, sib = 0; 863 | unsigned long displacement = 0; 864 | bool memread = true; 865 | 866 | if((*eip)!=0xFF) return 0; 867 | eip++; 868 | 869 | modregrm = (*eip); 870 | eip++; 871 | if((modregrm & 0x38) != 0x10) return 0; 872 | 873 | switch(modregrm & 0xC7) 874 | { 875 | case 0x00: 876 | targetAddr = registers[7]; 877 | break; 878 | case 0x40: 879 | targetAddr = registers[7]; 880 | displacement = 1; 881 | break; 882 | case 0x80: 883 | targetAddr = registers[7]; 884 | displacement = 4; 885 | break; 886 | case 0xC0: 887 | targetAddr = registers[7]; 888 | memread = false; 889 | break; 890 | case 0x01: 891 | targetAddr = registers[6]; 892 | break; 893 | case 0x41: 894 | targetAddr = registers[6]; 895 | displacement = 1; 896 | break; 897 | case 0x81: 898 | targetAddr = registers[6]; 899 | displacement = 4; 900 | break; 901 | case 0xC1: 902 | targetAddr = registers[6]; 903 | memread = false; 904 | break; 905 | case 0x02: 906 | targetAddr = registers[5]; 907 | break; 908 | case 0x42: 909 | targetAddr = registers[5]; 910 | displacement = 1; 911 | break; 912 | case 0x82: 913 | targetAddr = registers[5]; 914 | displacement = 4; 915 | break; 916 | case 0xC2: 917 | targetAddr = registers[5]; 918 | memread = false; 919 | break; 920 | case 0x03: 921 | targetAddr = registers[4]; 922 | break; 923 | case 0x43: 924 | targetAddr = registers[4]; 925 | displacement = 1; 926 | break; 927 | case 0x83: 928 | targetAddr = registers[4]; 929 | displacement = 4; 930 | break; 931 | case 0xC3: 932 | targetAddr = registers[4]; 933 | memread = false; 934 | break; 935 | case 0x04: 936 | sib = 1; 937 | break; 938 | case 0x44: 939 | sib = 1; 940 | displacement = 1; 941 | break; 942 | case 0x84: 943 | sib = 1; 944 | displacement = 4; 945 | break; 946 | case 0xC4: 947 | targetAddr = registers[3]; 948 | memread = false; 949 | break; 950 | case 0x05: 951 | displacement = 4; 952 | break; 953 | case 0x45: 954 | targetAddr = registers[2]; 955 | displacement = 1; 956 | break; 957 | case 0x85: 958 | targetAddr = registers[2]; 959 | displacement = 4; 960 | break; 961 | case 0xC5: 962 | targetAddr = registers[2]; 963 | memread = false; 964 | break; 965 | case 0x06: 966 | targetAddr = registers[1]; 967 | break; 968 | case 0x46: 969 | targetAddr = registers[1]; 970 | displacement = 1; 971 | break; 972 | case 0x86: 973 | targetAddr = registers[1]; 974 | displacement = 4; 975 | break; 976 | case 0xC6: 977 | targetAddr = registers[1]; 978 | memread = false; 979 | break; 980 | case 0x07: 981 | targetAddr = registers[0]; 982 | break; 983 | case 0x47: 984 | targetAddr = registers[0]; 985 | displacement = 1; 986 | break; 987 | case 0x87: 988 | targetAddr = registers[0]; 989 | displacement = 4; 990 | break; 991 | case 0xC7: 992 | targetAddr = registers[0]; 993 | memread = false; 994 | break; 995 | } 996 | 997 | 998 | if (sib) 999 | { 1000 | sib = (*eip); 1001 | eip++; 1002 | 1003 | int n; 1004 | switch (sib&0xC0) 1005 | { 1006 | case 0x00: 1007 | n = 1; 1008 | break; 1009 | case 0x40: 1010 | n = 2; 1011 | break; 1012 | case 0x80: 1013 | n = 4; 1014 | break; 1015 | case 0xC0: 1016 | n = 8; 1017 | break; 1018 | } 1019 | 1020 | //add n*index 1021 | targetAddr += registers[7-((sib&0x38)>>3)]*n; 1022 | 1023 | //add base 1024 | switch(modregrm & 0xC0) 1025 | { 1026 | case 0x00: 1027 | if((sib & 0x07)==0x05) 1028 | { 1029 | displacement = 4; 1030 | } else { 1031 | targetAddr += registers[7-(sib & 0x07)]; 1032 | } 1033 | break; 1034 | case 0x40: 1035 | targetAddr += registers[7-(sib & 0x07)] & 0x000000FF; 1036 | break; 1037 | case 0x80: 1038 | targetAddr += registers[7-(sib & 0x07)]; 1039 | break; 1040 | } 1041 | } 1042 | 1043 | if (displacement == 1) 1044 | { 1045 | targetAddr += (*eip); 1046 | eip++; 1047 | } 1048 | else if(displacement == 4) 1049 | { 1050 | targetAddr += *((unsigned long *)eip); 1051 | eip += 4; 1052 | } 1053 | 1054 | if(((unsigned long)eip)!=returnAddress) 1055 | return 0; 1056 | 1057 | if (memread) 1058 | { 1059 | targetAddr = *((unsigned long *)targetAddr); 1060 | } 1061 | 1062 | if(targetAddr == (functionAddress^key)) 1063 | { 1064 | //MessageBoxA(NULL, "Call target check success", "ROPGuard", MB_OK); 1065 | return 1; 1066 | } 1067 | return 0; 1068 | } 1069 | --------------------------------------------------------------------------------