-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTrampolines.hpp
2821 lines (2336 loc) · 112 KB
/
Trampolines.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//
// Copyright © 2003-2010, by YaPB Development Team. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Trampolines.hpp
//
// Namespace: Trampolines
//
// Version: $ID:$
//
#if defined _MSC_VER && _MSC_VER > 1000
# pragma once
#endif // if defined _MSC_VER && _MSC_VER > 1000
#ifndef TRAMPOLINES_INCLUDED
#define TRAMPOLINES_INCLUDED
namespace Trampolines
{
// Reliability checks.
CompileTimeAssert (sizeof (int) == sizeof (long));
CompileTimeAssert (sizeof (bool) == sizeof (char));
CompileTimeAssert (sizeof (bool) == 1u);
CompileTimeAssert (sizeof (BOOL) == 4u);
CompileTimeAssert (sizeof (char) == 1u);
CompileTimeAssert (sizeof (short) == 2u);
CompileTimeAssert (sizeof (int) == 4u);
CompileTimeAssert (sizeof (long) == 4u);
CompileTimeAssert (sizeof (enum Test_t) == 4u);
CompileTimeAssert (sizeof (long long) == 8u);
CompileTimeAssert (sizeof (float) == 4u);
CompileTimeAssert (sizeof (double) == 8u);
/**
* List of x86 bytecodes for creating basic trampolines at runtime.
* -
* These are defined here so that, should
* the need ever arise, this can be ported
* to other architectures fairly painlessly.
*/
namespace Bytecode
{
/** 32 bit 32 bit 32 bit 32 bit
•———————————————————• •———————————————————• •———————————————————• •———————————————————•
| EAX | | ECX | | EDX | | EBX |
|———————————————————| |———————————————————| |———————————————————| |———————————————————|
| | AX | | | CX | | | DX | | | BX |
|———————————————————| |———————————————————| |———————————————————| |———————————————————|
| | AH | AL | | | CH | CL | | | DH | DL | | | BH | BL |
•———————————————————• •———————————————————• •———————————————————• •———————————————————•
•———————————————————• •———————————————————• •———————————————————• •———————————————————•
| ESP | | EBP | | ESI | | EDI |
|———————————————————| |———————————————————| |———————————————————| |———————————————————|
| | SP | | | BP | | | SI | | | DI |
|———————————————————| |———————————————————| |———————————————————| |———————————————————|
| | | SPL | | | | BP | | | | SIL | | | | DIL |
•———————————————————• •———————————————————• •———————————————————• •———————————————————•
*/
/**
* EAX - result of call.
* ESP - stack pointer to function arguments.
* ECX - pointer to 'this' pointer in member functions.
*/
const unsigned char Pointer8Size (sizeof (unsigned char));
const unsigned char Pointer16Size (sizeof (unsigned short));
const unsigned char Pointer32Size (sizeof (void *));
const unsigned char Pointer64Size (sizeof (unsigned long long));
// Values to replace....
const unsigned char RawNumber[4u] = {0xDE, 0xFA, 0xAD, 0xDE}; // Raw number (DEADFADEh)
const unsigned char SomeByteValue/*[sizeof (char)]*/ (0xFF); // Some byte value (0xFF)
const unsigned char SomeShortValue[sizeof (short)] = {0xCD, 0xAB}; // Some short value (0xABCD)
const unsigned char SomeValue[sizeof (int)] = {SomeByteValue, SomeByteValue, SomeByteValue, SomeByteValue}; // Some value (0xFF, 0xFF, 0xFF, 0xFF)
// Opcodes with encoding information....
const unsigned char WildCard (0x2A); // Unknown opcode - used for signature scanning. ('*')
const unsigned char Breakpoint (0xCC); // int 3 (no extra encoding)
const unsigned char Nop (0x90); // nop (no extra encoding)
const unsigned char PushEAX (0x50); // push eax (encoding is +r)
const unsigned char PushECX (0x51); // push ecx
const unsigned char PushEDX (0x52); // push edx
const unsigned char PushEBX (0x53); // push ebx
const unsigned char PushEBP (0x55); // push ebp
const unsigned char PushESI (0x56); // push esi
const unsigned char PushEDI (0x57); // push edi
const unsigned char PushESPWithOffset8[2u] = {0xFF, 0x74}; // push [esp+'.']
const unsigned char PushEBPWithOffset8[2u] = {0xFF, 0x75}; // push [ebp+'.']
const unsigned char Push8 (0x6A); // push '.' (encoding is <imm8>)
const unsigned char Push32 (0x68); // push '....' (encoding is <imm32>)
const unsigned char Push32Size (sizeof (Push32) + Pointer32Size); // size of the push instruction
const unsigned char MoveRegisterImmediately (0xB8); // mov eax, '....' (encoding is +r <imm32>)
const unsigned char MoveESPToEBP[2u] = {0x89, 0xE5}; // mov ebp, esp
const unsigned char MoveValue32ToECX[2u] = {0x8B, 0x0D}; // mov ecx, '....'
const unsigned char MoveValue32ToECXSize (sizeof (MoveValue32ToECX) + Pointer32Size);
const unsigned char MoveESIToValue32[2u] = {0x89, 0x35}; // mov '....', esi
const unsigned char MoveESIToValue32Size (sizeof (MoveESIToValue32) + Pointer32Size);
const unsigned char MoveValue32ToEAX (0xA1); // mov eax, '....'
const unsigned char MoveValue32ToEAXSize (sizeof (MoveValue32ToEAX) + Pointer32Size);
const unsigned char MovePointer32ToPointer32[] = {0xC7, 0x05}; // mov '....', '....'
const unsigned char MovePointer32ToPointer32Size (sizeof (MovePointer32ToPointer32) + Pointer32Size + Pointer32Size);
const unsigned char CallEAX[2u] = {0xFF, 0xD0}; // call eax
const unsigned char AddESP8[2u] = {0x83, 0xC4}; // add esp, '.'
const unsigned char AddESP8Size (sizeof (AddESP8) + Pointer8Size);
const unsigned char AddESP32[2u] = {0x81, 0xC4}; // add esp, '....'
const unsigned char AddESP32Size (sizeof (AddESP32) + Pointer32Size);
const unsigned char PopECX (0x59); // pop ecx
const unsigned char PopEBP (0x5D); // pop ebp
const unsigned char PopESI (0x5E); // pop esi
const unsigned char Return (0xC3); // ret (no extra encoding)
const unsigned char ReturnNearValue (0xC2); // retn '..' (encoding is <imm16>)
const unsigned char PopRegister (0x58); // pop eax (encoding is +r)
const unsigned char CallImmediately32 (0xE8); // call '....' (relative call, <imm32>)
const unsigned char CallImmediately32Size (sizeof (CallImmediately32) + Pointer32Size);
const unsigned char JumpImmediately8 (0xEB); // jmp '.' (encoding is imm8)
const unsigned char JumpImmediately8Size (sizeof (JumpImmediately8) + Pointer8Size);
const unsigned char JumpImmediately32 (0xE9); // jmp '....' (encoding is imm32)
const unsigned char JumpImmediately32Size (sizeof (JumpImmediately32) + Pointer32Size); // size of the jump-to instruction
const unsigned char JumpIfZeroImmediately32[] = {0x0F, 0x84}; // jz '....' (encoding is imm32)
const unsigned char JumpIfZeroImmediately32Size (sizeof (JumpIfZeroImmediately32) + Pointer32Size); // size of the jump-to instruction
const unsigned char JumpIfNotZeroImmediately32[] = {0x0F, 0x85}; // jnz '....' (encoding is imm32)
const unsigned char JumpIfNotZeroImmediately32Size (sizeof (JumpIfNotZeroImmediately32) + Pointer32Size); // size of the jump-to instruction
/**
* Prologue for a void function Clobbers EBX and EAX
*/
const unsigned char codeVoidPrologue[sizeof (PushEBP) + sizeof (MoveESPToEBP) + sizeof (PushEAX)] =
{
PushEBP, // push ebp
MoveESPToEBP[0u], MoveESPToEBP[1u], // mov ebp, esp
PushEAX // push eax
};
/**
* Prologue for a function that returns Clobbers EBX, EAX too but not after call.
*/
const unsigned char codeReturnPrologue[sizeof (PushEBP) + sizeof (MoveESPToEBP)] =
{
PushEBP, // push ebp
MoveESPToEBP[0u], MoveESPToEBP[1u] // mov ebp, esp
};
const unsigned char codeThisReturnPrologue[sizeof (PushEBP) + sizeof (MoveESPToEBP)] =
{
PushEBP, // push ebp
MoveESPToEBP[0u], MoveESPToEBP[1u] // mov ebp, esp
};
/**
* Takes a paramter from the trampoline's stack and pushes it onto the target's stack.
*/
const unsigned char codePushParam[sizeof (PushEBPWithOffset8) + sizeof (SomeByteValue)] =
{
PushEBPWithOffset8[0u], PushEBPWithOffset8[1u], SomeByteValue // push [ebp+'SomeByteValue']
};
/**
* Offset of 'codePushParam' to modify at runtime that contains the stack offset.
*/
const unsigned char codePushParamReplace (sizeof (PushEBPWithOffset8));
/**
* Takes the "this" pointer from the trampoline and pushes it onto the target's stack.
*/
const unsigned char codePushThis (0x51); // push ecx
/**
* Pushes a raw number onto the target's stack.
*/
const unsigned char codePushID[Push32Size] =
{
Push32, RawNumber[0u], RawNumber[1u], RawNumber[2u], RawNumber[3u] // push 'RawNumber'
};
/**
* Offset of 'codePushID' to modify at runtime to contain the number to push.
*/
const unsigned char codePushIDReplace (sizeof (Push32));
/**
* Call our procedure.
*/
const unsigned char codeCall[sizeof (MoveRegisterImmediately) + sizeof (RawNumber) + sizeof (CallEAX)] =
{
MoveRegisterImmediately, RawNumber[0u], RawNumber[1u], RawNumber[2u], RawNumber[3u], // mov eax, 'RawNumber'
CallEAX[0u], CallEAX[1u] // call eax
};
/**
* Offset of 'codeCall' to modify at runtime to contain the pointer to the function.
*/
const unsigned char codeCallReplace (sizeof (MoveRegisterImmediately));
/**
* Adds to ESP, freeing up stack space
*/
const unsigned char codeFreeStack8[sizeof (AddESP8) + sizeof (SomeByteValue)] =
{
AddESP8[0u], AddESP8[1u], SomeByteValue // add esp, 'SomeByteValue'
};
const unsigned char codeFreeStack32[sizeof (AddESP32) + sizeof (SomeValue)] =
{
AddESP32[0u], AddESP32[1u], SomeValue[0u], SomeValue[1u], SomeValue[2u], SomeValue[3u] // add esp, 'SomeValue'
};
/**
* Offset of 'codeFreeStack*' to modify at runtime to contain how much data to free.
*/
const unsigned char codeFreeStackReplace (sizeof (AddESP32));
/**
* Epilogue of a simple return function.
*/
const unsigned char codeReturnEpilogue[sizeof (PopEBP) + sizeof (Return)] =
{
PopEBP, // pop ebp
Return // ret
};
const unsigned char codeReturnEpilogueN[sizeof (PopEBP) + sizeof (ReturnNearValue) + sizeof (SomeShortValue)] =
{
PopEBP, // pop ebp
ReturnNearValue, SomeShortValue[0u], SomeShortValue[1u] // retn 'SomeShortValue'
};
const unsigned char codeReturnEpilogueNReplace (sizeof (PopEBP) + sizeof (ReturnNearValue));
/**
* Epilogue of a void return function.
*/
const unsigned char codeVoidEpilogue[sizeof (PopRegister) + sizeof (PopEBP) + sizeof (Return)] =
{
PopRegister, // pop eax
PopEBP, // pop ebp
Return // ret
};
const unsigned char codeVoidEpilogueN[sizeof (PopRegister) + sizeof (PopEBP) + sizeof (ReturnNearValue) + sizeof (SomeShortValue)] =
{
PopRegister, // pop eax
PopEBP, // pop ebp
ReturnNearValue, SomeShortValue[0u], SomeShortValue[1u] // retn 'SomeShortValue'
};
const unsigned char codeVoidEpilogueNReplace (sizeof (PopRegister) + sizeof (PopEBP) + sizeof (ReturnNearValue));
#pragma pack (push, 1) // Structures must be packed (byte-aligned) (Very important!)
struct MoveESIToValue32_t
{
unsigned char opcodes[sizeof (MoveESIToValue32)]; // 0x8935 = "mov '....', esi" (from 'MoveESIToValue32')
union /* Unnamed */
{
unsigned char bytes[Pointer32Size]; // Raw bytes.
void *pointer; // Pointer to assign at.
void **pointerToPointer; // Pointer to pointer to assign at.
unsigned int value; // Value to assign at.
};
}; // sizeof (MoveESIToValue32_t) == 6 (1.5)
template <const unsigned char instruction, typename functionType> struct BaseCallOrJumpImmediately32_t
{
private:
const unsigned char opcode; // "instruction '....'" (relative call, <imm32>) (from 'instruction')
public:
union /* Unnamed */
{
unsigned char bytes[Pointer32Size]; // Raw bytes.
void *pointer; // Pointer to call.
unsigned int value; // Value to call.
functionType function; // Function to call.
};
inline BaseCallOrJumpImmediately32_t (void *const address = *reinterpret_cast <void **> (const_cast <unsigned char *> (RawNumber))) :
opcode (instruction),
pointer (address)
{ /* VOID */ }
inline BaseCallOrJumpImmediately32_t (const BaseCallOrJumpImmediately32_t &otherCallImmediately32) :
opcode (instruction),
pointer (otherCallImmediately32.pointer)
{ /* VOID */ }
inline BaseCallOrJumpImmediately32_t &operator = (const BaseCallOrJumpImmediately32_t &otherCallImmediately32)
{
pointer = otherCallImmediately32.pointer;
return *this;
}
}; // sizeof (BaseCallOrJumpImmediately32_t) == 5 (1.25)
template <typename functionType = void *> struct CallImmediately32_t : BaseCallOrJumpImmediately32_t <CallImmediately32, functionType> { /* VOID */ };
template <typename functionType = void *> struct JumpImmediately32_t : BaseCallOrJumpImmediately32_t <JumpImmediately32, functionType> { /* VOID */ };
#pragma pack (pop) // Reset default packing.
// Reliability checks.
CompileTimeAssert (sizeof (MoveESIToValue32_t) == MoveValue32ToECXSize);
CompileTimeAssert (sizeof (CallImmediately32_t <>) == CallImmediately32Size);
CompileTimeAssert (sizeof (JumpImmediately32_t <>) == JumpImmediately32Size);
}
// Ideas by Don Clugston.
// Check out his excellent paper: http://www.codeproject.com/cpp/FastDelegate.asp
namespace
{
// GenericClass is a fake class, ONLY used to provide a type.
// It is vitally important that it is never defined, so that the compiler doesn't
// think it can optimize the invocation. For example, Borland generates simpler
// code if it knows the class only uses single inheritance.
// Compilers using Microsoft's structure need to be treated as a special case.
// For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP
// (4 bytes), even when the /vmg option is used. Declaring an empty class
// would give 16 byte pointers in this case....
class __single_inheritance GenericClass;
// ...but for Codeplay, an empty class *always* gives 4 byte pointers.
// If compiled with the /clr option ("managed C++"), the JIT compiler thinks
// it needs to load GenericClass before it can call any of its functions,
// (compiles OK but crashes at runtime!), so we need to declare an
// empty class to make it happy.
// Codeplay and VC4 can't cope with the unknown_inheritance case either.
class GenericClass { /* Empty */ }; // Sigscanned member functions are casted to member function pointers of this class and called with member function pointer syntax.
class EmptyClass { /* Empty */ }; // An empty class. No inheritance used. Used for original-function-call hacks.
// virtual inheritance is a real nuisance. It's inefficient and complicated.
// On MSVC and Intel, there isn't enough information in the pointer itself to
// enable conversion to a closure pointer. Earlier versions of this code didn't
// work for all cases, and generated a compile-time error instead.
// But a very clever hack invented by John M. Dlugosz solves this problem.
// My code is somewhat different to his: I have no asm code, and I make no
// assumptions about the calling convention that is used.
// In VC++ and ICL, a virtual_inheritance member pointer
// is internally defined as:
struct MicrosoftVirtualMFP_t
{
void (GenericClass::*codeptr) (void); // points to the actual member function
int delta; // #bytes to be added to the 'this' pointer
int virtualFunctionTableIndex; // or 0 if no virtual inheritance
};
// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the
// m_codeptr member is *always* called, regardless of the values of the other
// members. (This is *not* true for other compilers, eg GCC, which obtain the
// function address from the vtable if a virtual function is being called).
// Dlugosz's trick is to make the codeptr point to a probe function which
// returns the 'this' pointer that was used.
// Define a generic class that uses virtual inheritance.
// It has a trival member function that returns the value of the 'this' pointer.
struct GenericVirtualClass : virtual public GenericClass
{
typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType) (void);
inline GenericVirtualClass *const GetThis (void) { return this; }
};
// The size of a single inheritance member function pointer.
const unsigned char MemoryFunctionPointerSize = sizeof (void (GenericClass::*) (void));
}
inline const int GetVirtualFunctionTableOffset (const void *const memberFunctionPointer)
{
const unsigned char *address (static_cast <const unsigned char *> (memberFunctionPointer));
if (*address == Bytecode::JumpImmediately32) // Jmp
{
// May or may not be!
// Check where it'd jump
address += Bytecode::JumpImmediately32Size + *reinterpret_cast <const unsigned long *> (address + sizeof (Bytecode::JumpImmediately32));
}
// Check whether it's a virtual function call
// They look like this:
// 004125A0 8B 01 mov eax, dword ptr [ecx]
// 004125A2 FF 60 04 jmp dword ptr [eax+4]
// ==OR==
// 00411B80 8B 01 mov eax, dword ptr [ecx]
// 00411B82 FF A0 18 03 00 00 jmp dword ptr [eax+318h]
// However, for vararg functions, they look like this:
// 0048F0B0 8B 44 24 04 mov eax, dword ptr [esp+4]
// 0048F0B4 8B 00 mov eax, dword ptr [eax]
// 0048F0B6 FF 60 08 jmp dword ptr [eax+8]
// ==OR==
// 0048F0B0 8B 44 24 04 mov eax, dword ptr [esp+4]
// 0048F0B4 8B 00 mov eax, dword ptr [eax]
// 00411B82 FF A0 18 03 00 00 jmp dword ptr [eax+318h]
// With varargs, the this pointer is passed as if it was the first argument
if (address[0u] != 0x8B)
return -1;
if (address[1u] == 0x44 && address[2u] == 0x24 && address[3u] == 0x04 && address[4u] == 0x8B && address[5u] == 0x00)
address += 6u;
else if (address[1u] == 0x01)
address += 2u;
else
return -1;
if (*address != 0xFF)
return -1;
if (*++address == 0x60)
return *++address / 4u;
if (*address == 0xA0)
return *reinterpret_cast <const unsigned int *> (++address) / 4u;
if (*address == 0x20)
return 0;
return -1;
}
namespace
{
// implicit_cast < type >
// I believe this was originally going to be in the C++ standard but
// was left out by accident. It's even milder than static_cast.
// I use it instead of static_cast<> to emphasize that I'm not doing
// anything nasty.
// Usage is identical to static_cast<>.
template <typename OutputClass, typename InputClass> inline OutputClass implicit_cast (InputClass input) { return input; }
// horrible_cast < type >
// This is truly evil. It completely subverts C++'s type system, allowing you
// to cast from any class to any other class. Technically, using a union
// to perform the cast is undefined behaviour (even in C). But we can see if
// it is OK by checking that the union is the same size as each of its members.
// horrible_cast<> should only be used for compiler-specific workarounds.
// Usage is identical to reinterpret_cast<>.
template <typename OutputClass, typename InputClass> inline OutputClass horrible_cast (const InputClass input)
{
// This union is declared outside the horrible_cast because BCC 5.5.1
// can't inline a function with a nested class, and gives a warning.
union /* Unnamed */
{
OutputClass out;
InputClass in;
} horribleUnion;
// Cause a compile-time error if in, out and horribleUnion are not the same size.
// If the compile fails here, it means the compiler has peculiar
// unions which would prevent the cast from working.
CompileTimeAssert (sizeof (InputClass) == sizeof (horribleUnion) && sizeof (InputClass) == sizeof (OutputClass)); // Cant use horrible case?
horribleUnion.in = input;
return horribleUnion.out;
}
}
struct MemoryFunctionInformation_t
{
int thisPointerOffset; // The this pointer the function expects to be called with
// If -1, you need to call the GetFuncInfo_GetThisPtr function
int virtualFunctionTableIndex; // The function's index in the vtable (-1-function not virtual, 0-based, 1=second entry, 2=third entry, ...)
int virtualFunctionTableOffset; // The vtable pointer
inline MemoryFunctionInformation_t (void) :
thisPointerOffset (-1),
virtualFunctionTableIndex (-1),
virtualFunctionTableOffset (0)
{ /* VOID */ }
};
// general case -- don't know how to get info. Force a compile failure.
template <const unsigned short size> struct MFI_Impl
{
template <typename MFP> static inline void GetFunctionInformation (MFP *mfp, MemoryFunctionInformation_t &out)
{
// Unsupported member function type -- force a compile failure. (it's illegal to have a array with negative size).
static char weird_memfunc_pointer_exclamation_mark_arrow_error[static_cast <int> (size) - 1000];
}
};
// For compilers where all member func ptrs are the same size, everything goes here.
// For non-standard compilers, only single_inheritance classes go here.
template <> struct MFI_Impl <MemoryFunctionPointerSize> // simple ones
{
template <typename MFP> static inline void GetFunctionInformation (MFP mfp, MemoryFunctionInformation_t &out)
{
out.virtualFunctionTableIndex = GetVirtualFunctionTableOffset (*reinterpret_cast <void **> (&mfp));
out.thisPointerOffset = 0;
out.virtualFunctionTableOffset = 0;
}
};
// __multiple_inheritance classes go here
template <> struct MFI_Impl <2u * MemoryFunctionPointerSize> // more complicated ones!
{
template <typename MFP> static inline void GetFunctionInformation (MFP mfp, MemoryFunctionInformation_t &out)
{
struct MSVC_MemFunPtr2
{
void *funcadr; // points to the actual member function
int delta; // #BYTES to be added to the 'this' pointer
};
out.virtualFunctionTableIndex = GetVirtualFunctionTableOffset (*reinterpret_cast <void **> (&mfp));
out.thisPointerOffset = reinterpret_cast <MSVC_MemFunPtr2 *> (&mfp)->delta;
out.virtualFunctionTableOffset = 0;
}
};
// __virtual_inheritance classes go here
template <> struct MFI_Impl <3u * MemoryFunctionPointerSize> // WOW IT'S GETTING BIGGER OMGOMOGMG
{
template <typename MFP> static inline void GetFunctionInformation (MFP mfp, MemoryFunctionInformation_t &out)
{
out.virtualFunctionTableIndex = GetVirtualFunctionTableOffset (*reinterpret_cast <void **> (&mfp));
// This pointer
/*
union /* Unnamed *//*
{
MFP func;
GenericClass * (T::*ProbeFunc) (void);
MicrosoftVirtualMFP_t s;
} u;
u.func = mfp;
union /* Unnamed *//*
{
GenericVirtualClass::ProbePtrType virtfunc;
MicrosoftVirtualMFP_t s;
} u2;
// Check that the horrible_cast<>s will work
typedef int ERROR_CantUsehorrible_cast[sizeof(mfp)==sizeof(u.s)
&& sizeof(mfp)==sizeof(u.ProbeFunc)
&& sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];
// Unfortunately, taking the address of a MF prevents it from being inlined, so
// this next line can't be completely optimised away by the compiler.
u2.virtfunc = &GenericVirtualClass::GetThis;
u.s.codeptr = u2.s.codeptr;
out.thisPointerOffset = (reinterpret_cast<T*>(NULL)->*u.ProbeFunc) ();
*/
out.thisPointerOffset = -1;
out.virtualFunctionTableOffset = 0;
}
};
// Nasty hack for Microsoft and Intel (IA32 and Itanium)
// unknown_inheritance classes go here
// This is probably the ugliest bit of code I've ever written. Look at the casts!
// There is a compiler bug in MSVC6 which prevents it from using this code.
template <> struct MFI_Impl <4u * MemoryFunctionPointerSize> // THE BIGGEST ONE!!!1GABEN
{
template <typename MFP> static inline void GetFunctionInformation (MFP mfp, MemoryFunctionInformation_t &out)
{
out.virtualFunctionTableIndex = GetVirtualFunctionTableOffset (*reinterpret_cast <void **> (&mfp));
// The member function pointer is 16 bytes long. We can't use a normal cast, but
// we can use a union to do the conversion.
union /* Unnamed */
{
MFP func;
// In VC++ and ICL, an unknown_inheritance member pointer is internally defined as:
struct
{
void *m_funcaddress; // points to the actual member function
int delta; // #bytes to be added to the 'this' pointer
int vtordisp; // #bytes to add to 'this' to find the vtable
int virtualFunctionTableIndex; // or 0 if no virtual inheritance
} s;
} u;
// Check that the horrible_cast will work
typedef int ERROR_CantUsehorrible_cast[sizeof (u.func) == sizeof (u.s) ? 1 : -1];
u.func = mfp;
if (u.s.virtualFunctionTableIndex > 0)
{
// Virtual inheritance is used
/*
// First, get to the vtable.
// It is 'vtordisp' bytes from the start of the class.
int *vtable (*reinterpret_cast<int **> (reinterpret_cast<char *>(thisptr) + u.s.vtordisp));
// 'virtualFunctionTableIndex' tells us where in the table we should be looking.
const int virtual_delta = u.s.vtordisp + *reinterpret_cast <const int *> (reinterpret_cast <const char *> (vtable) + u.s.virtualFunctionTableIndex);
// The int at 'virtual_delta' gives us the amount to add to 'this'.
// Finally we can add the three components together. Phew!
out.thisptr = reinterpret_cast <void *> (reinterpret_cast <char *> (thisptr) + u.s.delta + virtual_delta);
*/
out.virtualFunctionTableOffset = u.s.vtordisp;
out.thisPointerOffset = -1;
}
else
{
out.virtualFunctionTableOffset = out.virtualFunctionTableIndex < 0 ? 0 : u.s.delta;
out.thisPointerOffset = u.s.delta;
}
};
};
// This version does not take a this pointer
// Useful for hookdecls, as they ensure that mfp is correct through a static_cast
template <typename X> inline void GetFunctionInformation (X mfp, MemoryFunctionInformation_t &out)
{
MFI_Impl <sizeof (mfp)>::GetFunctionInformation (mfp, out);
}
// Versions which do take a this
template <typename X, typename Y, typename RetType>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12, typename Param13>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12, typename Param13>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12, typename Param13, typename Param14>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12, typename Param13, typename Param14>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12, typename Param13, typename Param14, typename Param15>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12, typename Param13, typename Param14, typename Param15>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12, typename Param13, typename Param14, typename Param15, typename Param16>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, ...), MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, ...) = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
template <typename X, typename Y, typename RetType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8, typename Param9, typename Param10, typename Param11, typename Param12, typename Param13, typename Param14, typename Param15, typename Param16>
inline void GetFunctionInformation (Y *ptr, RetType (X::*mfp) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, ...) const, MemoryFunctionInformation_t &out)
{
RetType (Y::*mfp2) (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, ...) const = mfp;
MFI_Impl <sizeof (mfp2)>::GetFunctionInformation (mfp2, out);
}
inline void *const GetRealAddressOfRelativeAddress8 (const void *const relativeAddress)
{
// Reliability check.
InternalAssert (relativeAddress != NULL);
return reinterpret_cast <void *> (static_cast <const unsigned char *const> (relativeAddress)[0u] + reinterpret_cast <const unsigned int> (relativeAddress) + Bytecode::Pointer8Size);
}
inline void *const GetRelativeAddressOfRealAddress8 (const void *const callAddress, const void *const realAddress)
{
// Reliability checks.
InternalAssert (callAddress != NULL);
InternalAssert (realAddress != NULL);
return reinterpret_cast <void *> (reinterpret_cast <const unsigned int> (realAddress) - reinterpret_cast <const unsigned int> (callAddress) - Bytecode::Pointer8Size);
}
inline void *const GetRealAddressOfRelativeAddress16 (const void *const relativeAddress)
{
// Reliability check.
InternalAssert (relativeAddress != NULL);
return reinterpret_cast <void *> (static_cast <const unsigned short *const> (relativeAddress)[0u] + reinterpret_cast <const unsigned int> (relativeAddress) + Bytecode::Pointer16Size);
}
inline void *const GetRelativeAddressOfRealAddress16 (const void *const callAddress, const void *const realAddress)
{
// Reliability checks.
InternalAssert (callAddress != NULL);
InternalAssert (realAddress != NULL);
return reinterpret_cast <void *> (reinterpret_cast <const unsigned int> (realAddress) - reinterpret_cast <const unsigned int> (callAddress) - Bytecode::Pointer16Size);
}
inline void *const GetRealAddressOfRelativeAddress32 (const void *const relativeAddress)
{
// Reliability check.
InternalAssert (relativeAddress != NULL);
return reinterpret_cast <void *> (static_cast <const unsigned int *const> (relativeAddress)[0u] + reinterpret_cast <const unsigned int> (relativeAddress) + Bytecode::Pointer32Size);
}
inline void *const GetRelativeAddressOfRealAddress32 (const void *const callAddress, const void *const realAddress)
{
// Reliability checks.
InternalAssert (callAddress != NULL);
InternalAssert (realAddress != NULL);
return reinterpret_cast <void *> (reinterpret_cast <const unsigned int> (realAddress) - reinterpret_cast <const unsigned int> (callAddress) - Bytecode::Pointer32Size);
}
template <typename elementType> inline const bool PatchMemoryData (void *const realAddress, const elementType &newValue)
{
/* unsigned long oldProtectFlags (0ul);
if (!::VirtualProtect (realAddress, sizeof (elementType), PAGE_EXECUTE_READWRITE, &oldProtectFlags))*/
if (!VirtualProtect (realAddress, sizeof (elementType), PAGE_EXECUTE_READWRITE))
return false;
static_cast <elementType *const> (realAddress)[0u] = newValue;
// return oldProtectFlags == PAGE_EXECUTE_READWRITE || VirtualProtect (realAddress, sizeof (elementType), oldProtectFlags);
return true;
}
inline const bool RedirectFunctionJump32 (void *const callAddress, const void *const newFunctionAddress)
{
// Reliability checks.
InternalAssert (callAddress != NULL);
InternalAssert ((static_cast <unsigned char *const> (callAddress) - sizeof (Bytecode::JumpImmediately32))[0u] == Bytecode::JumpImmediately32);
return PatchMemoryData <unsigned int> (callAddress, reinterpret_cast <unsigned int> (GetRelativeAddressOfRealAddress32 (callAddress, newFunctionAddress))/* calculate relative offset */);
}
inline const bool WriteFunctionJump32 (void *const address, const void *const newFunctionAddress)
{
// Reliability checks.
InternalAssert (address != NULL);
unsigned char *const tempByteAddress (static_cast <unsigned char *> (address));
if (!PatchMemoryData <unsigned char> (tempByteAddress, Bytecode::JumpImmediately32))
return false;
return RedirectFunctionJump32 (tempByteAddress + sizeof (Bytecode::JumpImmediately32), newFunctionAddress);
}
inline const bool RedirectFunctionCall32 (void *const callAddress, const void *const newFunctionAddress)
{
// Reliability checks.
InternalAssert (callAddress != NULL);
InternalAssert ((static_cast <unsigned char *const> (callAddress) - sizeof (Bytecode::CallImmediately32))[0u] == Bytecode::CallImmediately32);
return PatchMemoryData <unsigned int> (callAddress, reinterpret_cast <unsigned int> (GetRelativeAddressOfRealAddress32 (callAddress, newFunctionAddress))/* calculate relative offset */);
}
inline const bool RedirectFunctionCall32 (void *const callAddress, const void *const newFunctionAddress, const void *&originalFunctionAddress)
{
// Save the original function address at first....
originalFunctionAddress = GetRealAddressOfRelativeAddress32 (callAddress);