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 */