1- #pragma once
21/*
3- // Original assembly.hpp functions moved to SafetyHook
4- */
2+ * Injectors - Useful Assembly Stuff
3+ *
4+ * Copyright (C) 2012-2014 LINK/2012 <[email protected] > 5+ *
6+ * This software is provided 'as-is', without any express or implied
7+ * warranty. In no event will the authors be held liable for any damages
8+ * arising from the use of this software.
9+ *
10+ * Permission is granted to anyone to use this software for any purpose,
11+ * including commercial applications, and to alter it and redistribute it
12+ * freely, subject to the following restrictions:
13+ *
14+ * 1. The origin of this software must not be misrepresented; you must not
15+ * claim that you wrote the original software. If you use this software
16+ * in a product, an acknowledgment in the product documentation would be
17+ * appreciated but is not required.
18+ *
19+ * 2. Altered source versions must be plainly marked as such, and must not be
20+ * misrepresented as being the original software.
21+ *
22+ * 3. This notice may not be removed or altered from any source
23+ * distribution.
24+ *
25+ */
26+ #pragma once
27+
28+ // This header is very restrict about compiler and architecture
29+ #ifndef _MSC_VER
30+ #warning This header is tested only with MSVC
31+ #endif
32+ #if ! (defined (_M_IX86) || defined (_X86_))
33+ #error Supported only in x86
34+ #endif
35+
36+ //
37+ #include < utility>
38+ #include < memory>
539#include " injector.hpp"
6- #include " ..\safetyhook\safetyhook.hpp"
740
841namespace injector
942{
10- using reg_pack = SafetyHookContext;
43+ struct reg_pack
44+ {
45+ // The ordering is very important, don't change
46+ // The first field is the last to be pushed and first to be poped
47+
48+ // PUSHFD / POPFD
49+ uint32_t ef;
50+
51+ // PUSHAD/POPAD -- must be the lastest fields (because of esp)
52+ union
53+ {
54+ uint32_t arr[8 ];
55+ struct { uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; };
56+ };
57+
58+ enum reg_name {
59+ reg_edi, reg_esi, reg_ebp, reg_esp, reg_ebx, reg_edx, reg_ecx, reg_eax
60+ };
61+
62+ enum ef_flag {
63+ carry_flag = 0 , parity_flag = 2 , adjust_flag = 4 , zero_flag = 6 , sign_flag = 7 ,
64+ direction_flag = 10 , overflow_flag = 11
65+ };
66+
67+ uint32_t & operator [](size_t i)
68+ { return this ->arr [i]; }
69+ const uint32_t & operator [](size_t i) const
70+ { return this ->arr [i]; }
71+
72+ template <uint32_t bit> // bit starts from 0, use ef_flag enum
73+ bool flag ()
74+ {
75+ return (this ->ef & (1 << bit)) != 0 ;
76+ }
77+
78+ bool jnb ()
79+ {
80+ return flag<carry_flag>() == false ;
81+ }
82+ };
83+
84+ // Lowest level stuff (actual assembly) goes on the following namespace
85+ // PRIVATE! Skip this, not interesting for you.
1186 namespace injector_asm
1287 {
1388 // Wrapper functor, so the assembly can use some templating
@@ -22,28 +97,68 @@ namespace injector
2297
2398 // Constructs a reg_pack and calls the wrapper functor
2499 template <class W > // where W is of type wrapper
25- inline void make_reg_pack_and_call (memory_pointer_tr at )
100+ inline void __declspec (naked) make_reg_pack_and_call( )
26101 {
27- static std::vector<SafetyHookMid> pack;
28- auto m = safetyhook::create_mid (at. get < void >(), [](reg_pack& ctx)
102+ # ifdef _MSC_VER // MSVC is much more flexible when we're talking about inline assembly
103+ _asm
29104 {
30- W::call (&ctx);
31- });
32- pack.emplace_back (std::move (m));
105+ // Construct the reg_pack structure on the stack
106+ pushad // Pushes general purposes registers to reg_pack
107+ add [esp+12 ], 4 // Add 4 to reg_pack::esp 'cuz of our return pointer, let it be as before this func is called
108+ pushfd // Pushes EFLAGS to reg_pack
109+
110+ // Call wrapper sending reg_pack as parameter
111+ push esp
112+ call W::call
113+ add esp, 4
114+
115+ // Destructs the reg_pack from the stack
116+ sub [esp+12 +4 ], 4 // Fix reg_pack::esp before popping it (doesn't make a difference though) (+4 because eflags)
117+ popfd // Warning: Do not use any instruction that changes EFLAGS after this (-> sub affects EF!! <-)
118+ popad
119+
120+ // Back to normal flow
121+ ret
122+ }
123+ #else // MINGW needs -masm=intel
124+ asm
125+ (
126+ // Construct the reg_pack structure on the stack
127+ " pushad\n " // Pushes general purposes registers to reg_pack
128+ " add DWORD PTR [esp+12], 4\n " // Add 4 to reg_pack::esp 'cuz of our return pointer, let it be as before this func is called
129+ " pushfd\n " // Pushes EFLAGS to reg_pack
130+
131+ // Call wrapper sending reg_pack as parameter
132+ " push esp\n "
133+ );
134+ // https://stackoverflow.com/questions/3467180/direct-c-function-call-using-gccs-inline-assembly
135+ asm (" call %P0" : : " i" (W::call)); // FIXME: missing clobbers
136+ asm (
137+ " add esp, 4\n "
138+
139+ // Destructs the reg_pack from the stack
140+ " sub DWORD PTR [esp+12+4], 4\n " // Fix reg_pack::esp before popping it (doesn't make a difference though) (+4 because eflags)
141+ " popfd\n " // Warning: Do not use any instruction that changes EFLAGS after this (-> sub affects EF!! <-)
142+ " popad\n "
143+
144+ // Back to normal flow
145+ " ret\n "
146+ );
147+ #endif
33148 }
34149 };
35150
151+
36152 /*
37153 * MakeInline
38154 * Makes inline assembly (but not assembly, an actual functor of type FuncT) at address
39155 */
40156 template <class FuncT >
41157 void MakeInline (memory_pointer_tr at)
42158 {
43- MakeNOP (at, 5 );
44159 typedef injector_asm::wrapper<FuncT> functor;
45160 if (false ) functor::call (nullptr ); // To instantiate the template, if not done _asm will fail
46- injector_asm::make_reg_pack_and_call<functor>(at );
161+ MakeCALL (at, injector_asm::make_reg_pack_and_call<functor>);
47162 }
48163
49164 /*
@@ -102,8 +217,6 @@ namespace injector
102217 template <uintptr_t at, class FuncT >
103218 void MakeInline (FuncT func)
104219 {
105- MakeNOP (at, 5 );
106220 return MakeInline<at, at+5 , FuncT>(func);
107221 }
108222};
109-
0 commit comments