diff --git a/msvc/libzzuf.vcxproj b/msvc/libzzuf.vcxproj
index d7ed49a..9f94517 100644
--- a/msvc/libzzuf.vcxproj
+++ b/msvc/libzzuf.vcxproj
@@ -5,10 +5,18 @@
Debug
Win32
+
+ Debug
+ x64
+
Release
Win32
+
+ Release
+ x64
+
{E658DCE5-E1E5-41C8-910B-1CC2D73C435C}
@@ -19,34 +27,60 @@
DynamicLibrary
MultiByte
+
+ DynamicLibrary
+ MultiByte
+
DynamicLibrary
MultiByte
+
+ DynamicLibrary
+ MultiByte
+
+
+
+
+
+
+
<_ProjectFileVersion>10.0.21006.1
Debug\
+ Debug\
Debug\$(ProjectName)\
+ Debug\$(ProjectName)\
true
+ true
Release\
+ Release\
Release\$(ProjectName)\
+ Release\$(ProjectName)\
false
+ false
AllRules.ruleset
+ AllRules.ruleset
+
+
AllRules.ruleset
+ AllRules.ruleset
+
+
@@ -76,6 +110,32 @@
0x0409
+
+
+ Disabled
+ ..\msvc;..\src\common;..\src\libzzuf;%(AdditionalIncludeDirectories)
+ WIN32;_WINDOWS;_DEBUG;LIBZZUF;_USRDLL;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ $(IntDir).libs/
+ Level3
+ ProgramDatabase
+ CompileAsC
+
+
+ imagehlp.lib;ws2_32.lib;%(AdditionalDependencies)
+ true
+ Windows
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+ false
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+ 0x0409
+
+
..\msvc;..\src\common;..\src\libzzuf;%(AdditionalIncludeDirectories)
@@ -103,6 +163,32 @@
0x0409
+
+
+ ..\msvc;..\src\common;..\src\libzzuf;%(AdditionalIncludeDirectories)
+ WIN32;_WINDOWS;LIBZZUF;NDEBUG;_USRDLL;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ $(IntDir).libs/
+ Level3
+ ProgramDatabase
+ CompileAsC
+
+
+ imagehlp.lib;ws2_32.lib;%(AdditionalDependencies)
+ true
+ Windows
+ true
+ true
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+ false
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+ 0x0409
+
+
@@ -124,7 +210,9 @@
CompileAsCpp
+ CompileAsCpp
CompileAsCpp
+ CompileAsCpp
diff --git a/msvc/zzat.vcxproj b/msvc/zzat.vcxproj
index fb27e4c..3a91a77 100644
--- a/msvc/zzat.vcxproj
+++ b/msvc/zzat.vcxproj
@@ -5,10 +5,18 @@
Debug
Win32
+
+ Debug
+ x64
+
Release
Win32
+
+ Release
+ x64
+
{83987482-7F82-427E-7832-809F80AB809C}
@@ -19,34 +27,60 @@
Application
MultiByte
+
+ Application
+ MultiByte
+
Application
MultiByte
+
+ Application
+ MultiByte
+
+
+
+
+
+
+
<_ProjectFileVersion>10.0.21006.1
Debug\
+ Debug\
Debug\$(ProjectName)\
+ Debug\$(ProjectName)\
true
+ true
Release\
+ Release\
Release\$(ProjectName)\
+ Release\$(ProjectName)\
false
+ false
AllRules.ruleset
+ AllRules.ruleset
+
+
AllRules.ruleset
+ AllRules.ruleset
+
+
@@ -71,6 +105,27 @@
MachineX86
+
+
+ Disabled
+ ..\msvc;..\..\libcaca\caca;..\..\libcaca\caca\win32;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebug
+
+
+ Level3
+ ProgramDatabase
+ CompileAsC
+
+
+ ws2_32.lib;..\..\libcaca\win32\Debug\x64\libcaca.lib;%(AdditionalDependencies)
+ $(OutDir)zzat.exe
+ true
+ $(OutDir)zzat.pdb
+ Console
+
+
..\msvc;..\..\libcaca\caca;..\..\libcaca\caca\win32;%(AdditionalIncludeDirectories)
@@ -92,10 +147,32 @@
MachineX86
+
+
+ ..\msvc;..\..\libcaca\caca;..\..\libcaca\caca\win32;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Level3
+ ProgramDatabase
+ CompileAsC
+
+
+ ws2_32.lib;..\..\libcaca\win32\Release\x64\libcaca.lib;%(AdditionalDependencies)
+ $(OutDir)zzat.exe
+ true
+ Console
+ true
+ true
+
+
$(IntDir)%(FileName)1.obj
+ $(IntDir)%(FileName)1.obj
$(IntDir)%(FileName)1.obj
+ $(IntDir)%(FileName)1.obj
@@ -104,4 +181,4 @@
-
+
\ No newline at end of file
diff --git a/msvc/zznop.vcxproj b/msvc/zznop.vcxproj
index aab547f..1422eee 100644
--- a/msvc/zznop.vcxproj
+++ b/msvc/zznop.vcxproj
@@ -5,10 +5,18 @@
Debug
Win32
+
+ Debug
+ x64
+
Release
Win32
+
+ Release
+ x64
+
{04486051-18D2-402D-91C0-3E0A8F2FD0D7}
@@ -19,34 +27,60 @@
Application
MultiByte
+
+ Application
+ MultiByte
+
Application
MultiByte
+
+ Application
+ MultiByte
+
+
+
+
+
+
+
<_ProjectFileVersion>10.0.21006.1
Debug\
+ Debug\
Debug\$(ProjectName)\
+ Debug\$(ProjectName)\
true
+ true
Release\
+ Release\
Release\$(ProjectName)\
+ Release\$(ProjectName)\
false
+ false
AllRules.ruleset
+ AllRules.ruleset
+
+
AllRules.ruleset
+ AllRules.ruleset
+
+
@@ -71,6 +105,27 @@
MachineX86
+
+
+ Disabled
+ ..\msvc;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebug
+
+
+ Level3
+ ProgramDatabase
+ CompileAsC
+
+
+ ws2_32.lib;%(AdditionalDependencies)
+ $(OutDir)zznop.exe
+ true
+ $(OutDir)zznop.pdb
+ Console
+
+
..\msvc;%(AdditionalIncludeDirectories)
@@ -92,10 +147,32 @@
MachineX86
+
+
+ ..\msvc;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Level3
+ ProgramDatabase
+ CompileAsC
+
+
+ ws2_32.lib;%(AdditionalDependencies)
+ $(OutDir)zznop.exe
+ true
+ Console
+ true
+ true
+
+
$(IntDir)%(FileName)1.obj
+ $(IntDir)%(FileName)1.obj
$(IntDir)%(FileName)1.obj
+ $(IntDir)%(FileName)1.obj
diff --git a/msvc/zzuf.sln b/msvc/zzuf.sln
index 5556282..5aaf54a 100644
--- a/msvc/zzuf.sln
+++ b/msvc/zzuf.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual C++ Express 2010
+# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zzuf", "zzuf.vcxproj", "{2E5723ED-A886-45A9-AAAC-3D02F2EFC358}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzzuf", "libzzuf.vcxproj", "{E658DCE5-E1E5-41C8-910B-1CC2D73C435C}"
@@ -12,43 +12,43 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
- Debug|x64 = Debug|x64
+ Debug|Win64 = Debug|Win64
Release|Win32 = Release|Win32
- Release|x64 = Release|x64
+ Release|Win64 = Release|Win64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Debug|Win32.ActiveCfg = Debug|Win32
{2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Debug|Win32.Build.0 = Debug|Win32
- {2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Debug|x64.ActiveCfg = Debug|Win32
- {2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Debug|x64.Build.0 = Debug|Win32
+ {2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Debug|Win64.ActiveCfg = Debug|x64
+ {2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Debug|Win64.Build.0 = Debug|x64
{2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Release|Win32.ActiveCfg = Release|Win32
{2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Release|Win32.Build.0 = Release|Win32
- {2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Release|x64.ActiveCfg = Release|Win32
- {2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Release|x64.Build.0 = Release|Win32
+ {2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Release|Win64.ActiveCfg = Release|x64
+ {2E5723ED-A886-45A9-AAAC-3D02F2EFC358}.Release|Win64.Build.0 = Release|x64
{E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Debug|Win32.ActiveCfg = Debug|Win32
{E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Debug|Win32.Build.0 = Debug|Win32
- {E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Debug|x64.ActiveCfg = Debug|Win32
- {E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Debug|x64.Build.0 = Debug|Win32
+ {E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Debug|Win64.ActiveCfg = Debug|x64
+ {E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Debug|Win64.Build.0 = Debug|x64
{E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Release|Win32.ActiveCfg = Release|Win32
{E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Release|Win32.Build.0 = Release|Win32
- {E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Release|x64.ActiveCfg = Release|Win32
- {E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Release|x64.Build.0 = Release|Win32
+ {E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Release|Win64.ActiveCfg = Release|x64
+ {E658DCE5-E1E5-41C8-910B-1CC2D73C435C}.Release|Win64.Build.0 = Release|x64
{04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Debug|Win32.ActiveCfg = Debug|Win32
{04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Debug|Win32.Build.0 = Debug|Win32
- {04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Debug|x64.ActiveCfg = Debug|Win32
- {04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Debug|x64.Build.0 = Debug|Win32
+ {04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Debug|Win64.ActiveCfg = Debug|x64
+ {04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Debug|Win64.Build.0 = Debug|x64
{04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Release|Win32.ActiveCfg = Release|Win32
{04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Release|Win32.Build.0 = Release|Win32
- {04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Release|x64.ActiveCfg = Release|Win32
- {04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Release|x64.Build.0 = Release|Win32
+ {04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Release|Win64.ActiveCfg = Release|x64
+ {04486051-18D2-402D-91C0-3E0A8F2FD0D7}.Release|Win64.Build.0 = Release|x64
{83987482-7F82-427E-7832-809F80AB809C}.Debug|Win32.ActiveCfg = Debug|Win32
{83987482-7F82-427E-7832-809F80AB809C}.Debug|Win32.Build.0 = Debug|Win32
- {83987482-7F82-427E-7832-809F80AB809C}.Debug|x64.ActiveCfg = Debug|Win32
- {83987482-7F82-427E-7832-809F80AB809C}.Debug|x64.Build.0 = Debug|Win32
+ {83987482-7F82-427E-7832-809F80AB809C}.Debug|Win64.ActiveCfg = Debug|x64
+ {83987482-7F82-427E-7832-809F80AB809C}.Debug|Win64.Build.0 = Debug|x64
{83987482-7F82-427E-7832-809F80AB809C}.Release|Win32.ActiveCfg = Release|Win32
{83987482-7F82-427E-7832-809F80AB809C}.Release|Win32.Build.0 = Release|Win32
- {83987482-7F82-427E-7832-809F80AB809C}.Release|x64.ActiveCfg = Release|Win32
- {83987482-7F82-427E-7832-809F80AB809C}.Release|x64.Build.0 = Release|Win32
+ {83987482-7F82-427E-7832-809F80AB809C}.Release|Win64.ActiveCfg = Release|x64
+ {83987482-7F82-427E-7832-809F80AB809C}.Release|Win64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/msvc/zzuf.vcxproj b/msvc/zzuf.vcxproj
index 5dea2ff..97f4def 100644
--- a/msvc/zzuf.vcxproj
+++ b/msvc/zzuf.vcxproj
@@ -5,10 +5,18 @@
Debug
Win32
+
+ Debug
+ x64
+
Release
Win32
+
+ Release
+ x64
+
{2E5723ED-A886-45A9-AAAC-3D02F2EFC358}
@@ -19,34 +27,60 @@
Application
MultiByte
+
+ Application
+ MultiByte
+
Application
MultiByte
+
+ Application
+ MultiByte
+
+
+
+
+
+
+
<_ProjectFileVersion>10.0.21006.1
Debug\
+ Debug\
Debug\$(ProjectName)\
+ Debug\$(ProjectName)\
true
+ true
Release\
+ Release\
Release\$(ProjectName)\
+ Release\$(ProjectName)\
false
+ false
AllRules.ruleset
+ AllRules.ruleset
+
+
AllRules.ruleset
+ AllRules.ruleset
+
+
@@ -71,6 +105,27 @@
MachineX86
+
+
+ Disabled
+ ..\msvc;..\src\common;..\..\libcaca\caca;..\..\libcaca\caca\win32;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebug
+
+
+ Level3
+ ProgramDatabase
+ CompileAsC
+
+
+ ws2_32.lib;..\..\libcaca\win32\Debug\x64\libcaca.lib;%(AdditionalDependencies)
+ $(OutDir)zzuf.exe
+ true
+ $(OutDir)zzuf.pdb
+ Console
+
+
..\msvc;..\src\common;..\..\libcaca\caca;..\..\libcaca\caca\win32;%(AdditionalIncludeDirectories)
@@ -92,6 +147,26 @@
MachineX86
+
+
+ ..\msvc;..\src\common;..\..\libcaca\caca;..\..\libcaca\caca\win32;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreaded
+
+
+ Level3
+ ProgramDatabase
+ CompileAsC
+
+
+ ws2_32.lib;..\..\libcaca\win32\Release\x64\libcaca.lib;%(AdditionalDependencies)
+ $(OutDir)zzuf.exe
+ true
+ Console
+ true
+ true
+
+
@@ -112,7 +187,9 @@
CompileAsCpp
+ CompileAsCpp
CompileAsCpp
+ CompileAsCpp
diff --git a/src/libzzuf/sys.c b/src/libzzuf/sys.c
index b69086c..f5acf59 100644
--- a/src/libzzuf/sys.c
+++ b/src/libzzuf/sys.c
@@ -98,82 +98,208 @@ void _zz_sys_init(void)
#define MK_JMP_JD(dst, src) ((dst) - ((src) + 5))
+static int modrm_sib_size(uint8_t* code)
+{
+ static uint8_t modrm_size[] = { 0, 1, 4, 0 }; /* [reg ...], [reg ... + sbyte], [reg ... + sdword], reg */
+ uint8_t modrm = *code;
+
+ if (modrm == 0x05) /* [(rip) + sdword] */ return 1 + 4;
+
+ /* Does the instruciton have a SIB byte ? */
+ return 1 + (!!(((modrm & 0x7) == 0x4) && ((modrm >> 6) != 0x3))) + modrm_size[modrm >> 6];
+}
+
/* zz_lde is a _very_ simple length disassemble engine.
* x64 is not tested and should not work. */
-static int zz_lde(uint8_t *code, int required_size)
+static int zz_lde(uint8_t *code)
{
int insn_size = 0;
- static uint8_t modrm_size[] = { 0, 1, 4, 0 }; /* [reg ...], [reg ... + sbyte], [reg ... + sdword], reg */
- while (insn_size < required_size)
+ uint8_t opcd = code[insn_size++];
+ int imm_size = 4; /* Iv */
+
+#ifdef _M_AMD64
+ // REX prefix
+ if ((opcd & 0xf8) == 0x48)
{
- uint8_t opcd = code[insn_size++];
+ imm_size = 8; /* REX.W */
+ opcd = code[insn_size++];
+ }
+#endif
- /* Simple instructions should be placed here */
- switch (opcd)
- {
- case 0x68: insn_size += 4; continue; /* PUSH Iv */
- case 0x6a: insn_size += 1; continue; /* PUSH Ib */
- default: break;
- }
+ /* Simple instructions should be placed here */
+ switch (opcd)
+ {
+ case 0x68: insn_size += 4; break; /* PUSH Iv */
+ case 0x6a: insn_size += 1; break; /* PUSH Ib */
+ default: break;
+ }
- /* PUSH/POP rv */
- if ((opcd & 0xf0) == 0x50) continue;
+ /* PUSH/POP rv */
+ if ((opcd & 0xf0) == 0x50) return insn_size;
- /* MOV Ev, Gv or Gv, Ev */
- else if (opcd == 0x89 || opcd == 0x8b)
- {
- uint8_t modrm = code[insn_size++];
+ /* MNEM E?, G? or G?, E? */
+ switch (opcd)
+ {
+ case 0x89: /* mov Ev, Gv */
+ case 0x8b: /* mov Gv, Ev */
+ insn_size += modrm_sib_size(code + insn_size);
+ break;
- /* Does the instruciton have a SIB byte ? */
- if (((modrm & 0x7) == 0x4) && ((modrm >> 6) != 0x3))
- insn_size++;
+ case 0x80: /* Group#1 Eb, Ib */
+ case 0x82: /* Group#1 Eb, Ib */
+ case 0x83: /* Group#1 Ev, Ib */
+ insn_size += (modrm_sib_size(code + insn_size) + 1);
+ break;
- insn_size += modrm_size[modrm >> 6];
+ case 0x81: /* Group#1 Ev, Iz */
+ insn_size += (modrm_sib_size(code + insn_size) + 4);
+ break;
- continue;
- }
+ case 0xff:
+ if ((code[insn_size] & 0x38) == 0x30) /* PUSH Ev */
+ insn_size += modrm_sib_size(code + insn_size);
+ break;
-
- /* If we can't disassemble the current instruction, we give up */
- return -1;
+ default: break;
}
return insn_size;
}
+/* This function returns the required size to insert a patch */
+static int compute_patch_size(uint8_t *code, int required_size)
+{
+ int patch_size = 0;
+ while (patch_size < required_size)
+ {
+ int insn_size = zz_lde(code);
+ if (insn_size == 0) return -1;
+ patch_size += insn_size;
+ }
+ return patch_size;
+}
+
+static void make_jmp32(uint8_t *src, uint8_t *dst, uint8_t *code)
+{
+ *(uint8_t *)(code + 0) = 0xe9; /* JMP Jd */
+ *(uint32_t *)(code + 1) = (uint32_t)MK_JMP_JD(dst, src);
+}
+
+static void make_jmp64(uint8_t *dst, uint8_t *code)
+{
+ memcpy(code, "\x48\xb8", 2); /* MOV rAX, Iq */
+ *(uint64_t *)(code + 2) = (uint64_t)dst;
+ memcpy(code + 10, "\xff\xe0", 2); /* JMP rAX */
+}
+
+/* This function allocates and fills a trampoline for the function pointed by code. It also tries to handle some relocations. */
+static int make_trampoline(uint8_t *code, size_t patch_size, uint8_t **trampoline_buf, size_t *trampoline_size)
+{
+ uint8_t *trampoline;
+
+ *trampoline_buf = NULL;
+ *trampoline_size = 0;
+
+#ifdef _M_AMD64
+ {
+ size_t code_offset = 0;
+ size_t trampoline_offset = 0;
+ const size_t reloc_size = -7 /* size of mov rax, [rip + ...] */ +10 /* size of mov rax, Iq */;
+
+ trampoline = malloc(patch_size + reloc_size + 13); /* Worst case */
+ if (trampoline == NULL) return -1;
+ memset(trampoline, 0xcc, patch_size + 13);
+
+ while (code_offset < patch_size)
+ {
+ int insn_size = zz_lde(code + code_offset);
+ if (insn_size == 0) return -1;
+
+ /* mov rax, [rip + ...] is the signature for stack cookie */
+ if (!memcmp(code + code_offset, "\x48\x8b\x05", 3))
+ {
+ uint64_t *cookie_address = (uint64_t *)(code + code_offset + insn_size + *(uint32_t *)(code + code_offset + 3));
+ patch_size += reloc_size;
+
+ memcpy(trampoline + trampoline_offset, "\x48\xb8", 2); /* MOV rAX, Iq */
+ *(uint64_t *)(trampoline + trampoline_offset + 2) = *cookie_address;
+ trampoline_offset += 10;
+ }
+ else
+ {
+ *trampoline_size += insn_size;
+ memcpy(trampoline + trampoline_offset, code + code_offset, insn_size);
+ trampoline_offset += insn_size;
+ }
+
+ code_offset += insn_size;
+ }
+
+
+ /* We can't use make_jmp64 since rAX is used by the __security_cookie */
+ memcpy(trampoline + trampoline_offset, "\x49\xba", 2); /* MOV r10, Iq */
+ *(uint64_t *)(trampoline + trampoline_offset + 2) = (uint64_t)(code + code_offset);
+ memcpy(trampoline + trampoline_offset + 10, "\x41\xff\xe2", 3); /* JMP r10 */
+
+ *trampoline_buf = trampoline;
+ *trampoline_size = trampoline_offset;
+ return 0;
+ }
+#elif _M_IX86
+ trampoline = malloc(patch_size + 5);
+ if (trampoline == NULL) return -1;
+ memcpy(trampoline, code, patch_size);
+ make_jmp32(trampoline + patch_size, code + patch_size, trampoline + patch_size);
+
+ *trampoline_size = patch_size;
+ *trampoline_buf = trampoline;
+ return 0;
+#else
+# error Unsupported architecture !
+#endif
+}
+
/* This function allows to hook any API. To do so, it disassembles the beginning of the
* targeted function and looks for, at least, 5 bytes (size of JMP Jd).
* Then it writes a JMP Jv instruction to make the new_api executed.
* Finally, trampoline_api contains a wrapper to call in order to execute the original API */
static int hook_inline(uint8_t *old_api, uint8_t *new_api, uint8_t **trampoline_api)
{
- int res = -1;
- int patch_size = 0;
- uint8_t *jmp_prolog = NULL;
- uint8_t *trampoline = NULL;
+ int res = -1;
+ int required_size = 5;
+ int patch_size = 0;
+ uint8_t jmp_prolog[12];
+ uint8_t *trampoline = NULL;
+ size_t trampoline_size = 0;
DWORD old_prot;
- /* if we can't get enough byte, we quit */
- if ((patch_size = zz_lde(old_api, 5)) == -1)
- return -1;
-
- if ((jmp_prolog = malloc(patch_size)) == NULL) goto _out;
- memset(jmp_prolog, '\xcc', patch_size); /* We use 0xcc because the code after the jmp should be executed */
-
*trampoline_api = NULL;
- jmp_prolog[0] = '\xe9'; /* jmp Jd */
- *(uint32_t *)(&jmp_prolog[1]) = MK_JMP_JD(new_api, old_api);
+ memset(jmp_prolog, 0xcc, sizeof(jmp_prolog));
- trampoline = malloc(patch_size + 5); /* size of old byte + sizeof of jmp Jd */
- memcpy(trampoline, old_api, patch_size);
- *(uint8_t *)&trampoline[patch_size] = '\xe9'; /* jmp Jd */
- *(uint32_t *)&trampoline[patch_size + 1] = MK_JMP_JD(old_api + patch_size, trampoline + patch_size);
+#ifdef _M_AMD64
+ if (new_api - old_api > 0xffffffff)
+ {
+ required_size = 12;
+ make_jmp64(new_api, jmp_prolog);
+ }
+ else make_jmp32(old_api, new_api, jmp_prolog);
+#elif _M_IX86
+ make_jmp32(old_api, new_api, jmp_prolog);
+#else
+# error Unsupported architecture !
+#endif
+
+ /* if we can't get enough byte, we quit */
+ if ((patch_size = compute_patch_size(old_api, required_size)) == -1)
+ return -1;
+
+ if (make_trampoline(old_api, patch_size, &trampoline, &trampoline_size) < 0) goto _out;
/* We must make the trampoline executable, this line is required because of DEP */
/* NOTE: We _must_ set the write protection, otherwise the heap allocator will crash ! */
- if (!VirtualProtect(trampoline, patch_size + 5, PAGE_EXECUTE_READWRITE, &old_prot)) goto _out;
+ if (!VirtualProtect(trampoline, trampoline_size, PAGE_EXECUTE_READWRITE, &old_prot)) goto _out;
/* We patch the targeted API, so we must set it as writable */
if (!VirtualProtect(old_api, patch_size, PAGE_EXECUTE_READWRITE, &old_prot)) goto _out;
@@ -194,8 +320,6 @@ _out:
}
}
- if (jmp_prolog != NULL) free(jmp_prolog);
-
return res;
}
diff --git a/src/myfork.c b/src/myfork.c
index fcc7b72..7ee45cc 100644
--- a/src/myfork.c
+++ b/src/myfork.c
@@ -393,7 +393,36 @@ static int run_process(struct child *child, struct opts *opts, int pipes[][2])
static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib)
{
- int res = -1;
+#ifdef _M_AMD64
+# define InstructionPointer Rip
+# define StackPointer Rsp
+# define LoaderRegister Rcx
+# define LoadLibraryAOffset 0x15
+
+ /* This payload allows us to load arbitrary module located at the end of this buffer */
+ static uint8_t const ldr[] =
+ {
+ "\x55" /* push rbp */
+ "\x48\x89\xE5" /* mov rbp,rsp */
+ "\x48\x83\xEC\x20" /* sub rsp,byte +0x20 */
+ "\x48\x83\xE4\xF0" /* and rsp,byte -0x10 */
+ "\x48\x8D\x0D\x14\x00\x00\x00" /* lea rcx,[rel 0x27] */
+ "\x48\xB8________" /* mov rax, LoadLibraryA */
+ "\xFF\xD0" /* call rax */
+ "\x48\x85\xC0" /* test rax,rax */
+ "\x75\x01" /* jnz 0x25 */
+ "\xCC" /* int3 */
+ "\xC9" /* leave */
+ "\xC3" /* ret */
+ };
+
+#elif defined (_M_IX86)
+# define InstructionPointer Eip
+# define StackPointer Esp
+# define LoaderRegister Eax /* It seems the Windows loader store the oep as the first param
+ * but by a side effect it's also contained in eax register */
+# define ldr ldr32
+# define LoadLibraryAOffset 0x04
/* This payload allows us to load arbitrary module located at the end of this buffer */
static uint8_t const ldr[] =
@@ -409,6 +438,11 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib)
"\xC3" /* ret */
"\xE8\xED\xFF\xFF\xFF" /* call dword 0x3 */
};
+#else
+# error Unimplemented architecture !
+#endif
+
+ int res = -1;
/* We use this code to make the targeted process waits for us */
static uint8_t const wait[] = "\xeb\xfe"; /* jmp $-1 */
@@ -419,7 +453,7 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib)
void *thread = pinfo->hThread;
DWORD pid = pinfo->dwProcessId;
void *rldlib = NULL;
- DWORD written = 0;
+ SIZE_T written = 0;
DWORD old_prot = 0;
/* Payload */
@@ -428,21 +462,21 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib)
size_t pl_len = sizeof(ldr) - 1 + strlen(lib) + 1;
CONTEXT ctxt;
- DWORD oep; /* Original Entry Point */
+ DWORD_PTR oep; /* Original Entry Point */
/* Use the main thread to inject our library */
ctxt.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(thread, &ctxt)) goto _return;
/* Make the target program waits when it reachs the original entry point, because we can't do many thing from the windows loader */
- oep = ctxt.Eax;
+ oep = ctxt.LoaderRegister;
if (!ReadProcessMemory(process, (LPVOID)oep, orig_data, sizeof(orig_data), &written) || written != sizeof(orig_data)) goto _return; /* save original opcode */
if (!WriteProcessMemory(process, (LPVOID)oep, wait, wait_len , &written) || written != wait_len) goto _return; /* write jmp short $-1 */
if (!FlushInstructionCache(process, (LPVOID)oep, wait_len)) goto _return;
if (ResumeThread(thread) == (DWORD)-1) goto _return;
/* Stop when the program reachs the oep */
- while (oep != ctxt.Eip)
+ while (oep != ctxt.InstructionPointer)
{
if (!GetThreadContext(thread, &ctxt)) goto _return;
Sleep(10);
@@ -455,17 +489,17 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib)
if ((rpl = VirtualAllocEx(process, NULL, pl_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == NULL) goto _return;
- /* Emulate a call to the ldr code, thus the ret instruction from ldr will get eip back to the original entry point */
- ctxt.Esp -= 4;
- if (!WriteProcessMemory(process, (LPVOID)ctxt.Esp, &oep, sizeof(oep), &written) || written != sizeof(oep)) goto _return;
- ctxt.Eip = (DWORD)rpl;
+ /* Emulate a call to the ldr code, thus the ret instruction from ldr will get (e|r)ip back to the original entry point */
+ ctxt.StackPointer -= sizeof(oep);
+ if (!WriteProcessMemory(process, (LPVOID)ctxt.StackPointer, &oep, sizeof(oep), &written) || written != sizeof(oep)) goto _return;
+ ctxt.InstructionPointer = (DWORD_PTR)rpl;
if (!SetThreadContext(thread, &ctxt)) goto _return;
/* Forge the payload */
if ((pl = (uint8_t *)malloc(pl_len)) == NULL) goto _return;
memcpy(pl, ldr, sizeof(ldr) - 1);
- memcpy(pl + 4, &rldlib, sizeof(rldlib)); /* Write the address of LoadLibraryA */
- strcpy((char *)(pl + sizeof(ldr) - 1), lib); /* Write the first parameter of LoadLibraryA */
+ memcpy(pl + LoadLibraryAOffset, &rldlib, sizeof(rldlib)); /* Write the address of LoadLibraryA */
+ strcpy((char *)(pl + sizeof(ldr) - 1), lib); /* Write the first parameter of LoadLibraryA */
if (!WriteProcessMemory(process, rpl, pl, pl_len, &written) || written != pl_len) goto _return;
@@ -481,6 +515,11 @@ _return:
/* We must not free remote allocated memory since they will be used after the process will be resumed */
return res;
+
+#undef InstructionPointer
+#undef StackPointer
+#undef LoaderRegister
+#undef LoadLibraryAOffset
}
static void *get_proc_address(void *process, DWORD pid, const char *func)
@@ -490,7 +529,7 @@ static void *get_proc_address(void *process, DWORD pid, const char *func)
MODULEENTRY32 entry;
void *ret = 0;
- DWORD tmp;
+ SIZE_T tmp;
void *list;
int i, k;
diff --git a/src/zzuf.c b/src/zzuf.c
index 50d2f97..14165ed 100644
--- a/src/zzuf.c
+++ b/src/zzuf.c
@@ -28,12 +28,12 @@
#if defined HAVE_UNISTD_H
# include /* for read(), write(), close() */
#endif
-#if defined HAVE_REGEX_H
-# if _WIN32
-# include "com_regexp.hpp"
-# else
-# include
-# endif
+#if defined HAVE_REGEX_H
+# if _WIN32
+# include "com_regexp.hpp"
+# else
+# include
+# endif
#endif
#if defined HAVE_WINSOCK2_H
# include /* for fd_set */
@@ -500,7 +500,10 @@ int main(int argc, char *argv[])
/* Allocate memory for children handling */
opts->child = malloc(opts->maxchild * sizeof(struct child));
for(i = 0; i < opts->maxchild; i++)
+ {
opts->child[i].status = STATUS_FREE;
+ memset(opts->child[i].fd, -1, sizeof(opts->child->fd));
+ }
opts->nchild = 0;
/* Create new argv */