├── .github
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── .gitignore
├── AntiDumpFix.pas
├── BeaEngineDelphi32.pas
├── BeaEngineLib.obj
├── Debugger.pas
├── Dumper.pas
├── Magicmida.dpr
├── Magicmida.dproj
├── Magicmida.exe.manifest
├── Magicmida.res
├── PEInfo.pas
├── Patcher.pas
├── README.md
├── Tracer.pas
├── Unit2.dfm
├── Unit2.pas
├── Utils.pas
├── fatal.ico
├── good_or_tick.ico
├── information.ico
├── scylla_hide.ini
└── tree_2.ico
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report about an issue with Magicmida
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.exe
2 | *.dll
3 | *.local
4 | *.identcache
5 | Win32/
6 | __history/
7 |
--------------------------------------------------------------------------------
/AntiDumpFix.pas:
--------------------------------------------------------------------------------
1 | unit AntiDumpFix;
2 |
3 | interface
4 |
5 | uses Windows, Utils;
6 |
7 | type
8 | // This fixes only one type of anti dump, and it's not guaranteed that it'll be the type used for the OEP.
9 | // If your binary uses virtualization in other parts of the program, it will very likely crash.
10 | // Other anti dump types check various fields in the PE header of kernel32.dll. Dumps won't run
11 | // on other systems/after rebooting because the DLL base will have changed.
12 | TAntiDumpFixer = class
13 | private
14 | FhProcess: THandle;
15 | FImageBase: NativeUInt;
16 |
17 | function RPM(Address: NativeUInt; Buf: Pointer; BufSize: NativeUInt): Boolean;
18 | public
19 | constructor Create(hProcess: THandle; AImageBase: NativeUInt);
20 |
21 | procedure RedirectOEP(OEP, IAT: NativeUInt);
22 | end;
23 |
24 | implementation
25 |
26 | { TAntiDumpFixer }
27 |
28 | constructor TAntiDumpFixer.Create(hProcess: THandle; AImageBase: NativeUInt);
29 | begin
30 | FhProcess := hProcess;
31 | FImageBase := AImageBase;
32 | end;
33 |
34 | function TAntiDumpFixer.RPM(Address: NativeUInt; Buf: Pointer; BufSize: NativeUInt): Boolean;
35 | begin
36 | Result := ReadProcessMemory(FhProcess, Pointer(Address), Buf, BufSize, BufSize);
37 | end;
38 |
39 | procedure TAntiDumpFixer.RedirectOEP(OEP, IAT: NativeUInt);
40 | const
41 | PUSH_ARGS_RW_PROTECT: array[0..14] of Byte = ($6A, $00, $54, $6A, $04, $68, $00, $04, $00, $00, $68, $00, $00, $40, $00);
42 | PUSH_ARGS_OLD_PROTECT: array[0..14] of Byte = ($54, $FF, $74, $24, $04, $68, $00, $04, $00, $00, $68, $00, $00, $40, $00);
43 | var
44 | Displ: UInt32;
45 | NewCode: packed record
46 | PushArgs1: array[0..High(PUSH_ARGS_RW_PROTECT)] of Byte;
47 | CallInstr1: UInt16;
48 | VirtualProtectAddr1: UInt32;
49 |
50 | MovInstr: UInt16;
51 | OptHdrEntrypoint: UInt32;
52 | Entrypoint: UInt32;
53 |
54 | PushArgs2: array[0..High(PUSH_ARGS_OLD_PROTECT)] of Byte;
55 | CallInstr2: UInt16;
56 | VirtualProtectAddr2: UInt32;
57 | PopStack: Byte;
58 |
59 | JmpInstr: Byte;
60 | JmpDispl: UInt32;
61 | end;
62 | LfaNew: UInt32;
63 | VProtectAddr: NativeUInt;
64 | VProtectIAT, i: UInt32;
65 | IATData: array[0..511] of NativeUInt;
66 | begin
67 | RPM(OEP + 1, @Displ, 4);
68 |
69 | VProtectAddr := NativeUInt(GetProcAddress(GetModuleHandle(kernel32), 'VirtualProtect'));
70 | VProtectIAT := 0;
71 | RPM(IAT, @IATData, SizeOf(IATData));
72 | for i := 0 to High(IATData) do
73 | if IATData[i] = VProtectAddr then
74 | begin
75 | VProtectIAT := IAT + i * 4;
76 | Break;
77 | end;
78 |
79 | if VProtectIAT = 0 then
80 | begin
81 | Log(ltFatal, 'VirtualProtect not found in IAT');
82 | Exit;
83 | end;
84 |
85 | // VirtualProtect($400000, $400, PAGE_READWRITE, OldProtect)
86 | Move(PUSH_ARGS_RW_PROTECT, NewCode.PushArgs1, Length(NewCode.PushArgs1));
87 | NewCode.CallInstr1 := $15FF;
88 | NewCode.VirtualProtectAddr1 := VProtectIAT;
89 |
90 | // mov dword ptr [AddressOfEntryPoint], ThemidaEntrypoint
91 | NewCode.MovInstr := $05C7;
92 | if not RPM(FImageBase + $3C, @LfaNew, 4) or not RPM(FImageBase + LfaNew + $28, @NewCode.Entrypoint, 4) then
93 | begin
94 | Log(ltFatal, 'ReadProcessMemory failed');
95 | Exit;
96 | end;
97 | NewCode.OptHdrEntrypoint := FImageBase + LfaNew + $28;
98 |
99 | // VirtualProtect($400000, $400, OldProtect, _)
100 | Move(PUSH_ARGS_OLD_PROTECT, NewCode.PushArgs2, Length(NewCode.PushArgs2));
101 | NewCode.CallInstr2 := $15FF;
102 | NewCode.VirtualProtectAddr2 := VProtectIAT;
103 | // pop eax (undo initial "push 0" for OldProtect)
104 | NewCode.PopStack := $58;
105 |
106 | // jmp vm
107 | NewCode.JmpInstr := $E9;
108 | NewCode.JmpDispl := Displ - (SizeOf(NewCode) - 5);
109 |
110 | if WriteProcessMemory(FhProcess, Pointer(OEP), @NewCode, SizeOf(NewCode), NativeUInt(nil^)) then
111 | begin
112 | Log(ltGood, 'Installed VM anti-dump mitigation at OEP');
113 | Log(ltInfo, 'NOTE: We assume there is enough space at the entrypoint, which may not be the case in every binary.');
114 | end
115 | else
116 | Log(ltFatal, 'WriteProcessMemory failed');
117 | end;
118 |
119 | end.
120 |
--------------------------------------------------------------------------------
/BeaEngineDelphi32.pas:
--------------------------------------------------------------------------------
1 | // ====================================================================
2 | //
3 | // Delphi Static lib for BeaEngine 4.x
4 | //
5 | // upDate: 2010-Jan-9
6 | // v0.4 support Delphi7 - Delphi2010
7 | // ====================================================================
8 | // BeaEngine.pas convert by Vince
9 | // updated by kao
10 | // ====================================================================
11 | // [+] BranchTaken,BranchNotTaken added in TPREFIXINFO v3.1.0
12 | unit BeaEngineDelphi32;
13 | // ====================================================================
14 | // Default link type is static lib
15 | // comment below line to switch link with DLL
16 | // ====================================================================
17 | // {$DEFINE USEDLL}
18 | // ====================================================================
19 | // Copyright 2006-2009, BeatriX
20 | // File coded by BeatriX
21 | //
22 | // This file is part of BeaEngine.
23 | //
24 | // BeaEngine is free software: you can redistribute it and/or modify
25 | // it under the terms of the GNU Lesser General Public License as published by
26 | // the Free Software Foundation, either version 3 of the License, or
27 | // (at your option) any later version.
28 | //
29 | // BeaEngine is distributed in the hope that it will be useful,
30 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
31 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 | // GNU Lesser General Public License for more details.
33 | //
34 | // You should have received a copy of the GNU Lesser General Public License
35 | // along with BeaEngine. If not, see .
36 |
37 | interface
38 |
39 | uses Windows,SysUtils;
40 |
41 | const
42 | INSTRUCT_LENGTH = 64;
43 |
44 |
45 | type
46 |
47 | TREX_Struct = packed record
48 | W_ : BYTE;
49 | R_ : BYTE;
50 | X_ : BYTE;
51 | B_ : BYTE;
52 | state : BYTE;
53 | end;
54 |
55 | type
56 |
57 | TPREFIXINFO = packed record
58 | Number : longint;
59 | NbUndefined : longint;
60 | LockPrefix : BYTE;
61 | OperandSize : BYTE;
62 | AddressSize : BYTE;
63 | RepnePrefix : BYTE;
64 | RepPrefix : BYTE;
65 | FSPrefix : BYTE;
66 | SSPrefix : BYTE;
67 | GSPrefix : BYTE;
68 | ESPrefix : BYTE;
69 | CSPrefix : BYTE;
70 | DSPrefix : BYTE;
71 | BranchTaken : BYTE; //v3.1.0 added 2009-11-05
72 | BranchNotTaken : BYTE; //v3.1.0 added 2009-11-05
73 | REX : TREX_Struct;
74 | alignment : array[0..1] of AnsiChar;
75 | end;
76 |
77 | type
78 |
79 | TEFLStruct = packed record
80 | OF_ : BYTE;
81 | SF_ : BYTE;
82 | ZF_ : BYTE;
83 | AF_ : BYTE;
84 | PF_ : BYTE;
85 | CF_ : BYTE;
86 | TF_ : BYTE;
87 | IF_ : BYTE;
88 | DF_ : BYTE;
89 | NT_ : BYTE;
90 | RF_ : BYTE;
91 | alignment : BYTE;
92 | end;
93 |
94 | type
95 |
96 | TMEMORYTYPE = packed record
97 | BaseRegister : longint;
98 | IndexRegister : longint;
99 | Scale : longint;
100 | Displacement : int64;
101 | end;
102 |
103 | type
104 |
105 | TINSTRTYPE = packed record
106 | Category : longint;
107 | Opcode : longint;
108 | Mnemonic : array[0..15] of AnsiChar;
109 | BranchType : longint;
110 | Flags : TEFLStruct;
111 | AddrValue : int64;
112 | Immediat : int64;
113 | ImplicitModifiedRegs : longint;
114 | end;
115 |
116 | type
117 |
118 | TARGTYPE = packed record
119 | ArgMnemonic : array[0..63] of AnsiChar;
120 | ArgType : longint;
121 | ArgSize : longint;
122 | ArgPosition : longint;
123 | AccessMode : longint;
124 | Memory : TMEMORYTYPE;
125 | SegmentReg : longint;
126 | end;
127 |
128 | type
129 |
130 | _Disasm = packed record
131 | EIP : longint;
132 | VirtualAddr : int64;
133 | SecurityBlock : longint;
134 | CompleteInstr : array[0..(INSTRUCT_LENGTH)-1] of AnsiChar;
135 | Archi : longint;
136 | Options : int64;
137 | Instruction : TINSTRTYPE;
138 | Argument1 : TARGTYPE;
139 | Argument2 : TARGTYPE;
140 | Argument3 : TARGTYPE;
141 | Prefix : TPREFIXINFO;
142 | Reserved_ : array[0..39] of longint;
143 | end;
144 | TDISASM = _Disasm;
145 | PDISASM = ^_Disasm;
146 | LPDISASM = ^_Disasm;
147 |
148 | const
149 | ESReg = 1;
150 | DSReg = 2;
151 | FSReg = 3;
152 | GSReg = 4;
153 | CSReg = 5;
154 | SSReg = 6;
155 | InvalidPrefix = 4;
156 | SuperfluousPrefix = 2;
157 | NotUsedPrefix = 0;
158 | MandatoryPrefix = 8;
159 | InUsePrefix = 1;
160 |
161 |
162 | type
163 | INSTRUCTION_TYPE = Longint;
164 | Const
165 | GENERAL_PURPOSE_INSTRUCTION = $10000;
166 | FPU_INSTRUCTION = $20000;
167 | MMX_INSTRUCTION = $40000;
168 | SSE_INSTRUCTION = $80000;
169 | SSE2_INSTRUCTION = $100000;
170 | SSE3_INSTRUCTION = $200000;
171 | SSSE3_INSTRUCTION = $400000;
172 | SSE41_INSTRUCTION = $800000;
173 | SSE42_INSTRUCTION = $1000000;
174 | SYSTEM_INSTRUCTION = $2000000;
175 | VM_INSTRUCTION = $4000000;
176 | UNDOCUMENTED_INSTRUCTION = $8000000;
177 | AMD_INSTRUCTION = $10000000;
178 | ILLEGAL_INSTRUCTION = $20000000;
179 | AES_INSTRUCTION = $40000000;
180 | CLMUL_INSTRUCTION = $80000000;
181 |
182 | DATA_TRANSFER = $1;
183 | ARITHMETIC_INSTRUCTION = 2;
184 | LOGICAL_INSTRUCTION = 3;
185 | SHIFT_ROTATE = 4;
186 | BIT_BYTE = 5;
187 | CONTROL_TRANSFER = 6;
188 | STRING_INSTRUCTION = 7;
189 | InOutINSTRUCTION = 8;
190 | ENTER_LEAVE_INSTRUCTION = 9;
191 | FLAG_CONTROL_INSTRUCTION = 10;
192 | SEGMENT_REGISTER = 11;
193 | MISCELLANEOUS_INSTRUCTION = 12;
194 | COMPARISON_INSTRUCTION = 13;
195 | LOGARITHMIC_INSTRUCTION = 14;
196 | TRIGONOMETRIC_INSTRUCTION = 15;
197 | UNSUPPORTED_INSTRUCTION = 16;
198 | LOAD_CONSTANTS = 17;
199 | FPUCONTROL = 18;
200 | STATE_MANAGEMENT = 19;
201 | CONVERSION_INSTRUCTION = 20;
202 | SHUFFLE_UNPACK = 21;
203 | PACKED_SINGLE_PRECISION = 22;
204 | SIMD128bits = 23;
205 | SIMD64bits = 24;
206 | CACHEABILITY_CONTROL = 25;
207 | FP_INTEGER_CONVERSION = 26;
208 | SPECIALIZED_128bits = 27;
209 | SIMD_FP_PACKED = 28;
210 | SIMD_FP_HORIZONTAL = 29;
211 | AGENT_SYNCHRONISATION = 30;
212 | PACKED_ALIGN_RIGHT = 31;
213 | PACKED_SIGN = 32;
214 | PACKED_BLENDING_INSTRUCTION = 33;
215 | PACKED_TEST = 34;
216 | PACKED_MINMAX = 35;
217 | HORIZONTAL_SEARCH = 36;
218 | PACKED_EQUALITY = 37;
219 | STREAMING_LOAD = 38;
220 | INSERTION_EXTRACTION = 39;
221 | DOT_PRODUCT = 40;
222 | SAD_INSTRUCTION = 41;
223 | ACCELERATOR_INSTRUCTION = 42; // crc32, popcnt (sse4.2)
224 | ROUND_INSTRUCTION = 43;
225 |
226 |
227 | type
228 | EFLAGS_STATES = Longint;
229 | Const
230 | TE_ = 1;
231 | MO_ = 2;
232 | RE_ = 4;
233 | SE_ = 8;
234 | UN_ = $10;
235 | PR_ = $20;
236 |
237 |
238 | type
239 | BRANCH_TYPE = Longint;
240 | Const
241 | JO = 1;
242 | JC = 2;
243 | JE = 3;
244 | JA = 4;
245 | JS = 5;
246 | JP = 6;
247 | JL = 7;
248 | JG = 8;
249 | JB = 2;
250 | JECXZ = 10;
251 | JmpType = 11;
252 | CallType = 12;
253 | RetType = 13;
254 | JNO = -(1);
255 | JNC = -(2);
256 | JNE = -(3);
257 | JNA = -(4);
258 | JNS = -(5);
259 | JNP = -(6);
260 | JNL = -(7);
261 | JNG = -(8);
262 | JNB = -(2);
263 |
264 |
265 | type
266 | ARGUMENTS_TYPE = Longint;
267 | Const
268 | NO_ARGUMENT = $10000000;
269 | REGISTER_TYPE = $20000000;
270 | MEMORY_TYPE = $40000000;
271 | CONSTANT_TYPE = $80000000;
272 |
273 | MMX_REG = $10000;
274 | GENERAL_REG = $20000;
275 | FPU_REG = $40000;
276 | SSE_REG = $80000;
277 | CR_REG = $100000;
278 | DR_REG = $200000;
279 | SPECIAL_REG = $400000;
280 | MEMORY_MANAGEMENT_REG = $800000;
281 | SEGMENT_REG = $1000000;
282 |
283 | RELATIVE_ = $4000000;
284 | ABSOLUTE_ = $8000000;
285 |
286 | READ = $1;
287 | WRITE = $2;
288 |
289 | REG0 = $1;
290 | REG1 = $2;
291 | REG2 = $4;
292 | REG3 = $8;
293 | REG4 = $10;
294 | REG5 = $20;
295 | REG6 = $40;
296 | REG7 = $80;
297 | REG8 = $100;
298 | REG9 = $200;
299 | REG10 = $400;
300 | REG11 = $800;
301 | REG12 = $1000;
302 | REG13 = $2000;
303 | REG14 = $4000;
304 | REG15 = $8000;
305 |
306 | type
307 | SPECIAL_INFO = Longint;
308 | Const
309 | UNKNOWN_OPCODE = -(1);
310 | OUT_OF_BLOCK = 0;
311 | { === mask = 0xff }
312 | NoTabulation = $00000000;
313 | Tabulation = $00000001;
314 | { === mask = 0xff00 }
315 | MasmSyntax = $00000000;
316 | GoAsmSyntax = $00000100;
317 | NasmSyntax = $00000200;
318 | ATSyntax = $00000400;
319 | { === mask = 0xff0000 }
320 | PrefixedNumeral = $00010000;
321 | SuffixedNumeral = $00000000;
322 | { === mask = 0xff000000 }
323 | ShowSegmentRegs = $01000000;
324 | LowPosition = 0;
325 | HighPosition = 1;
326 |
327 |
328 | function Disasm(var aDisAsm:TDISASM):longint;stdcall;
329 | function BeaEngineVersion:longint;stdcall;
330 | function BeaEngineRevision:longint;stdcall;
331 |
332 | implementation
333 | {$IFNDEF USEDLL}
334 | {$L BeaEngineLib.obj}
335 |
336 | function strcmp(Str1, Str2: PAnsiChar): Integer;cdecl;
337 | begin
338 | Result := SysUtils.StrComp(Str1, Str2);
339 | end;
340 |
341 | function strcpy(dest, src: PAnsiChar): PAnsiChar;cdecl;
342 | begin
343 | Result := SysUtils.StrCopy(dest, src);
344 | end;
345 |
346 | function strlen(s: PAnsiChar): Cardinal; cdecl;
347 | begin
348 | Result := SysUtils.StrLen(s);
349 | end;
350 |
351 | function memset(Destination: Pointer; C: Integer; Count: Cardinal): Pointer; cdecl;
352 | begin
353 | FillMemory(Destination, Count, C);
354 | Result := Destination;
355 | end;
356 |
357 | function sprintf(Buffer, Format: PAnsiChar):longint; varargs; cdecl; external user32 name 'wsprintfA';
358 |
359 | function Disasm(var aDisAsm:TDISASM):longint;stdcall;external;
360 | function BeaEngineVersion:longint;stdcall;external;
361 | function BeaEngineRevision:longint;stdcall;external;
362 |
363 | {$ELSE}
364 |
365 | function Disasm(var aDisAsm:TDISASM):longint;stdcall;external 'BeaEngine.DLL' name '_Disasm@4';
366 | function BeaEngineVersion:longint;stdcall;external 'BeaEngine.DLL' name '_BeaEngineVersion@0';
367 | function BeaEngineRevision:longint;stdcall;external 'BeaEngine.DLL' name '_BeaEngineRevision@0';
368 |
369 | {$ENDIF}
370 |
371 | end.
372 |
--------------------------------------------------------------------------------
/BeaEngineLib.obj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hendi48/Magicmida/58b895a1918d718d4c1d9383595dfbda8620dbf3/BeaEngineLib.obj
--------------------------------------------------------------------------------
/Dumper.pas:
--------------------------------------------------------------------------------
1 | unit Dumper;
2 |
3 | interface
4 |
5 | uses Windows, SysUtils, Classes, Generics.Collections, TlHelp32, PEInfo, Utils;
6 |
7 | const
8 | MAX_IAT_SIZE = $2000; // max 2048 imports
9 |
10 | type
11 | TExportTable = TDictionary;
12 |
13 | TRemoteModule = record
14 | Base, EndOff: PByte;
15 | Name: string;
16 | ExportTbl: TExportTable;
17 | end;
18 | PRemoteModule = ^TRemoteModule;
19 |
20 | TForwardDict = TDictionary;
21 |
22 | TImportThunk = class
23 | public
24 | Module: PRemoteModule;
25 | Name: string;
26 | Addresses: TList;
27 |
28 | constructor Create(RM: PRemoteModule);
29 | destructor Destroy; override;
30 | end;
31 |
32 | TDumper = class
33 | private
34 | FProcess: TProcessInformation;
35 | FOEP, FIAT, FImageBase: NativeUInt;
36 | FForwards: TForwardDict; // Key: NTDLL, Value: kernel32 (points to API)
37 | FForwardsType2: TForwardDict; // Key: NTDLL, Value: user32 (points to fwd-string)
38 | FForwardsOle32: TForwardDict; // Key: combase, Value: ole32
39 | FForwardsNetapi32: TForwardDict; // Key: netutils, Value: netapi32
40 | FForwardsCrypt32: TForwardDict; // Key: DPAPI, Value: crypt32
41 | FForwardsDbghelp: TForwardDict; // Key: dbgcore, Value: dbghelp
42 | FForwardsKernelbase: TForwardDict; // Key: NTDLL, Value: kernelbase (Win8 sync APIs like WakeByAddressAll)
43 | FAllModules: TList;
44 | FIATImage: PByte;
45 | FIATImageSize: Cardinal;
46 |
47 | FUsrPath: PChar;
48 | FHUsr: HMODULE;
49 |
50 | procedure CollectNTFwd; overload;
51 | procedure CollectForwards(Fwds: TForwardDict; hModReal, hModScan: HMODULE); overload;
52 | procedure GatherModuleExportsFromRemoteProcess(M: PRemoteModule);
53 | procedure TakeModuleSnapshot;
54 | function GetLocalProcAddr(hModule: HMODULE; ProcName: PAnsiChar): Pointer;
55 | function RPM(Address: NativeUInt; Buf: Pointer; BufSize: NativeUInt): Boolean;
56 | public
57 | constructor Create(const AProcess: TProcessInformation; AImageBase, AOEP: UIntPtr);
58 | destructor Destroy; override;
59 |
60 | function Process: TPEHeader;
61 | procedure DumpToFile(const FileName: string; PE: TPEHeader);
62 |
63 | function IsAPIAddress(Address: NativeUInt): Boolean;
64 |
65 | property IAT: NativeUInt read FIAT write FIAT; // Virtual address of IAT in target
66 | end;
67 |
68 | implementation
69 |
70 | uses Debugger;
71 |
72 | { TDumper }
73 |
74 | constructor TDumper.Create(const AProcess: TProcessInformation; AImageBase, AOEP: UIntPtr);
75 | begin
76 | FProcess := AProcess;
77 | FOEP := AOEP;
78 | FImageBase := AImageBase;
79 |
80 | if Win32MajorVersion > 5 then
81 | begin
82 | FUsrPath := PChar(ExtractFilePath(ParamStr(0)) + 'mmusr32.dll');
83 | CopyFile('C:\Windows\system32\user32.dll', FUsrPath, False);
84 | FHUsr := LoadLibraryEx(FUsrPath, 0, $20) - 2;
85 | end;
86 |
87 | FForwards := TForwardDict.Create(32);
88 | FForwardsType2 := TForwardDict.Create(16);
89 | FForwardsOle32 := TForwardDict.Create(32);
90 | FForwardsNetapi32 := TForwardDict.Create(32);
91 | FForwardsCrypt32 := TForwardDict.Create(16);
92 | FForwardsDbghelp := TForwardDict.Create(16);
93 | FForwardsKernelbase := TForwardDict.Create(16);
94 | CollectNTFwd;
95 | end;
96 |
97 | destructor TDumper.Destroy;
98 | var
99 | RM: PRemoteModule;
100 | begin
101 | FForwards.Free;
102 | FForwardsType2.Free;
103 | FForwardsOle32.Free;
104 | FForwardsNetapi32.Free;
105 | FForwardsCrypt32.Free;
106 | FForwardsDbghelp.Free;
107 | FForwardsKernelbase.Free;
108 |
109 | if FAllModules <> nil then
110 | begin
111 | for RM in FAllModules do
112 | begin
113 | RM.ExportTbl.Free;
114 | Dispose(RM);
115 | end;
116 | FAllModules.Free;
117 | end;
118 |
119 | if FIATImage <> nil then
120 | FreeMem(FIATImage);
121 |
122 | if FHUsr <> 0 then
123 | begin
124 | FreeLibrary(FHUsr + 2);
125 | Windows.DeleteFile(FUsrPath);
126 | end;
127 |
128 | inherited;
129 | end;
130 |
131 | procedure TDumper.CollectNTFwd;
132 | var
133 | hNetapi, hSrvcli, hCrypt32, hDpapi, hDbghelp, hDbgcore: HMODULE;
134 | begin
135 | CollectForwards(FForwards, GetModuleHandle(kernel32), 0);
136 | if FHUsr <> 0 then
137 | CollectForwards(FForwardsType2, GetModuleHandle(user32), FHUsr);
138 | CollectForwards(FForwardsOle32, GetModuleHandle('ole32.dll'), 0);
139 |
140 | hNetapi := LoadLibrary('netapi32.dll');
141 | hSrvcli := LoadLibrary('srvcli.dll'); // Required for CollectForwards
142 | CollectForwards(FForwardsNetapi32, hNetapi, 0);
143 | FreeLibrary(hSrvcli);
144 | FreeLibrary(hNetapi);
145 |
146 | if Win32MajorVersion >= 6 then
147 | begin
148 | hCrypt32 := LoadLibrary('crypt32.dll');
149 | hDpapi := LoadLibrary('dpapi.dll'); // Required for CollectForwards
150 | CollectForwards(FForwardsCrypt32, hCrypt32, 0);
151 | FreeLibrary(hCrypt32);
152 | FreeLibrary(hDpapi);
153 | end;
154 |
155 | hDbghelp := LoadLibrary('dbghelp.dll');
156 | hDbgcore := LoadLibrary('dbgcore.dll'); // Required for CollectForwards
157 | CollectForwards(FForwardsDbghelp, hDbghelp, 0);
158 | FreeLibrary(hDbghelp);
159 | FreeLibrary(hDbgcore);
160 |
161 | if GetModuleHandle('kernelbase.dll') <> 0 then
162 | CollectForwards(FForwardsKernelbase, GetModuleHandle('kernelbase.dll'), 0);
163 | end;
164 |
165 | procedure TDumper.CollectForwards(Fwds: TForwardDict; hModReal, hModScan: HMODULE);
166 | var
167 | ModScan: PByte;
168 | ExpDir: PImageExportDirectory;
169 | i, DotPos: Integer;
170 | a: PCardinal;
171 | Fwd: PAnsiChar;
172 | hMod: HMODULE;
173 | ProcAddr: Pointer;
174 | begin
175 | if hModScan = 0 then
176 | hModScan := hModReal;
177 | ModScan := Pointer(hModScan);
178 | ExpDir := Pointer(ModScan + PImageNTHeaders(ModScan + PImageDosHeader(ModScan)._lfanew).OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
179 |
180 | a := PCardinal(ModScan + ExpDir.AddressOfFunctions);
181 | for i := 0 to ExpDir.NumberOfFunctions - 1 do
182 | begin
183 | Fwd := PAnsiChar(ModScan + a^); // e.g. NTDLL.RtlAllocateHeap
184 | DotPos := Pos(AnsiString('.'), Fwd);
185 | if (Length(Fwd) in [10..90]) and (((DotPos > 0) and (DotPos < 15)) or (Pos(AnsiString('api-ms-win'), Fwd) > 0)) and (Pos(AnsiString('.#'), Fwd) = 0) then
186 | begin
187 | hMod := GetModuleHandleA(PAnsiChar(Copy(Fwd, 1, DotPos - 1)));
188 | if hMod > 0 then
189 | begin
190 | // Not using the normal GetProcAddress because it can return apphelp hooks (e.g., CoCreateInstance when running as admin)
191 | ProcAddr := GetLocalProcAddr(hMod, PAnsiChar(Copy(Fwd, DotPos + 1, 50)));
192 | if ProcAddr <> nil then
193 | Fwds.AddOrSetValue(ProcAddr, PByte(hModReal) + a^);
194 | //Log(ltInfo, Format('%s @ %p', [PAnsiChar(Copy(Fwd, DotPos + 1, 50)), ProcAddr]));
195 | end
196 | //else
197 | // Log(ltFatal, Format('Forward target not loaded: %s', [string(AnsiString(PAnsiChar(Copy(Fwd, 1, DotPos - 1))))]));
198 | end;
199 | Inc(a);
200 | end;
201 | end;
202 |
203 | procedure TDumper.DumpToFile(const FileName: string; PE: TPEHeader);
204 | var
205 | FS: TFileStream;
206 | Buf: PByte;
207 | i: Integer;
208 | Size, Delta, IATRawOffset: Cardinal;
209 | begin
210 | FS := TFileStream.Create(FileName, fmCreate);
211 | try
212 | Size := PE.DumpSize;
213 | GetMem(Buf, Size);
214 | if not RPM(FImageBase, Buf, Size) then
215 | raise Exception.Create('DumpToFile RPM failed');
216 |
217 | IATRawOffset := FIAT - FImageBase;
218 | // TrimHugeSections may adjust IATRawOffset depending on what is trimmed.
219 | Delta := PE.TrimHugeSections(Buf, IATRawOffset);
220 | Dec(Size, Delta);
221 | FS.Write(Buf^, Size);
222 | FreeMem(Buf);
223 |
224 | for i := PE.NTHeaders.FileHeader.NumberOfSections to High(PE.Sections) do
225 | begin
226 | FS.Write(PE.Sections[i].Data^, PE.Sections[i].Header.SizeOfRawData);
227 | end;
228 | PE.NTHeaders.FileHeader.NumberOfSections := Length(PE.Sections);
229 | PE.NTHeaders.OptionalHeader.AddressOfEntryPoint := FOEP - FImageBase;
230 |
231 | if (PE.NTHeaders.OptionalHeader.DllCharacteristics and $40) <> 0 then
232 | begin
233 | Log(ltInfo, 'Executable is ASLR-aware - disabling the flag in the dump');
234 | PE.NTHeaders.OptionalHeader.DllCharacteristics := PE.NTHeaders.OptionalHeader.DllCharacteristics and not $40;
235 | end;
236 |
237 | PE.SaveToStream(FS);
238 |
239 | FS.Seek(IATRawOffset, soBeginning);
240 | FS.Write(FIATImage^, FIATImageSize);
241 | finally
242 | FS.Free;
243 | end;
244 | end;
245 |
246 | {$POINTERMATH ON}
247 |
248 | function TDumper.Process: TPEHeader;
249 | var
250 | IAT: PByte;
251 | i, j: Integer;
252 | IATSize, Diff: Cardinal;
253 | LastValidOffset: NativeUInt;
254 | PE: TPEHeader;
255 | a: ^PByte;
256 | Fwd: Pointer;
257 | Thunks: TList;
258 | Thunk: TImportThunk;
259 | NeedNewThunk, Found: Boolean;
260 | RM: PRemoteModule;
261 | s: AnsiString;
262 | Section, Strs, RangeChecker: PByte;
263 | Descriptors: PImageImportDescriptor;
264 | ImportSect: PPESection;
265 | begin
266 | if FIAT = 0 then
267 | raise Exception.Create('Must set IAT before calling Process()');
268 |
269 | // Read header from memory
270 | GetMem(Section, $1000);
271 | RPM(FImageBase, Section, $1000);
272 | PE := TPEHeader.Create(Section);
273 | PE.Sanitize;
274 | FreeMem(Section);
275 |
276 | GetMem(IAT, MAX_IAT_SIZE);
277 | RPM(FIAT, IAT, MAX_IAT_SIZE);
278 |
279 | LastValidOffset := 0;
280 | i := 0;
281 | while (i < MAX_IAT_SIZE) and ((LastValidOffset = 0) or (NativeUInt(i) < LastValidOffset + $100)) do
282 | begin
283 | if IsAPIAddress(PNativeUInt(IAT + i)^) then
284 | LastValidOffset := NativeUInt(i);
285 |
286 | Inc(i, SizeOf(Pointer));
287 | end;
288 |
289 | IATSize := LastValidOffset + SizeOf(Pointer);
290 | Log(ltInfo, Format('Determined IAT size: %X', [IATSize]));
291 |
292 | with PE.NTHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] do
293 | begin
294 | VirtualAddress := FIAT - FImageBase;
295 | Size := IATSize + SizeOf(Pointer);
296 | end;
297 |
298 | if FAllModules = nil then
299 | TakeModuleSnapshot;
300 |
301 | Thunks := TObjectList.Create;
302 | a := Pointer(IAT);
303 | NeedNewThunk := False; // whether there's an address "gap" (example: k32-api, 0, k32-api)
304 | for i := 0 to IATSize div SizeOf(Pointer) - 1 do
305 | begin
306 | //Log(ltInfo, IntToHex(UIntPtr(a) - UIntPtr(IAT) + FIAT, 8) + ' -> ' + IntToHex(UIntPtr(a^), 8));
307 | // Type 2: a^ is correct for export lookup, but need to look in different module! (ntdll --> user32)
308 | if FForwardsType2.TryGetValue(a^, Fwd) then
309 | begin
310 | RangeChecker := Fwd;
311 | end
312 | else
313 | begin
314 | // Some kernel32 functions are forwarded to ntdll - restore the original address
315 | if FForwards.TryGetValue(a^, Fwd) then
316 | a^ := Fwd
317 | else if FForwardsOle32.TryGetValue(a^, Fwd) then
318 | a^ := Fwd
319 | else if FForwardsNetapi32.TryGetValue(a^, Fwd) then
320 | a^ := Fwd
321 | else if FForwardsCrypt32.TryGetValue(a^, Fwd) then
322 | a^ := Fwd
323 | else if FForwardsDbghelp.TryGetValue(a^, Fwd) then
324 | a^ := Fwd
325 | else if FForwardsKernelbase.TryGetValue(a^, Fwd) then
326 | a^ := Fwd;
327 | RangeChecker := a^;
328 | end;
329 | //Log(ltInfo, ' -> ' + IntToHex(UIntPtr(a^), 8));
330 |
331 | Found := False;
332 | for RM in FAllModules do
333 | if (RangeChecker > RM.Base) and (RangeChecker < RM.EndOff) then
334 | begin
335 | if RM.ExportTbl = nil then
336 | GatherModuleExportsFromRemoteProcess(RM);
337 |
338 | if RM.ExportTbl.ContainsKey(a^) then
339 | begin
340 | if (Thunks.Count = 0) or (Thunks.Last.Name <> RM.Name) or NeedNewThunk then
341 | begin
342 | Thunks.Add(TImportThunk.Create(RM));
343 | NeedNewThunk := False; // reset
344 | end;
345 |
346 | Found := True;
347 | //Log(ltInfo, 'IAT ' + IntToHex(UIntPtr(a) - UIntPtr(IAT) + FIAT, 8) + ' -> API ' + IntToHex(UIntPtr(a^), 8) + ' belongs to ' + RM.Name);
348 | Thunks.Last.Addresses.Add(PPointer(a))
349 | end
350 | else
351 | Log(ltFatal, 'IAT ' + IntToHex(UIntPtr(a) - UIntPtr(IAT) + FIAT, 8) + ' -> API ' + IntToHex(UIntPtr(a^), 8) + ' not in export table of ' + RM.Name + ' (likely a bogus entry)');
352 |
353 | Break;
354 | end;
355 |
356 | if not Found then
357 | NeedNewThunk := True;
358 |
359 | Inc(a);
360 | end;
361 |
362 | ImportSect := PE.CreateSection('.import', $1000);
363 |
364 | Section := AllocMem(ImportSect.Header.SizeOfRawData);
365 | Pointer(Descriptors) := Section; // Map the Descriptors array to the start of the section
366 | Strs := Section + (Thunks.Count + 1) * SizeOf(TImageImportDescriptor); // Last descriptor is empty
367 |
368 | i := 0;
369 | for Thunk in Thunks do
370 | begin
371 | Descriptors[i].FirstThunk := (FIAT - FImageBase) + UIntPtr(Thunk.Addresses.First) - UIntPtr(IAT);
372 | Descriptors[i].Name := PE.ConvertOffsetToRVAVector(ImportSect.Header.PointerToRawData + Cardinal(Strs - Section));
373 | Inc(i);
374 | s := AnsiString(Thunk.Name);
375 | Move(s[1], Strs^, Length(s));
376 | Inc(Strs, Length(s) + 1);
377 | RM := Thunk.Module;
378 | Log(ltInfo, 'Thunk ' + Thunk.Name + ' - first import: ' + RM.ExportTbl[Thunk.Addresses.First^]);
379 | for j := 0 to Thunk.Addresses.Count - 1 do
380 | begin
381 | Inc(Strs, 2); // Hint
382 | s := AnsiString(RM.ExportTbl[Thunk.Addresses[j]^]);
383 | // Set the address in the IAT to this string entry
384 | Thunk.Addresses[j]^ := Pointer(PE.ConvertOffsetToRVAVector(ImportSect.Header.PointerToRawData + Cardinal(Strs - 2 - Section)));
385 | Move(s[1], Strs^, Length(s));
386 | Inc(Strs, Length(s) + 1);
387 |
388 | if Strs > Section + ImportSect.Header.SizeOfRawData - $100 then
389 | begin
390 | Inc(ImportSect.Header.SizeOfRawData, $1000);
391 | Inc(ImportSect.Header.Misc.VirtualSize, $1000);
392 | Inc(PE.NTHeaders.OptionalHeader.SizeOfImage, $1000);
393 | Diff := Strs - Section;
394 | ReallocMem(Section, ImportSect.Header.SizeOfRawData);
395 | FillChar((Section + ImportSect.Header.SizeOfRawData - $1000)^, $1000, 0);
396 | Strs := Section + Diff;
397 | Pointer(Descriptors) := Section;
398 | //Log(ltInfo, 'Increased import section size to ' + IntToHex(ImportSect.Header.SizeOfRawData, 4));
399 | end;
400 | end;
401 | end;
402 |
403 | ImportSect.Data := Section;
404 | with PE.NTHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] do
405 | begin
406 | VirtualAddress := ImportSect.Header.VirtualAddress;
407 | Size := Thunks.Count * SizeOf(TImageImportDescriptor);
408 | end;
409 |
410 | Thunks.Free;
411 |
412 | FIATImage := IAT;
413 | FIATImageSize := IATSize;
414 |
415 | Result := PE;
416 | end;
417 |
418 | procedure TDumper.GatherModuleExportsFromRemoteProcess(M: PRemoteModule);
419 | var
420 | Head: PByte;
421 | Exp: PImageExportDirectory;
422 | Off: PByte;
423 | a, n: PCardinal;
424 | o: PWord;
425 | i: Integer;
426 | begin
427 | M.ExportTbl := TExportTable.Create;
428 | GetMem(Head, $1000);
429 | RPM(NativeUInt(M.Base), Head, $1000);
430 | with PImageNtHeaders(Head + PImageDosHeader(Head)._lfanew).OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] do
431 | begin
432 | GetMem(Exp, Size);
433 | RPM(NativeUInt(M.Base + VirtualAddress), Exp, Size);
434 | Off := PByte(Exp) - VirtualAddress;
435 | end;
436 | FreeMem(Head);
437 |
438 | Pointer(a) := Off + Exp.AddressOfFunctions;
439 | Pointer(n) := Off + Exp.AddressOfNames;
440 | Pointer(o) := Off + Exp.AddressOfNameOrdinals;
441 | for i := 0 to Exp.NumberOfNames - 1 do
442 | begin
443 | M.ExportTbl.AddOrSetValue(M.Base + a[o[i]], string(AnsiString(PAnsiChar(Off + n[i]))));
444 | end;
445 |
446 | FreeMem(Exp);
447 | end;
448 |
449 | function TDumper.GetLocalProcAddr(hModule: HMODULE; ProcName: PAnsiChar): Pointer;
450 | var
451 | Exp: PImageExportDirectory;
452 | Off: PByte;
453 | a, n: PCardinal;
454 | o: PWord;
455 | i: Integer;
456 | begin
457 | with PImageNtHeaders(hModule + Cardinal(PImageDosHeader(hModule)._lfanew)).OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] do
458 | begin
459 | Exp := Pointer(hModule + VirtualAddress);
460 | Off := PByte(Exp) - VirtualAddress;
461 | end;
462 |
463 | Pointer(a) := Off + Exp.AddressOfFunctions;
464 | Pointer(n) := Off + Exp.AddressOfNames;
465 | Pointer(o) := Off + Exp.AddressOfNameOrdinals;
466 | for i := 0 to Exp.NumberOfNames - 1 do
467 | if AnsiStrComp(PAnsiChar(Off + n[i]), ProcName) = 0 then
468 | Exit(Pointer(hModule + a[o[i]]));
469 |
470 | Result := nil;
471 | end;
472 |
473 | function TDumper.IsAPIAddress(Address: NativeUInt): Boolean;
474 | var
475 | RM: PRemoteModule;
476 | begin
477 | if FAllModules = nil then
478 | TakeModuleSnapshot;
479 |
480 | for RM in FAllModules do
481 | if (Address >= NativeUInt(RM.Base)) and (Address < NativeUInt(RM.EndOff)) then
482 | begin
483 | if RM.ExportTbl = nil then
484 | GatherModuleExportsFromRemoteProcess(RM);
485 |
486 | Exit(RM.ExportTbl.ContainsKey(Pointer(Address)));
487 | end;
488 |
489 | Result := False;
490 | end;
491 |
492 | procedure TDumper.TakeModuleSnapshot;
493 | var
494 | hSnap: THandle;
495 | ME: TModuleEntry32;
496 | RM: PRemoteModule;
497 | begin
498 | FAllModules := TList.Create;
499 | hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, FProcess.dwProcessId);
500 | ME.dwSize := SizeOf(TModuleEntry32);
501 | if not Module32First(hSnap, ME) then
502 | raise Exception.Create('Module32First');
503 | repeat
504 | if ME.hModule <> FImageBase then
505 | begin
506 | //Log(ltInfo, IntToHex(ME.hModule, 8) + ' : ' + IntToHex(ME.modBaseSize, 4) + ' : ' + string(ME.szModule));
507 | New(RM);
508 | RM.Base := ME.modBaseAddr;
509 | RM.EndOff := ME.modBaseAddr + ME.modBaseSize;
510 | RM.Name := LowerCase(ME.szModule);
511 | RM.ExportTbl := nil;
512 | FAllModules.Add(RM);
513 | end;
514 | until not Module32Next(hSnap, ME);
515 | CloseHandle(hSnap);
516 | end;
517 |
518 | function TDumper.RPM(Address: NativeUInt; Buf: Pointer; BufSize: NativeUInt): Boolean;
519 | begin
520 | Result := ReadProcessMemory(FProcess.hProcess, Pointer(Address), Buf, BufSize, BufSize);
521 | if not Result then
522 | Log(ltFatal, 'RPM failed');
523 | end;
524 |
525 | { TImportThunk }
526 |
527 | constructor TImportThunk.Create(RM: PRemoteModule);
528 | begin
529 | Module := RM;
530 | Name := RM.Name;
531 | Addresses := TList.Create;
532 | end;
533 |
534 | destructor TImportThunk.Destroy;
535 | begin
536 | Addresses.Free;
537 |
538 | inherited;
539 | end;
540 |
541 | end.
542 |
--------------------------------------------------------------------------------
/Magicmida.dpr:
--------------------------------------------------------------------------------
1 | program Magicmida;
2 |
3 | {$WEAKLINKRTTI ON}
4 | {$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
5 |
6 | uses
7 | Windows,
8 | TypInfo,
9 | Vcl.Forms,
10 | Unit2 in 'Unit2.pas' {ThemidaUnpackerWnd},
11 | Debugger in 'Debugger.pas',
12 | Utils in 'Utils.pas',
13 | Dumper in 'Dumper.pas',
14 | PEInfo in 'PEInfo.pas',
15 | Patcher in 'Patcher.pas',
16 | BeaEngineDelphi32 in 'BeaEngineDelphi32.pas',
17 | Tracer in 'Tracer.pas',
18 | AntiDumpFix in 'AntiDumpFix.pas';
19 |
20 | {$R *.res}
21 |
22 | procedure ConsoleLog(MsgType: TLogMsgType; const Msg: string);
23 | begin
24 | Writeln('[', Copy(TypInfo.GetEnumName(TypeInfo(TLogMsgType), Ord(MsgType)), 3, 10), '] ', Msg);
25 | end;
26 |
27 | procedure CheckCommandlineInvocation;
28 | begin
29 | if (ParamCount >= 1) and (ParamStr(1) = '/unpack') then
30 | begin
31 | if not AttachConsole(ATTACH_PARENT_PROCESS) then
32 | begin
33 | AssignFile(Output, 'NUL');
34 | Rewrite(Output);
35 | end;
36 | Log := ConsoleLog;
37 |
38 | if ParamCount < 2 then
39 | begin
40 | Writeln('Usage: ', ParamStr(0), ' /unpack ');
41 | Halt(1);
42 | end;
43 |
44 | try
45 | with TDebugger.Create(ParamStr(2), '', True) do
46 | try
47 | WaitFor;
48 | finally
49 | Free;
50 | end;
51 | finally
52 | Halt(0);
53 | end;
54 | end;
55 | end;
56 |
57 |
58 | begin
59 | CheckCommandlineInvocation;
60 |
61 | Application.Initialize;
62 | Application.MainFormOnTaskbar := True;
63 | Application.CreateForm(TThemidaUnpackerWnd, ThemidaUnpackerWnd);
64 | Application.Run;
65 | end.
66 |
--------------------------------------------------------------------------------
/Magicmida.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {DC21AACF-9E5A-4855-BBED-DE0E0455912D}
4 | 19.5
5 | VCL
6 | Magicmida.dpr
7 | True
8 | Release
9 | Win32
10 | 1
11 | Application
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Base
40 | true
41 |
42 |
43 | true
44 | Cfg_2
45 | true
46 | true
47 |
48 |
49 | 1031
50 | None
51 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
52 | bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapCommon;DataSnapClient;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;soaprtl;bindengine;DBXOracleDriver;CustomIPTransport;dsnap;DBXInformixDriver;IndyCore;fmxase;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IPIndyImpl;$(DCC_UsePackage)
53 | $(BDS)\bin\delphi_PROJECTICON.ico
54 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
55 | .\$(Platform)\$(Config)
56 | false
57 | false
58 | false
59 | false
60 | false
61 | Magicmida
62 |
63 |
64 | tree_2.ico
65 | vcldbx;TeeDB;VirtualTreesD;inetdbbde;Tee;DBXOdbcDriver;PBClpBrd;svnui;DBXSybaseASEDriver;SynEdit_RXE2;vclimg;fmi;vclactnband;FMXTee;vcldb;TeeUI;bindcompvcl;vcldsnap;vclie;vcltouch;DBXDb2Driver;websnap;vclribbon;VclSmp;vcl;DataSnapConnectors;Label3DBorder;CloudService;DBXMSSQLDriver;CodeSiteExpressPkg;FmxTeeUI;dsnapcon;vclx;webdsnap;svn;Shockwave;bdertl;VirtualTreesR;adortl;$(DCC_UsePackage)
66 | true
67 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
68 | 1033
69 | $(BDS)\bin\default_app.manifest
70 | true
71 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
72 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
73 |
74 |
75 | DBXOdbcDriver;DBXSybaseASEDriver;SynEdit_RXE2;vclimg;vclactnband;vcldb;bindcompvcl;vcldsnap;vclie;vcltouch;DBXDb2Driver;websnap;VclSmp;vcl;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;VirtualTreesR;$(DCC_UsePackage)
76 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
77 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
78 |
79 |
80 | DEBUG;$(DCC_Define)
81 | false
82 | true
83 | true
84 | true
85 |
86 |
87 | true
88 | tree_2.ico
89 | $(BDS)\bin\default_app.manifest
90 | true
91 | 1033
92 | false
93 | true
94 | Debug
95 |
96 |
97 | false
98 | RELEASE;$(DCC_Define)
99 | 0
100 | 0
101 |
102 |
103 | true
104 | tree_2.ico
105 | 1033
106 | Magicmida.exe.manifest
107 | Debug
108 | 5.1
109 | 5.1
110 | none
111 |
112 |
113 |
114 | MainSource
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | Base
129 |
130 |
131 | Cfg_1
132 | Base
133 |
134 |
135 | Cfg_2
136 | Base
137 |
138 |
139 |
140 | Delphi.Personality.12
141 |
142 |
143 |
144 |
145 | False
146 | False
147 | 1
148 | 0
149 | 0
150 | 0
151 | False
152 | False
153 | False
154 | False
155 | False
156 | 1031
157 | 1252
158 |
159 |
160 |
161 |
162 | 1.0.0.0
163 |
164 |
165 |
166 |
167 |
168 | 1.0.0.0
169 |
170 |
171 |
172 | Magicmida.dpr
173 |
174 |
175 | Microsoft Office 2000 Sample Automation Server Wrapper Components
176 | Microsoft Office XP Sample Automation Server Wrapper Components
177 |
178 |
179 |
180 |
181 |
182 |
183 | 1
184 |
185 |
186 | Contents\MacOS
187 | 1
188 |
189 |
190 | 0
191 |
192 |
193 |
194 |
195 | classes
196 | 64
197 |
198 |
199 | classes
200 | 64
201 |
202 |
203 |
204 |
205 | res\xml
206 | 1
207 |
208 |
209 | res\xml
210 | 1
211 |
212 |
213 |
214 |
215 | library\lib\armeabi-v7a
216 | 1
217 |
218 |
219 |
220 |
221 | library\lib\armeabi
222 | 1
223 |
224 |
225 | library\lib\armeabi
226 | 1
227 |
228 |
229 |
230 |
231 | library\lib\armeabi-v7a
232 | 1
233 |
234 |
235 |
236 |
237 | library\lib\mips
238 | 1
239 |
240 |
241 | library\lib\mips
242 | 1
243 |
244 |
245 |
246 |
247 | library\lib\armeabi-v7a
248 | 1
249 |
250 |
251 | library\lib\arm64-v8a
252 | 1
253 |
254 |
255 |
256 |
257 | library\lib\armeabi-v7a
258 | 1
259 |
260 |
261 |
262 |
263 | res\drawable
264 | 1
265 |
266 |
267 | res\drawable
268 | 1
269 |
270 |
271 |
272 |
273 | res\values
274 | 1
275 |
276 |
277 | res\values
278 | 1
279 |
280 |
281 |
282 |
283 | res\values-v21
284 | 1
285 |
286 |
287 | res\values-v21
288 | 1
289 |
290 |
291 |
292 |
293 | res\values
294 | 1
295 |
296 |
297 | res\values
298 | 1
299 |
300 |
301 |
302 |
303 | res\drawable
304 | 1
305 |
306 |
307 | res\drawable
308 | 1
309 |
310 |
311 |
312 |
313 | res\drawable-xxhdpi
314 | 1
315 |
316 |
317 | res\drawable-xxhdpi
318 | 1
319 |
320 |
321 |
322 |
323 | res\drawable-xxxhdpi
324 | 1
325 |
326 |
327 | res\drawable-xxxhdpi
328 | 1
329 |
330 |
331 |
332 |
333 | res\drawable-ldpi
334 | 1
335 |
336 |
337 | res\drawable-ldpi
338 | 1
339 |
340 |
341 |
342 |
343 | res\drawable-mdpi
344 | 1
345 |
346 |
347 | res\drawable-mdpi
348 | 1
349 |
350 |
351 |
352 |
353 | res\drawable-hdpi
354 | 1
355 |
356 |
357 | res\drawable-hdpi
358 | 1
359 |
360 |
361 |
362 |
363 | res\drawable-xhdpi
364 | 1
365 |
366 |
367 | res\drawable-xhdpi
368 | 1
369 |
370 |
371 |
372 |
373 | res\drawable-mdpi
374 | 1
375 |
376 |
377 | res\drawable-mdpi
378 | 1
379 |
380 |
381 |
382 |
383 | res\drawable-hdpi
384 | 1
385 |
386 |
387 | res\drawable-hdpi
388 | 1
389 |
390 |
391 |
392 |
393 | res\drawable-xhdpi
394 | 1
395 |
396 |
397 | res\drawable-xhdpi
398 | 1
399 |
400 |
401 |
402 |
403 | res\drawable-xxhdpi
404 | 1
405 |
406 |
407 | res\drawable-xxhdpi
408 | 1
409 |
410 |
411 |
412 |
413 | res\drawable-xxxhdpi
414 | 1
415 |
416 |
417 | res\drawable-xxxhdpi
418 | 1
419 |
420 |
421 |
422 |
423 | res\drawable-small
424 | 1
425 |
426 |
427 | res\drawable-small
428 | 1
429 |
430 |
431 |
432 |
433 | res\drawable-normal
434 | 1
435 |
436 |
437 | res\drawable-normal
438 | 1
439 |
440 |
441 |
442 |
443 | res\drawable-large
444 | 1
445 |
446 |
447 | res\drawable-large
448 | 1
449 |
450 |
451 |
452 |
453 | res\drawable-xlarge
454 | 1
455 |
456 |
457 | res\drawable-xlarge
458 | 1
459 |
460 |
461 |
462 |
463 | res\values
464 | 1
465 |
466 |
467 | res\values
468 | 1
469 |
470 |
471 |
472 |
473 | 1
474 |
475 |
476 | Contents\MacOS
477 | 1
478 |
479 |
480 | 0
481 |
482 |
483 |
484 |
485 | Contents\MacOS
486 | 1
487 | .framework
488 |
489 |
490 | Contents\MacOS
491 | 1
492 | .framework
493 |
494 |
495 | Contents\MacOS
496 | 1
497 | .framework
498 |
499 |
500 | 0
501 |
502 |
503 |
504 |
505 | 1
506 | .dylib
507 |
508 |
509 | 1
510 | .dylib
511 |
512 |
513 | 1
514 | .dylib
515 |
516 |
517 | Contents\MacOS
518 | 1
519 | .dylib
520 |
521 |
522 | Contents\MacOS
523 | 1
524 | .dylib
525 |
526 |
527 | Contents\MacOS
528 | 1
529 | .dylib
530 |
531 |
532 | 0
533 | .dll;.bpl
534 |
535 |
536 |
537 |
538 | 1
539 | .dylib
540 |
541 |
542 | 1
543 | .dylib
544 |
545 |
546 | 1
547 | .dylib
548 |
549 |
550 | Contents\MacOS
551 | 1
552 | .dylib
553 |
554 |
555 | Contents\MacOS
556 | 1
557 | .dylib
558 |
559 |
560 | Contents\MacOS
561 | 1
562 | .dylib
563 |
564 |
565 | 0
566 | .bpl
567 |
568 |
569 |
570 |
571 | 0
572 |
573 |
574 | 0
575 |
576 |
577 | 0
578 |
579 |
580 | 0
581 |
582 |
583 | 0
584 |
585 |
586 | Contents\Resources\StartUp\
587 | 0
588 |
589 |
590 | Contents\Resources\StartUp\
591 | 0
592 |
593 |
594 | Contents\Resources\StartUp\
595 | 0
596 |
597 |
598 | 0
599 |
600 |
601 |
602 |
603 | 1
604 |
605 |
606 | 1
607 |
608 |
609 |
610 |
611 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
612 | 1
613 |
614 |
615 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
616 | 1
617 |
618 |
619 |
620 |
621 | ..\
622 | 1
623 |
624 |
625 | ..\
626 | 1
627 |
628 |
629 | ..\
630 | 1
631 |
632 |
633 |
634 |
635 | Contents
636 | 1
637 |
638 |
639 | Contents
640 | 1
641 |
642 |
643 | Contents
644 | 1
645 |
646 |
647 |
648 |
649 | Contents\Resources
650 | 1
651 |
652 |
653 | Contents\Resources
654 | 1
655 |
656 |
657 | Contents\Resources
658 | 1
659 |
660 |
661 |
662 |
663 | library\lib\armeabi-v7a
664 | 1
665 |
666 |
667 | library\lib\arm64-v8a
668 | 1
669 |
670 |
671 | 1
672 |
673 |
674 | 1
675 |
676 |
677 | 1
678 |
679 |
680 | 1
681 |
682 |
683 | Contents\MacOS
684 | 1
685 |
686 |
687 | Contents\MacOS
688 | 1
689 |
690 |
691 | Contents\MacOS
692 | 1
693 |
694 |
695 | 0
696 |
697 |
698 |
699 |
700 | library\lib\armeabi-v7a
701 | 1
702 |
703 |
704 |
705 |
706 | 1
707 |
708 |
709 | 1
710 |
711 |
712 |
713 |
714 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
715 | 1
716 |
717 |
718 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
719 | 1
720 |
721 |
722 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
723 | 1
724 |
725 |
726 |
727 |
728 | ..\
729 | 1
730 |
731 |
732 | ..\
733 | 1
734 |
735 |
736 | ..\
737 | 1
738 |
739 |
740 |
741 |
742 | 1
743 |
744 |
745 | 1
746 |
747 |
748 | 1
749 |
750 |
751 |
752 |
753 | ..\$(PROJECTNAME).launchscreen
754 | 64
755 |
756 |
757 | ..\$(PROJECTNAME).launchscreen
758 | 64
759 |
760 |
761 |
762 |
763 | 1
764 |
765 |
766 | 1
767 |
768 |
769 | 1
770 |
771 |
772 |
773 |
774 | Assets
775 | 1
776 |
777 |
778 | Assets
779 | 1
780 |
781 |
782 |
783 |
784 | Assets
785 | 1
786 |
787 |
788 | Assets
789 | 1
790 |
791 |
792 |
793 |
794 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
795 | 1
796 |
797 |
798 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
799 | 1
800 |
801 |
802 |
803 |
804 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
805 | 1
806 |
807 |
808 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
809 | 1
810 |
811 |
812 |
813 |
814 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
815 | 1
816 |
817 |
818 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
819 | 1
820 |
821 |
822 |
823 |
824 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
825 | 1
826 |
827 |
828 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
829 | 1
830 |
831 |
832 |
833 |
834 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
835 | 1
836 |
837 |
838 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
839 | 1
840 |
841 |
842 |
843 |
844 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
845 | 1
846 |
847 |
848 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
849 | 1
850 |
851 |
852 |
853 |
854 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
855 | 1
856 |
857 |
858 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
859 | 1
860 |
861 |
862 |
863 |
864 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
865 | 1
866 |
867 |
868 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
869 | 1
870 |
871 |
872 |
873 |
874 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
875 | 1
876 |
877 |
878 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
879 | 1
880 |
881 |
882 |
883 |
884 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
885 | 1
886 |
887 |
888 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
889 | 1
890 |
891 |
892 |
893 |
894 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
895 | 1
896 |
897 |
898 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
899 | 1
900 |
901 |
902 |
903 |
904 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
905 | 1
906 |
907 |
908 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
909 | 1
910 |
911 |
912 |
913 |
914 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
915 | 1
916 |
917 |
918 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
919 | 1
920 |
921 |
922 |
923 |
924 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
925 | 1
926 |
927 |
928 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
929 | 1
930 |
931 |
932 |
933 |
934 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
935 | 1
936 |
937 |
938 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
939 | 1
940 |
941 |
942 |
943 |
944 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
945 | 1
946 |
947 |
948 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
949 | 1
950 |
951 |
952 |
953 |
954 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
955 | 1
956 |
957 |
958 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
959 | 1
960 |
961 |
962 |
963 |
964 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
965 | 1
966 |
967 |
968 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
969 | 1
970 |
971 |
972 |
973 |
974 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
975 | 1
976 |
977 |
978 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
979 | 1
980 |
981 |
982 |
983 |
984 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
985 | 1
986 |
987 |
988 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
989 | 1
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
1006 | True
1007 | False
1008 |
1009 |
1010 | 12
1011 |
1012 |
1013 |
1014 |
1015 |
1016 |
--------------------------------------------------------------------------------
/Magicmida.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Magicmida.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hendi48/Magicmida/58b895a1918d718d4c1d9383595dfbda8620dbf3/Magicmida.res
--------------------------------------------------------------------------------
/PEInfo.pas:
--------------------------------------------------------------------------------
1 | unit PEInfo;
2 |
3 | interface
4 |
5 | uses Windows, Classes, SysUtils;
6 |
7 | type
8 | TPESection = record
9 | Header: TImageSectionHeader;
10 | Data: PByte;
11 | end;
12 | PPESection = ^TPESection;
13 |
14 | TPESections = TArray;
15 |
16 | TPEHeader = class
17 | private
18 | FSections: TPESections;
19 | FDumpSize: Cardinal;
20 | FLFANew: Cardinal;
21 |
22 | procedure FileAlign(var V: Cardinal);
23 | procedure SectionAlign(var V: Cardinal);
24 | public
25 | NTHeaders: TImageNTHeaders;
26 |
27 | constructor Create(Data: PByte);
28 |
29 | function CreateSection(const Name: AnsiString; Size: Cardinal): PPESection;
30 | procedure DeleteSection(Idx: Integer);
31 | function GetSectionByVA(V: Cardinal): PPESection;
32 | procedure AddSectionToArray;
33 |
34 | function ConvertOffsetToRVAVector(Offset: NativeUInt): NativeUInt;
35 |
36 | function TrimHugeSections(Buf: PByte; var IATRawAddr: Cardinal): Cardinal;
37 | procedure Sanitize;
38 |
39 | procedure SaveToStream(S: TStream);
40 |
41 | property Sections: TPESections read FSections;
42 |
43 | property LFANew: Cardinal read FLFANew;
44 | property DumpSize: Cardinal read FDumpSize;
45 | property SizeOfImage: Cardinal read NTHeaders.OptionalHeader.SizeOfImage;
46 | end;
47 |
48 | implementation
49 |
50 | uses Utils;
51 |
52 | { TPEHeader }
53 |
54 | constructor TPEHeader.Create(Data: PByte);
55 | var
56 | NT: PImageNTHeaders;
57 | Sect: PImageSectionHeader;
58 | i: Integer;
59 | begin
60 | FLFANew := PImageDosHeader(Data)._lfanew;
61 | NT := PImageNTHeaders(Data + FLFANew);
62 | NTHeaders := NT^;
63 | FDumpSize := SizeOfImage;
64 |
65 | Sect := PImageSectionHeader(PByte(NT) + SizeOf(TImageNTHeaders));
66 | SetLength(FSections, NT.FileHeader.NumberOfSections);
67 | for i := 0 to High(FSections) do
68 | begin
69 | FSections[i].Header := Sect^;
70 | Inc(Sect);
71 | end;
72 | end;
73 |
74 | function TPEHeader.CreateSection(const Name: AnsiString; Size: Cardinal): PPESection;
75 | var
76 | Prev: PImageSectionHeader;
77 | begin
78 | Prev := @FSections[High(FSections)].Header;
79 | SetLength(FSections, Length(FSections) + 1);
80 | Result := @FSections[High(FSections)];
81 | FillChar(Result^, SizeOf(Result^), 0);
82 | Move(Name[1], Result.Header.Name[0], Length(Name));
83 | with Result.Header do
84 | begin
85 | Misc.VirtualSize := Size;
86 | VirtualAddress := Prev.VirtualAddress + Prev.Misc.VirtualSize;
87 | SectionAlign(VirtualAddress);
88 | PointerToRawData := NTHeaders.OptionalHeader.SizeOfImage;
89 | SizeOfRawData := Size;
90 | Characteristics := IMAGE_SCN_MEM_READ or IMAGE_SCN_CNT_INITIALIZED_DATA;
91 | end;
92 | Inc(NTHeaders.OptionalHeader.SizeOfImage, Size);
93 | // NumberOfSections is handled by the dumper
94 | end;
95 |
96 | procedure TPEHeader.DeleteSection(Idx: Integer);
97 | var
98 | i: Integer;
99 | Sz: Cardinal;
100 | IsLast: Boolean;
101 | begin
102 | IsLast := Idx = High(FSections);
103 |
104 | if IsLast then
105 | Sz := NTHeaders.OptionalHeader.SizeOfImage - FSections[Idx].Header.SizeOfRawData
106 | else
107 | Sz := FSections[Idx + 1].Header.PointerToRawData - FSections[Idx].Header.PointerToRawData;
108 |
109 | for i := High(FSections) downto Idx + 1 do
110 | begin
111 | Dec(FSections[i].Header.PointerToRawData, Sz);
112 | end;
113 | Inc(FSections[Idx - 1].Header.Misc.VirtualSize, FSections[Idx].Header.Misc.VirtualSize);
114 | SectionAlign(FSections[Idx - 1].Header.Misc.VirtualSize);
115 |
116 | if not IsLast then
117 | Move(FSections[Idx + 1], FSections[Idx], SizeOf(TPESection) * (High(FSections) - Idx));
118 |
119 | SetLength(FSections, High(FSections));
120 | Dec(NTHeaders.FileHeader.NumberOfSections);
121 | end;
122 |
123 | function TPEHeader.GetSectionByVA(V: Cardinal): PPESection;
124 | var
125 | i: Integer;
126 | begin
127 | for i := 0 to High(FSections) do
128 | if FSections[i].Header.VirtualAddress + FSections[i].Header.Misc.VirtualSize > V then
129 | Exit(@FSections[i]);
130 |
131 | Result := nil;
132 | end;
133 |
134 | procedure TPEHeader.Sanitize;
135 | var
136 | i: Integer;
137 | begin
138 | for i := 0 to High(FSections) do
139 | begin
140 | with FSections[i].Header do
141 | begin
142 | PointerToRawData := VirtualAddress;
143 | SizeOfRawData := Misc.VirtualSize;
144 | end;
145 | end;
146 | NTHeaders.OptionalHeader.SizeOfHeaders := FSections[0].Header.PointerToRawData;
147 | // Must have write access in code section (in case .text and .data were merged)
148 | FSections[0].Header.Characteristics := FSections[0].Header.Characteristics or IMAGE_SCN_MEM_WRITE;
149 | end;
150 |
151 | procedure TPEHeader.SaveToStream(S: TStream);
152 | var
153 | i: Integer;
154 | LulzMem: PByte;
155 | begin
156 | S.Seek(FLFANew, soBeginning);
157 | S.Write(NTHeaders, SizeOf(NTHeaders));
158 | for i := 0 to High(FSections) do
159 | begin
160 | S.Write(FSections[i].Header, SizeOf(TImageSectionHeader));
161 | end;
162 | // Zero out some leftovers that may be in the header
163 | GetMem(LulzMem, $200);
164 | FillChar(LulzMem^, $200, 0);
165 | S.Write(LulzMem^, $200);
166 | FreeMem(LulzMem);
167 | end;
168 |
169 | function TPEHeader.TrimHugeSections(Buf: PByte; var IATRawAddr: Cardinal): Cardinal;
170 | var
171 | i, j, ZeroStart: Integer;
172 | SectionStart, OldSectionSize, NewSectionSize, Delta: Cardinal;
173 | begin
174 | Result := 0;
175 | for i := 0 to NTHeaders.FileHeader.NumberOfSections - 1 do
176 | begin
177 | SectionStart := FSections[i].Header.PointerToRawData;
178 | ZeroStart := -1;
179 | for j := (FSections[i].Header.SizeOfRawData div 4) - 1 downto 0 do
180 | if PCardinal(Buf + SectionStart + Cardinal(j) * 4)^ = 0 then
181 | ZeroStart := j * 4
182 | else
183 | Break;
184 |
185 | // We could reduce every single section to its minimal raw size, but having file offset = rva
186 | // is pretty convenient, so we only trim sections that were obviously bloated up
187 | if (ZeroStart <> -1) and (FSections[i].Header.SizeOfRawData - Cardinal(ZeroStart) > 1 * 1024 * 1024) then
188 | begin
189 | OldSectionSize := FSections[i].Header.SizeOfRawData;
190 | SectionAlign(OldSectionSize); // Because of Sanitize(), the actual size is always section-aligned in our case
191 |
192 | NewSectionSize := ZeroStart;
193 | FileAlign(NewSectionSize);
194 | Log(ltInfo, Format('Reducing size of section [%s]: %X -> %X', [Copy(AnsiString(PAnsiChar(@FSections[i].Header.Name)), 1, 8), OldSectionSize, NewSectionSize]));
195 | Delta := OldSectionSize - NewSectionSize;
196 | Inc(Result, Delta);
197 | FSections[i].Header.SizeOfRawData := NewSectionSize;
198 |
199 | if i < High(FSections) then
200 | begin
201 | Move(Buf[FSections[i + 1].Header.PointerToRawData], Buf[SectionStart + NewSectionSize], FDumpSize - SectionStart - OldSectionSize);
202 | for j := i + 1 to High(FSections) do
203 | Dec(FSections[j].Header.PointerToRawData, Delta);
204 | end;
205 |
206 | if IATRawAddr >= SectionStart + OldSectionSize then
207 | Dec(IATRawAddr, Delta);
208 | end;
209 | end;
210 | end;
211 |
212 | procedure TPEHeader.AddSectionToArray;
213 | begin
214 | SetLength(FSections, Length(FSections) + 1);
215 | end;
216 |
217 | procedure TPEHeader.FileAlign(var V: Cardinal);
218 | var
219 | Delta: Cardinal;
220 | begin
221 | Delta := V mod NTHeaders.OptionalHeader.FileAlignment;
222 | if Delta > 0 then
223 | Inc(V, NTHeaders.OptionalHeader.FileAlignment - Delta);
224 | end;
225 |
226 | procedure TPEHeader.SectionAlign(var V: Cardinal);
227 | var
228 | Delta: Cardinal;
229 | begin
230 | Delta := V mod NTHeaders.OptionalHeader.SectionAlignment;
231 | if Delta > 0 then
232 | Inc(V, NTHeaders.OptionalHeader.SectionAlignment - Delta);
233 | end;
234 |
235 | function TPEHeader.ConvertOffsetToRVAVector(Offset: NativeUInt): NativeUInt;
236 | var
237 | i: Integer;
238 | begin
239 | for i := 0 to High(FSections) do
240 | if (FSections[i].Header.PointerToRawData <= Offset) and ((FSections[i].Header.PointerToRawData + FSections[i].Header.SizeOfRawData) > Offset) then
241 | Exit((Offset - FSections[i].Header.PointerToRawData) + FSections[i].Header.VirtualAddress);
242 |
243 | Result := 0;
244 | end;
245 |
246 | end.
247 |
--------------------------------------------------------------------------------
/Patcher.pas:
--------------------------------------------------------------------------------
1 | unit Patcher;
2 |
3 | interface
4 |
5 | uses Windows, SysUtils, Classes, PEInfo, Generics.Collections, Utils;
6 |
7 | type
8 | TPatcher = class
9 | private
10 | FFileName: string;
11 | FStream: TMemoryStream;
12 | PE: TPEHeader;
13 |
14 | procedure ShrinkPE;
15 | procedure ShrinkExportSect;
16 |
17 | // Proper section characteristics are important for MSVC applications because they
18 | // check them during C runtime initialization (especially .rdata).
19 | procedure MapleCreateDataSections;
20 | procedure MSVCCreateDataSections;
21 |
22 | function FindDataStartMSVC6: NativeUInt;
23 | function FindDynTLSMSVC14(out DynTLSInit: NativeUInt): Boolean;
24 | //function FindDataStartByDisasm: NativeUInt;
25 | public
26 | constructor Create(const AFileName: string);
27 | destructor Destroy; override;
28 |
29 | procedure ProcessShrink;
30 | procedure ProcessMkData;
31 |
32 | procedure DumpProcessCode(hProcess: THandle);
33 | end;
34 |
35 | implementation
36 |
37 | uses Debugger, StrUtils;
38 |
39 | { TPatcher }
40 |
41 | constructor TPatcher.Create(const AFileName: string);
42 | begin
43 | FFileName := AFileName;
44 | FStream := TMemoryStream.Create;
45 | FStream.LoadFromFile(AFileName);
46 | FStream.Position := 0;
47 |
48 | PE := TPEHeader.Create(FStream.Memory);
49 | end;
50 |
51 | destructor TPatcher.Destroy;
52 | begin
53 | FStream.Free;
54 | PE.Free;
55 |
56 | inherited;
57 | end;
58 |
59 | procedure TPatcher.ProcessShrink;
60 | begin
61 | ShrinkPE;
62 | ShrinkExportSect;
63 |
64 | PE.SaveToStream(FStream);
65 | FStream.SaveToFile(FFileName);
66 | end;
67 |
68 | procedure TPatcher.ProcessMkData;
69 | var
70 | Lower: string;
71 | PosMS: Integer;
72 | begin
73 | Lower := LowerCase(FFileName);
74 | PosMS := Lower.LastIndexOf('maplestory');
75 | if (PosMS > 0) and (Pos('.exe', Lower, PosMS) < PosMS + 10 + 10) then
76 | MapleCreateDataSections
77 | else if PE.NTHeaders.OptionalHeader.MajorLinkerVersion = 14 then // MSVC 2015+
78 | MSVCCreateDataSections
79 | else
80 | begin
81 | Log(ltInfo, 'Data section creation not available for this compiler.');
82 | Exit;
83 | end;
84 |
85 | PE.SaveToStream(FStream);
86 | FStream.SaveToFile(FFileName);
87 | end;
88 |
89 | procedure TPatcher.ShrinkPE;
90 | var
91 | i: Integer;
92 | Del: TList;
93 | NS: TMemoryStream;
94 |
95 | function IsReferenced(SH: TImageSectionHeader): Boolean;
96 | var
97 | i: Integer;
98 | begin
99 | for i := 0 to High(PE.NTHeaders.OptionalHeader.DataDirectory) do
100 | with PE.NTHeaders.OptionalHeader.DataDirectory[i] do
101 | begin
102 | if (VirtualAddress >= SH.VirtualAddress) and (VirtualAddress + Size <= SH.VirtualAddress + SH.Misc.VirtualSize) then
103 | Exit(True);
104 | end;
105 | Result := False;
106 | end;
107 |
108 | begin
109 | Del := TList.Create;
110 | NS := TMemoryStream.Create;
111 | NS.CopyFrom(FStream, PE.Sections[0].Header.PointerToRawData);
112 | for i := 0 to High(PE.Sections) do
113 | begin
114 | if not IsReferenced(PE.Sections[i].Header) and (PAnsiChar(@PE.Sections[i].Header.Name) <> '.data')
115 | and (PAnsiChar(@PE.Sections[i].Header.Name) <> '.rdata') and (i > 0) then
116 | begin
117 | Del.Add(i);
118 | if i <> High(PE.Sections) then
119 | FStream.Seek(PE.Sections[i + 1].Header.PointerToRawData - PE.Sections[i].Header.PointerToRawData, soCurrent);
120 | end
121 | else
122 | begin
123 | if i <> High(PE.Sections) then
124 | NS.CopyFrom(FStream, PE.Sections[i + 1].Header.PointerToRawData - PE.Sections[i].Header.PointerToRawData)
125 | else
126 | NS.CopyFrom(FStream, PE.SizeOfImage - PE.Sections[i].Header.PointerToRawData);
127 | end;
128 | end;
129 | FStream.Free;
130 | FStream := NS;
131 |
132 | Del.Reverse;
133 | for i in Del do
134 | PE.DeleteSection(i);
135 | Del.Free;
136 | end;
137 |
138 | procedure TPatcher.ShrinkExportSect;
139 | var
140 | Dir: PImageDataDirectory;
141 | EH: PImageSectionHeader;
142 | PBase, PExp: PByte;
143 | Diff, i: Cardinal;
144 | NS: TMemoryStream;
145 | E: PImageExportDirectory;
146 | N: PCardinal;
147 | Name: AnsiString;
148 | begin
149 | Dir := @PE.NTHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
150 | EH := @PE.GetSectionByVA(Dir.VirtualAddress)^.Header;
151 | PBase := PByte(FStream.Memory) + EH.PointerToRawData;
152 | PExp := PBase + (Dir.VirtualAddress - EH.VirtualAddress);
153 | Move(PExp^, PBase^, Dir.Size);
154 | FillChar((PBase + Dir.Size)^, $1000 - Dir.Size, 0);
155 | Dir.VirtualAddress := EH.VirtualAddress;
156 |
157 | Diff := NativeUInt(PExp - PBase);
158 | E := Pointer(PBase);
159 | Dec(E.Name, Diff);
160 | Dec(E.AddressOfFunctions, Diff);
161 | Dec(E.AddressOfNames, Diff);
162 | Dec(E.AddressOfNameOrdinals, Diff);
163 | N := PCardinal(PBase + (E.AddressOfNames - EH.VirtualAddress));
164 | for i := 0 to E.NumberOfNames - 1 do
165 | begin
166 | Dec(N^, Diff);
167 | Inc(N);
168 | end;
169 |
170 | Diff := EH.SizeOfRawData - $1000;
171 | Dec(EH.SizeOfRawData, Diff);
172 | for i := 0 to High(PE.Sections) do
173 | begin
174 | if PE.Sections[i].Header.VirtualAddress > EH.VirtualAddress then
175 | begin
176 | Dec(PE.Sections[i].Header.PointerToRawData, Diff);
177 | end;
178 | end;
179 |
180 | Name := '.export'#0;
181 | Move(Name[1], EH.Name[0], Length(Name));
182 | EH.Characteristics := EH.Characteristics and not IMAGE_SCN_MEM_WRITE and not IMAGE_SCN_MEM_EXECUTE;
183 |
184 | FStream.Position := 0;
185 | NS := TMemoryStream.Create;
186 | NS.CopyFrom(FStream, EH.PointerToRawData + $1000);
187 | FStream.Seek(Diff, soCurrent);
188 | NS.CopyFrom(FStream, FStream.Size - FStream.Position);
189 | FStream.Free;
190 | FStream := NS;
191 | end;
192 |
193 | procedure TPatcher.MapleCreateDataSections;
194 | var
195 | Mem: PByte;
196 | DataStart, DataStartTW, DataSize, A, ZEnd, ZStart, GfidsSize: NativeUInt;
197 | RDataStart, RDataSize: NativeUInt;
198 | i: Integer;
199 | Name: AnsiString;
200 | ZSize: Cardinal;
201 | Lock: Boolean;
202 | begin
203 | Mem := PByte(FStream.Memory);
204 | DataStart := FindStatic('10000000200000004000000060000000', Mem + $2000000, FStream.Size - $2000000);
205 | if DataStart = 0 then
206 | begin
207 | if PE.NTHeaders.OptionalHeader.MajorLinkerVersion = 6 then
208 | begin
209 | DataStart := FindDataStartMSVC6;
210 | if DataStart = 0 then
211 | raise Exception.Create('Data section not found');
212 | end
213 | else
214 | begin
215 | DataStart := FindStatic('2E3F41565F636F6D5F6572726F724040', Mem + ($B00000 - $400000), FStream.Size - ($B00000 - $400000));
216 | DataStartTW := FindStatic('2E3F41563F245A4C69737440554D4150494E464F4043416374696F6E4672616D6540404040', Mem + ($B00000 - $400000), FStream.Size - ($B00000 - $400000)); // TW 122+
217 | if (DataStartTW <> 0) and (DataStartTW < DataStart) then
218 | DataStart := DataStartTW;
219 |
220 | if DataStart = 0 then
221 | begin
222 | raise Exception.Create('Data section not found');
223 | end
224 | else
225 | begin
226 | Inc(DataStart, ($B00000 - $400000) - 8);
227 | if ((DataStart and $FFF) = $B4) or ((DataStart and $FFF) = $F8) or ((DataStart and $FFF) = $FC) then
228 | DataStart := DataStart and $FFFFF000;
229 | Log(ltInfo, 'Old executable');
230 | end;
231 | end;
232 | end
233 | else
234 | Inc(DataStart, $2000000);
235 |
236 | if DataStart and $FFF <> 0 then
237 | raise Exception.CreateFmt('Data section bytes found, but not aligned: %X', [DataStart]);
238 |
239 | Log(ltGood, '.data section at ' + IntToHex(DataStart, 8) + ' (VA ' + IntToHex(DataStart + $400000, 8) + ')');
240 |
241 | PE.AddSectionToArray;
242 | PE.AddSectionToArray;
243 | for i := High(PE.Sections) downto 3 do
244 | PE.Sections[i] := PE.Sections[i - 2];
245 |
246 | ZEnd := 0;
247 | ZSize := 0;
248 | Lock := False;
249 | for A := PE.Sections[3].Header.PointerToRawData - 1 downto DataStart do
250 | begin
251 | if (Mem + A)^ = 0 then
252 | begin
253 | if ZSize = 0 then
254 | ZEnd := A+1;
255 | Inc(ZSize);
256 | if (ZSize > $2000) then
257 | begin
258 | Lock := True;
259 | end;
260 | end
261 | else
262 | begin
263 | if Lock then
264 | Break;
265 | ZSize := 0;
266 | end;
267 | end;
268 | Inc(A);
269 |
270 | if ZSize = 0 then
271 | raise Exception.Create('Data section doesn''t contain zeroes');
272 |
273 | // Sometimes first byte of following section is 0
274 | if ZEnd and $FFF = 1 then
275 | begin
276 | Dec(ZEnd);
277 | Dec(ZSize);
278 | end;
279 |
280 | if ZEnd and $FFF <> 0 then
281 | raise Exception.CreateFmt('Real .data section end not found (got %X with a size of %X)', [ZEnd, ZSize]);
282 |
283 | ZStart := (A + $1000) and $FFFFF000;
284 | Dec(ZSize, ZStart - A);
285 |
286 | GfidsSize := PE.Sections[3].Header.PointerToRawData - ZEnd;
287 |
288 | // .data
289 | Name := '.data';
290 | DataSize := PE.Sections[3].Header.PointerToRawData - DataStart - GfidsSize;
291 | FillChar(PE.Sections[2], SizeOf(TPESection), 0);
292 | Move(Name[1], PE.Sections[2].Header.Name[0], Length(Name));
293 | with PE.Sections[2].Header do
294 | begin
295 | Misc.VirtualSize := DataSize;
296 | VirtualAddress := DataStart;
297 | PointerToRawData := DataStart;
298 | SizeOfRawData := DataSize - ZSize;
299 | Characteristics := IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE or IMAGE_SCN_CNT_INITIALIZED_DATA;
300 | end;
301 |
302 | // .rdata
303 | Name := '.rdata';
304 | RDataStart := PE.NTHeaders.OptionalHeader.BaseOfData;
305 | RDataSize := DataStart - RDataStart;
306 | FillChar(PE.Sections[1], SizeOf(TPESection), 0);
307 | Move(Name[1], PE.Sections[1].Header.Name[0], Length(Name));
308 | with PE.Sections[1].Header do
309 | begin
310 | Misc.VirtualSize := RDataSize;
311 | VirtualAddress := RDataStart;
312 | PointerToRawData := RDataStart;
313 | SizeOfRawData := RDataSize;
314 | Characteristics := IMAGE_SCN_MEM_READ or IMAGE_SCN_CNT_INITIALIZED_DATA;
315 | end;
316 |
317 | // .gfids/.vmp
318 | if GfidsSize <> 0 then
319 | begin
320 | PE.AddSectionToArray;
321 | for i := High(PE.Sections) downto 4 do
322 | PE.Sections[i] := PE.Sections[i - 1];
323 |
324 | if PE.NTHeaders.OptionalHeader.MajorLinkerVersion >= 14 then
325 | Name := '.gfids'
326 | else
327 | Name := '.vmp';
328 |
329 | FillChar(PE.Sections[3], SizeOf(TPESection), 0);
330 | Move(Name[1], PE.Sections[3].Header.Name[0], Length(Name));
331 | with PE.Sections[3].Header do
332 | begin
333 | Misc.VirtualSize := GfidsSize;
334 | VirtualAddress := ZEnd;
335 | PointerToRawData := ZEnd;
336 | SizeOfRawData := GfidsSize;
337 | Characteristics := IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE or IMAGE_SCN_CNT_INITIALIZED_DATA;
338 | end;
339 |
340 | Inc(PE.NTHeaders.FileHeader.NumberOfSections, 3);
341 | end
342 | else
343 | begin
344 | if PE.NTHeaders.OptionalHeader.MajorLinkerVersion >= 14 then
345 | Log(ltFatal, '.gfids not found');
346 | Inc(PE.NTHeaders.FileHeader.NumberOfSections, 2);
347 | end;
348 |
349 | Dec(PE.Sections[0].Header.Misc.VirtualSize, RDataSize + DataSize + GfidsSize);
350 | Dec(PE.Sections[0].Header.SizeOfRawData, RDataSize + DataSize + GfidsSize);
351 |
352 | Name := '.text'#0#0#0;
353 | Move(Name[1], PE.Sections[0].Header.Name[0], Length(Name));
354 | PE.Sections[0].Header.Characteristics := PE.Sections[0].Header.Characteristics and not IMAGE_SCN_MEM_WRITE;
355 | end;
356 |
357 | function TPatcher.FindDataStartMSVC6: NativeUInt;
358 | var
359 | CInitCode: NativeUInt;
360 | begin
361 | // In MSVC6 binaries, the second (r/w) data section appears to start with the __cinit func list
362 | CInitCode := FindDynamic('68????????68??????00E8????????83C410C3', PByte(FStream.Memory) + $100000, FStream.Size - $100000);
363 | if CInitCode = 0 then
364 | Exit(0);
365 |
366 | Inc(CInitCode, $100000);
367 | Result := PCardinal(PByte(FStream.Memory) + CInitCode + 6)^;
368 | if Result and $FFF <> 0 then
369 | Result := 0
370 | else
371 | Dec(Result, PE.NTHeaders.OptionalHeader.ImageBase);
372 | end;
373 |
374 | function TPatcher.FindDynTLSMSVC14(out DynTLSInit: NativeUInt): Boolean;
375 | var
376 | DynTLSCode: NativeUInt;
377 | CodePtr, GetPtrFunc, DynTLSInitPtr: PByte;
378 | begin
379 | {
380 | call __scrt_get_dyn_tls_init_callback
381 | mov esi, eax
382 | xor edi, edi
383 | cmp [esi], edi
384 | jz short ??
385 | push esi
386 | call __scrt_is_nonwritable_in_current_image
387 | }
388 | DynTLSCode := FindDynamic('8BF033FF393E74??56E8', PByte(FStream.Memory) + $1000, FStream.Size - $1000);
389 | if DynTLSCode = 0 then
390 | begin
391 | Log(ltInfo, 'DynTLS code sequence not found.');
392 | Exit(False);
393 | end;
394 |
395 | CodePtr := PByte(FStream.Memory) + $1000 + DynTLSCode;
396 | if (CodePtr - 5)^ <> $E8 then
397 | begin
398 | Log(ltInfo, 'DynTLS code sequence mismatch.');
399 | Exit(False);
400 | end;
401 |
402 | GetPtrFunc := CodePtr + PInteger(CodePtr - 4)^;
403 | if GetPtrFunc^ = $E9 then // another indirection via jmp
404 | GetPtrFunc := GetPtrFunc + PInteger(GetPtrFunc + 1)^ + 5;
405 | if GetPtrFunc^ <> $B8 then
406 | begin
407 | Log(ltInfo, 'DynTLS call analysis failed.');
408 | Exit(False);
409 | end;
410 |
411 | DynTLSInit := PCardinal(GetPtrFunc + 1)^ - PE.NTHeaders.OptionalHeader.ImageBase;
412 | DynTLSInitPtr := PByte(FStream.Memory) + DynTLSInit;
413 |
414 | Log(ltInfo, Format('[MSVC] dyn_tls_init at %.8X', [PCardinal(DynTLSInitPtr)^]));
415 |
416 | // If the function pointer points to 0, the compiler places this var in a writable section
417 | // and we can't use it as a separator.
418 | if PCardinal(DynTLSInitPtr)^ = 0 then
419 | DynTLSInit := 0;
420 |
421 | Result := True;
422 | end;
423 |
424 | {
425 | This was a fun idea but it fails when executables have a construct like this as their first written access:
426 | mov ecx, offset FOO
427 | call DereferenceAndWriteEcx
428 |
429 | function TPatcher.FindDataStartByDisasm: NativeUInt;
430 | var
431 | Dis: _Disasm;
432 | Res: Integer;
433 | Addresses: TDictionary;
434 | AddressesList: TList;
435 | CandidateStart, CandidateEnd, Base: NativeUInt;
436 | i, j: Integer;
437 | OK: Boolean;
438 | begin
439 | FillChar(Dis, SizeOf(Dis), 0);
440 | Dis.Archi := 32;
441 | Dis.EIP := NativeUInt(FStream.Memory) + PE.Sections[0].Header.VirtualAddress;
442 | Dis.VirtualAddr := PE.Sections[0].Header.VirtualAddress;
443 |
444 | CandidateStart := PE.NTHeaders.OptionalHeader.BaseOfData;
445 | CandidateEnd := PE.Sections[0].Header.VirtualAddress + PE.Sections[0].Header.Misc.VirtualSize;
446 | Base := PE.NTHeaders.OptionalHeader.ImageBase;
447 |
448 | Addresses := TDictionary.Create;
449 | // Disassemble the entire text section and collect written addresses.
450 | while Dis.VirtualAddr < CandidateStart do
451 | begin
452 | Res := Disasm(Dis);
453 | if Res <= 0 then
454 | begin
455 | Inc(Dis.EIP);
456 | Inc(Dis.VirtualAddr);
457 | Continue;
458 | end;
459 |
460 | if ((Dis.Argument1.ArgType and $F0000000) = MEMORY_TYPE) and
461 | (Dis.Argument1.Memory.BaseRegister = 0) and
462 | (Dis.Argument1.Memory.Displacement <> 0) and
463 | (Dis.Argument1.AccessMode <> READ) and
464 | (NativeUInt(Dis.Argument1.Memory.Displacement) >= CandidateStart + Base) and
465 | (NativeUInt(Dis.Argument1.Memory.Displacement) < CandidateEnd + Base) then
466 | begin
467 | Addresses.AddOrSetValue(Dis.Argument1.Memory.Displacement, True);
468 | end;
469 |
470 | Inc(Dis.EIP, Res);
471 | Inc(Dis.VirtualAddr, Res);
472 | end;
473 |
474 | AddressesList := nil;
475 | try
476 | if Addresses.Count = 0 then
477 | Exit(0);
478 |
479 | AddressesList := TList.Create(Addresses.Keys);
480 | AddressesList.Sort;
481 |
482 | if AddressesList.Count < 3 then
483 | begin
484 | Log(ltInfo, Format('Only few mem writes, picking first reference for .data: %.8x.', [AddressesList[0] - Base]));
485 | Exit((AddressesList[0] - Base) and not $FFF);
486 | end;
487 |
488 | for i := 0 to AddressesList.Count - 1 do
489 | begin
490 | // Check if we have a set of 3 addresses that are all within $40 of each other.
491 | // This is a pretty dumb heuristic, 3 and $40 are randomly chosen.
492 | OK := True;
493 | for j := i + 1 to i + 2 do
494 | if AddressesList[j] > AddressesList[j - 1] + $40 then
495 | OK := False;
496 |
497 | if OK then
498 | begin
499 | Log(ltInfo, Format('Heuristic picked %.8x as first actual .data write.', [AddressesList[i] - Base]));
500 | Exit((AddressesList[i] - Base) and not $FFF);
501 | end;
502 | end;
503 |
504 | Result := 0;
505 | finally
506 | AddressesList.Free;
507 | Addresses.Free;
508 | end;
509 | end;
510 | }
511 |
512 | procedure TPatcher.MSVCCreateDataSections;
513 | var
514 | i: Integer;
515 | DynTLS: NativeUInt;
516 | BaseOfData, DataStart, DataSize, RDataStart, RDataSize: Cardinal;
517 | Name: AnsiString;
518 | begin
519 | BaseOfData := PE.NTHeaders.OptionalHeader.BaseOfData;
520 | if (BaseOfData > PE.Sections[0].Header.VirtualAddress) and
521 | (BaseOfData < PE.Sections[0].Header.VirtualAddress + PE.Sections[0].Header.Misc.VirtualSize) and
522 | ((BaseOfData and $FFF) = 0) then
523 | begin
524 | if not FindDynTLSMSVC14(DynTLS) then
525 | Exit;
526 |
527 | // This is by no means exact. We keep the writable data section as large as possible because
528 | // we can't determine its real size in a generic way and we don't want to risk access violations.
529 | if DynTLS <> 0 then
530 | begin
531 | DataStart := (DynTLS + $1000) and not $FFF;
532 | end
533 | else
534 | begin
535 | DataStart := BaseOfData + $1000;
536 | Log(ltInfo, 'Setting .rdata size to just 1000 (no reference point for actual size)');
537 | end;
538 |
539 | PE.AddSectionToArray;
540 | PE.AddSectionToArray;
541 | for i := High(PE.Sections) downto 3 do
542 | PE.Sections[i] := PE.Sections[i - 2];
543 |
544 | Inc(PE.NTHeaders.FileHeader.NumberOfSections, 2);
545 |
546 | // .data at [2]
547 | Name := '.data';
548 | DataSize := PE.Sections[3].Header.PointerToRawData - DataStart;
549 | FillChar(PE.Sections[2], SizeOf(TPESection), 0);
550 | Move(Name[1], PE.Sections[2].Header.Name[0], Length(Name));
551 | with PE.Sections[2].Header do
552 | begin
553 | Misc.VirtualSize := DataSize;
554 | VirtualAddress := DataStart;
555 | PointerToRawData := DataStart;
556 | SizeOfRawData := DataSize;
557 | Characteristics := IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE or IMAGE_SCN_CNT_INITIALIZED_DATA;
558 | end;
559 |
560 | // .rdata at [1]
561 | Name := '.rdata';
562 | RDataStart := BaseOfData;
563 | RDataSize := DataStart - RDataStart;
564 | FillChar(PE.Sections[1], SizeOf(TPESection), 0);
565 | Move(Name[1], PE.Sections[1].Header.Name[0], Length(Name));
566 | with PE.Sections[1].Header do
567 | begin
568 | Misc.VirtualSize := RDataSize;
569 | VirtualAddress := RDataStart;
570 | PointerToRawData := RDataStart;
571 | SizeOfRawData := RDataSize;
572 | Characteristics := IMAGE_SCN_MEM_READ or IMAGE_SCN_CNT_INITIALIZED_DATA;
573 | end;
574 |
575 | Dec(PE.Sections[0].Header.Misc.VirtualSize, RDataSize + DataSize);
576 | Dec(PE.Sections[0].Header.SizeOfRawData, RDataSize + DataSize);
577 |
578 | with PE.Sections[0].Header do
579 | Log(ltInfo, Format('.text : %.8x ~ %.8x', [VirtualAddress, VirtualAddress + Misc.VirtualSize]));
580 | with PE.Sections[1].Header do
581 | Log(ltInfo, Format('.rdata: %.8x ~ %.8x', [VirtualAddress, VirtualAddress + Misc.VirtualSize]));
582 | with PE.Sections[2].Header do
583 | Log(ltInfo, Format('.data : %.8x ~ %.8x', [VirtualAddress, VirtualAddress + Misc.VirtualSize]));
584 | end
585 | else
586 | Log(ltInfo, 'Assuming sections are not merged.');
587 |
588 | // Rename first section and remove WRITE characteristic.
589 | Name := '.text'#0#0#0;
590 | Move(Name[1], PE.Sections[0].Header.Name[0], Length(Name));
591 | PE.Sections[0].Header.Characteristics := PE.Sections[0].Header.Characteristics and not IMAGE_SCN_MEM_WRITE;
592 | end;
593 |
594 | procedure TPatcher.DumpProcessCode(hProcess: THandle);
595 | var
596 | StartAddr, EndAddr, NumRead: NativeUInt;
597 | Buf: Pointer;
598 | begin
599 | StartAddr := PE.NTHeaders.OptionalHeader.ImageBase + PE.Sections[0].Header.VirtualAddress;
600 | EndAddr := PE.NTHeaders.OptionalHeader.ImageBase + PE.NTHeaders.OptionalHeader.BaseOfData;
601 |
602 | GetMem(Buf, EndAddr - StartAddr);
603 | try
604 | if not ReadProcessMemory(hProcess, Pointer(StartAddr), Buf, EndAddr - StartAddr, NumRead) or (NumRead <> EndAddr - StartAddr) then
605 | RaiseLastOSError;
606 |
607 | FStream.Seek(PE.Sections[0].Header.PointerToRawData, soBeginning);
608 | FStream.Write(Buf^, EndAddr - StartAddr);
609 | FStream.SaveToFile(ChangeFileExt(FFilename, '.novm.exe'));
610 |
611 | Log(ltGood, Format('Dumped %X bytes.', [EndAddr - StartAddr]));
612 | finally
613 | FreeMem(Buf);
614 | end;
615 | end;
616 |
617 | end.
618 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Magicmida
2 |
3 | Magicmida is a Themida auto unpacker that works on some 32-bit applications.
4 |
5 | Functions:
6 | * Unpack: Unpacks the binary you select. The unpacked binary will be saved with an `U` suffix.
7 | * Auto create data sections: Restores .rdata/.data sections. Only works on specific targets. This is a must for MSVC applications using Thread Local Storage because they don't work properly otherwise.
8 | * Dump process: Allows you to enter the PID of a running process whose .text section will be dumped (overwritten) into an already unpacked file. This is useful after using Oreans Unvirtualizer in OllyDbg. Only works properly if data sections were created.
9 | * Shrink: Deletes all sections that are no longer needed (if you unvirtualized or if your binary does not use virtualization). Warning: This will break your binary for non-MSVC compilers.
10 |
11 | Note: The tool focuses on cleanness of the resulting binaries. Things such as VM anti-dump are explicitly *not* fixed. If your target has a virtualized entrypoint, the resulting dump will be broken and won't run (except for MSVC6, which has special fixup code to restore the OEP).
12 |
13 | Important: Never activate any compatibility mode options for Magicmida or for the target you're unpacking. It would very likely screw up the unpacking process due to shimming.
14 |
15 | Windows sometimes decides to auto-apply compatibility patches to an executable if it crashed before. This AppCompat information is stored in the registry and is linked to the exact path of your executable. This can be a problem if you're upgrading to a newer Magicmida version that has fixes for your target. You can try moving your target to a different path or look around in the subkeys of `HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags`.
16 |
17 | Old targets from 2007-2009 often don't run on Windows 10 and require an older OS version to unpack. The unpacked binaries should then work on newer Windows versions, given that the application itself doesn't have incompatibilities.
18 |
19 | ## Anti-anti-debugging
20 |
21 | Newer versions of Themida detect hardware breakpoints. In order to deal with this, injecting ScyllaHide is supported. A suitable profile is shipped with Magicmida. You just need to download SycllaHide and put `HookLibraryx86.dll` and `InjectorCLIx86.exe` next to `Magicmida.exe`. Do not overwrite scylla_hide.ini unless you know what you're doing.
22 |
23 | ## Command line usage
24 |
25 | If you'd like to automate unpacking, it's possible to invoke Magicmida as a command line application.
26 | To do so, pass the parameters `/unpack `.
27 |
28 | ## Unpacking applications with uiAccess=true
29 |
30 | When unpacking an application that has `uiAccess="true"` in its manifest, you'll likely get process creation error code 740 even when running Magicmida as Administrator.
31 | To get around this, you need to perform the following steps:
32 |
33 | 1. In `Magicmida.exe.manifest`, change `uiAccess` to `true` and recompile.
34 | 1. You need to have some version of Windows SDK installed.
35 | 1. Run `makecert.exe -r -pe -ss MMTestCert MMTestCert.cer`.
36 | 1. Run `certmgr -add MMTestCert.cer -s -r localMachine root`.
37 | 1. In my case, I also had to manually copy the cert to the "Trusted Root Certificate" store.
38 | 1. Run `signtool.exe sign /s MMTestCert Magicmida.exe`.
39 | 1. Copy Magicmida to `C:\Program Files (x86)\Magicmida` and run it from there. This step is important because uiAccess applications need to be in a "trusted location".
40 |
--------------------------------------------------------------------------------
/Tracer.pas:
--------------------------------------------------------------------------------
1 | unit Tracer;
2 |
3 | interface
4 |
5 | uses Windows, SysUtils, Utils;
6 |
7 | type
8 | TTracer = class;
9 |
10 | TTracePredicate = function(Tracer: TTracer; var C: TContext): Boolean of object;
11 |
12 | TTracer = class
13 | private
14 | FProcessID, FThreadID: Cardinal;
15 | FThreadHandle: THandle;
16 | FPredicate: TTracePredicate;
17 | FCounter, FLimit: Cardinal;
18 | FLimitReached: Boolean;
19 | Log: TLogProc;
20 |
21 | FStartAddress: NativeUInt;
22 |
23 | function OnSingleStep(const Ev: TDebugEvent): Cardinal;
24 | public
25 | constructor Create(AProcessID, AThreadID: Cardinal; AThreadHandle: THandle;
26 | APredicate: TTracePredicate; ALog: TLogProc);
27 |
28 | procedure Trace(AAddress: NativeUInt; ALimit: Cardinal);
29 |
30 | property StartAddress: NativeUInt read FStartAddress;
31 | property Counter: Cardinal read FCounter;
32 | property LimitReached: Boolean read FLimitReached;
33 | end;
34 |
35 | implementation
36 |
37 | { TTracer }
38 |
39 | constructor TTracer.Create(AProcessID, AThreadID: Cardinal; AThreadHandle: THandle;
40 | APredicate: TTracePredicate; ALog: TLogProc);
41 | begin
42 | FProcessID := AProcessID;
43 | FThreadID := AThreadID;
44 | FThreadHandle := AThreadHandle;
45 | FPredicate := APredicate;
46 | Log := ALog;
47 | end;
48 |
49 | procedure TTracer.Trace(AAddress: NativeUInt; ALimit: Cardinal);
50 | var
51 | C: TContext;
52 | Ev: TDebugEvent;
53 | Status: Cardinal;
54 | hThread: THandle;
55 | begin
56 | FCounter := 0;
57 | FLimit := ALimit;
58 | FLimitReached := False;
59 | FStartAddress := AAddress;
60 |
61 | C.ContextFlags := CONTEXT_CONTROL;
62 | if not GetThreadContext(FThreadHandle, C) then
63 | RaiseLastOSError;
64 |
65 | C.Eip := AAddress;
66 | C.EFlags := C.EFlags or $100; // Trap
67 | if not SetThreadContext(FThreadHandle, C) then
68 | RaiseLastOSError;
69 |
70 | if not ContinueDebugEvent(FProcessID, FThreadID, DBG_CONTINUE) then
71 | Exit;
72 |
73 | Status := DBG_EXCEPTION_NOT_HANDLED;
74 | while WaitForDebugEvent(Ev, INFINITE) do
75 | begin
76 | if Ev.dwThreadId <> FThreadID then
77 | begin
78 | Log(ltInfo, Format('Suspending spurious thread %d', [Ev.dwThreadId]));
79 | hThread := OpenThread(2, False, Ev.dwThreadId); // THREAD_SUSPEND_RESUME
80 | if hThread <> INVALID_HANDLE_VALUE then
81 | begin
82 | SuspendThread(hThread);
83 | CloseHandle(hThread);
84 | end;
85 | ContinueDebugEvent(Ev.dwProcessId, Ev.dwThreadId, DBG_CONTINUE);
86 | Continue;
87 | end;
88 |
89 | case Ev.dwDebugEventCode of
90 | EXCEPTION_DEBUG_EVENT:
91 | begin
92 | if Ev.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_SINGLE_STEP then
93 | begin
94 | Status := OnSingleStep(Ev);
95 | if Status = DBG_CONTROL_BREAK then
96 | Break;
97 | end
98 | else
99 | begin
100 | Log(ltFatal, Format('Unexpected exception during tracing: %.8X at %p in thread %d', [Ev.Exception.ExceptionRecord.ExceptionCode, Ev.Exception.ExceptionRecord.ExceptionAddress, Ev.dwThreadId]));
101 | Exit;
102 | end;
103 | end;
104 |
105 | else
106 | Status := DBG_CONTINUE;
107 | end;
108 |
109 | ContinueDebugEvent(Ev.dwProcessId, Ev.dwThreadId, Status);
110 | end;
111 | end;
112 |
113 | function TTracer.OnSingleStep(const Ev: TDebugEvent): Cardinal;
114 | var
115 | C: TContext;
116 | begin
117 | Inc(FCounter);
118 | if (FLimit <> 0) and (FCounter > FLimit) then
119 | begin
120 | FLimitReached := True;
121 | Log(ltInfo, 'Giving up trace due to instruction limit');
122 | Exit(DBG_CONTROL_BREAK);
123 | end;
124 |
125 | C.ContextFlags := CONTEXT_CONTROL;
126 | if not GetThreadContext(FThreadHandle, C) then
127 | RaiseLastOSError;
128 |
129 | if FPredicate(Self, C) then
130 | Result := DBG_CONTROL_BREAK
131 | else
132 | Result := DBG_CONTINUE;
133 |
134 | C.EFlags := C.EFlags or $100;
135 | if not SetThreadContext(FThreadHandle, C) then
136 | RaiseLastOSError;
137 | end;
138 |
139 | end.
140 |
--------------------------------------------------------------------------------
/Unit2.dfm:
--------------------------------------------------------------------------------
1 | object ThemidaUnpackerWnd: TThemidaUnpackerWnd
2 | Left = 0
3 | Top = 0
4 | Caption = 'Magicmida'
5 | ClientHeight = 300
6 | ClientWidth = 635
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -11
11 | Font.Name = 'Tahoma'
12 | Font.Style = []
13 | OnCreate = FormCreate
14 | TextHeight = 13
15 | object btnUnpack: TButton
16 | Left = 0
17 | Top = 0
18 | Width = 94
19 | Height = 24
20 | Align = alLeft
21 | Caption = 'Unpack'
22 | TabOrder = 0
23 | OnClick = btnUnpackClick
24 | end
25 | object LV: TListView
26 | Left = 0
27 | Top = 24
28 | Width = 635
29 | Height = 276
30 | Align = alBottom
31 | Anchors = [akLeft, akTop, akRight, akBottom]
32 | Columns = <
33 | item
34 | AutoSize = True
35 | end>
36 | SmallImages = ImageList1
37 | TabOrder = 1
38 | ViewStyle = vsReport
39 | ExplicitWidth = 631
40 | ExplicitHeight = 275
41 | end
42 | object btnShrink: TButton
43 | Left = 496
44 | Top = 0
45 | Width = 139
46 | Height = 24
47 | Hint =
48 | 'Strips all Themida sections from the binary. Only works if absol' +
49 | 'utely no VM references are left!'
50 | Align = alRight
51 | Caption = 'Shrink (after unvirtualizing)'
52 | ParentShowHint = False
53 | ShowHint = True
54 | TabOrder = 2
55 | OnClick = btnShrinkClick
56 | ExplicitLeft = 492
57 | end
58 | object btnDumpProcess: TButton
59 | Left = 416
60 | Top = 0
61 | Width = 80
62 | Height = 24
63 | Hint = 'For dumping process after using OreansUnvirtualizer'
64 | Align = alRight
65 | Caption = 'Dump process'
66 | ParentShowHint = False
67 | ShowHint = True
68 | TabOrder = 3
69 | OnClick = btnDumpProcessClick
70 | ExplicitLeft = 412
71 | end
72 | object cbDataSections: TCheckBox
73 | Left = 112
74 | Top = 3
75 | Width = 176
76 | Height = 17
77 | Hint =
78 | 'Attempt to split Themida merged sections. This is vital for MSVC' +
79 | ' applications utilizing Thread Local Storage.'
80 | Caption = 'Auto create data sections'
81 | Checked = True
82 | ParentShowHint = False
83 | PopupMenu = pmSections
84 | ShowHint = True
85 | State = cbChecked
86 | TabOrder = 4
87 | end
88 | object OD: TOpenDialog
89 | Filter = 'Application|*.exe|Nexshit|*.aes'
90 | Options = [ofHideReadOnly, ofFileMustExist, ofEnableSizing]
91 | Left = 120
92 | Top = 32
93 | end
94 | object ImageList1: TImageList
95 | Left = 200
96 | Top = 32
97 | Bitmap = {
98 | 494C010103000800040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
99 | 0000000000003600000028000000400000001000000001002000000000000010
100 | 0000000000000000000000000000000000000000000000000000000000000000
101 | 0000F6EAE420DBA6898FCE8155CFCC6B35FFCF7139FFD68757CFE5AE8C8FF9ED
102 | E520000000000000000000000000000000000000000000000000000000000000
103 | 000000000000FBFBFB04EBEBEB14D5D5D52AD5D5D52AEAEAEA15FBFBFB040000
104 | 0000000000000000000000000000000000000000000000000000000000000000
105 | 0000000000000000000000000000000000000000000000000000000000000000
106 | 0000000000000000000000000000000000000000000000000000000000000000
107 | 0000000000000000000000000000000000000000000000000000000000000000
108 | 0000000000000000000000000000000000000000000000000000FAF4F110D7A3
109 | 888FC25F2AFFD1662BFFDA7036FFDE7C42FFE38A4FFFE89A5FFFE69D62FFDE88
110 | 4BFFE9B18D8FFCF6F2100000000000000000000000000000000000000000FCFC
111 | FC03BABFBD46538973B51A885DEF08905DFE059260FE138C64EE4A8976B5B7BD
112 | BB48FAFAFA050000000000000000000000000000000000000000FAFBFE056B8F
113 | E7A16E90E69E6E90E69E6E90E69E6E90E69E6E90E69E6E90E69E6E90E69E6C8F
114 | E7A0D6DFF72E0000000000000000000000000000000000000000000000000000
115 | 0000000000000000000000000000000000000000000000000000000000000000
116 | 00000000000000000000000000000000000000000000FAF4F110C27852CFC65B
117 | 2AFFD26026FFD6682AFFDA7130FFDF7A37FFE4843EFFE98F46FFEF9C53FFF4B9
118 | 79FFEEAB6CFFE2915BCFFCF6F210000000000000000000000000F7F7F7087797
119 | 8A8F0D905AFC008F57FF00925BFF009560FF009965FF009C6BFF00A070FF04A0
120 | 74FB71978D8EF5F5F50A0000000000000000000000005179E0C5F5F6FFFF8C94
121 | FFFF848CFFFF848CFFFF848CFFFF848CFFFF848CFFFF848CFFFF848CFFFF8890
122 | FFFFDDDEFFFF456CDEFF00000000000000000000000000000000000000000000
123 | 0000000000000000000000000000000000000000000000000000000000000000
124 | 00000000000000000000000000000000000000000000D3A0868FC25C2FFFCE5B
125 | 27FFD26024FFD6682AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF994EFFF4A5
126 | 56FFFAC17CFFEFAD6EFFE9B18D8F0000000000000000FCFCFC0376998C900596
127 | 5DFF00965DFF009961FF009C66FF009F6BFF00A370FF00A675FF00A97AFF00AD
128 | 80FF01B085FE719B918EFBFBFB040000000000000000CCCFFFFF1B2AF8FF1D2A
129 | F1FF676ED4FF1E2FF6FF202EF7FF202EF7FF202EF7FF2230F7FF2D36D5FF1023
130 | E7FF1E2CF8FF747CFDFFE4EAFA1B000000000000000000000000000000000000
131 | 0000000000000000000000000000000000000000000000000000000000000000
132 | 000000000000000000000000000000000000F4E9E420B85B2FFFCB5E2FFFCE58
133 | 1EFFD15F23FFD56729FFDA702FFFFFFFFFFFFFFFFFFFE88C44FFED964BFFF19F
134 | 52FFF5A657FFF5BB7BFFDF894CFFF9EDE52000000000BDC4C2430CA067FC009F
135 | 64FF00A168FF06A36EFF32B188FF00A975FF00AD7BFF00B080FF00B385FF00B7
136 | 8BFF00BA90FF04B992FBBBC2C04400000000000000000A1FF1FF0A1DEBFFC5C5
137 | D1FFEAE7E6FF6A6FBFFF0E20F0FF0D22F1FF0D24F1FF1523C1FFEBE8E7FFEAE7
138 | E3FF0013E1FF0007F0FFCED7F5AA000000000000000000000000000000000000
139 | 0000000000000000000000000000000000000000000000000000000000000000
140 | 000000000000000000000000000000000000D09D868FC4673EFFCA541DFFCD57
141 | 1DFFD05E22FFD46527FFD86D2EFFFFFFFFFFFFFFFFFFE58740FFE98F46FFED96
142 | 4CFFEF9B4FFFF09F55FFE79F65FFE5AE8C8FFDFDFD02549A81B400A86CFF00AB
143 | 70FF06AB74FFB3E1D2FFFCFDFDFF5DC6A8FF00B786FF00BB8BFF00BE90FF00C1
144 | 95FF00C49AFF00C79FFF4DA090B2FCFCFC03FBFBFE0A0000EEFF535ACFFFE7E4
145 | E1FFE6E4E1FFE6E4E1FF5E64BCFF0115EEFF0A1DC0FFE9E6E1FFE6E4E1FFE6E4
146 | E1FFB5B5D0FF0000EEFFD1DAF6AE000000000000000000000000000000000000
147 | 0000000000000000000000000000000000000000000000000000000000000000
148 | 000000000000000000000000000000000000BA714FCFD07951FFCA511AFFCC55
149 | 1CFFCF5B20FFD36225FFD76A2BFFFFFFFFFFFFFFFFFFE2803CFFE58741FFE88D
150 | 45FFEA9047FFEA9148FFE99D62FFD68757CFF2F2F20D16AF7AF300B478FF06B4
151 | 7CFFB3E3D4FFD8F1EAFF6BCFB3FFF8FCFBFF5DCEB2FF00C496FF00C89BFF00CB
152 | A0FF00CDA4FF00D0A9FF14C1A2EDEEEEEE11FBFBFE0A0000F5FF0012F5FF5662
153 | BCFFE3DFDDFFE3DFDDFFE4DFDDFF6870B0FFE5E2DDFFE3DFDDFFE3DFDDFFB2B1
154 | C7FF000EF0FF0000F5FFD1DAF4AE000000000000000000000000000000000000
155 | 0000000000000000000000000000000000000000000000000000000000000000
156 | 000000000000000000000000000000000000B56039FFD37D56FFCF622EFFCC56
157 | 1DFFCE581EFFD15F23FFD46528FFFFFFFFFFFFFFFFFFDE7936FFE17F3AFFE383
158 | 3EFFE5853FFFE58640FFE48D51FFD0723AFFDADCDB250DC287FF00C184FF2BC6
159 | 97FFC6EDE2FF19C696FF00C893FF56D3B4FFF8FCFBFF5DD6BBFF01D1A5FF04D5
160 | ABFF04D7B0FF03D9B3FF06DBB8FEDCDDDC23FBFCFE0A0000FFFF000CFFFF0008
161 | FFFF5761C2FFE0DCD8FFE0DCD8FFE0DCD8FFE0DCD8FFE0DCD8FFAFAFC5FF0002
162 | FCFF000CFFFF0000FFFFD1DAF4AE000000000000000000000000000000000000
163 | 0000000000000000000000000000000000000000000000000000000000000000
164 | 000000000000000000000000000000000000B5613BFFD5825CFFD06634FFD166
165 | 32FFD06028FFCF5C22FFD26124FFFFFFFFFFFFFFFFFFDB7131FFDD7634FFDE7A
166 | 37FFDF7C38FFE07C38FFDF7F45FFCC6C36FFDADDDC251ED09AFF18D09AFF0ED0
167 | 99FF06CE98FF01D19CFF01D3A0FF08D5A5FF63DCC2FFF8FDFCFF6BDEC8FF1ADF
168 | BAFF1BE2BFFF1BE3C2FF1EE5C6FEDDDEDE22FBFCFE0A0000FFFF0000FFFF0000
169 | FFFF0000FFFF6970B5FFDEDAD6FFDEDAD6FFDEDAD6FFB6B4C2FF0000FFFF0000
170 | FFFF0000FFFF0000FFFFD1DAF4AE000000000000000000000000000000000000
171 | 0000000000000000000000000000000000000000000000000000000000000000
172 | 000000000000000000000000000000000000B76F4ECFD98D6BFFD06534FFD166
173 | 34FFD26834FFD36934FFFFFFFFFFFFFFFFFFFFFFFFFFD76A2BFFD96E2EFFDA71
174 | 30FFDB7231FFDB7232FFDA7239FFCE8155CFF4F4F40B36D4A6F436DFB0FF36E0
175 | B3FF36E1B6FF36E3B9FF36E4BCFF36E5BFFF35E5C1FF79E5D0FFF9FDFCFF7AE5
176 | D3FF35EACCFF36ECD0FF3CD9C2EEF1F1F10EFBFBFE0A6072FFFF6A7BFFFF6B7C
177 | FFFF5866CEFFF0EDEEFFEFECEEFFEFECEEFFEFECEEFFF0EDEEFF838AC7FF6A7A
178 | FFFF6A7BFFFF6476FFFFCFD8F4AE000000000000000000000000000000000000
179 | 0000000000000000000000000000000000000000000000000000000000000000
180 | 000000000000000000000000000000000000CC9B858FD58E6FFFD16B3DFFD066
181 | 34FFD16734FFD26834FFD36B35FFD56D36FFD66F37FFD77036FFD87136FFD972
182 | 37FFDA7337FFDA7438FFD36F36FFDBA6898FFEFEFE0169BAA4B455EBC3FF55EB
183 | C5FF55ECC8FF55EDCAFF55EECDFF55EFCFFF55F0D1FF54EFD2FF8CEADAFFFAFD
184 | FDFF70ECD9FF55F3DCFF6FB7ADAFFDFDFD02FBFBFE0A5A71FFFF667BFFFF5565
185 | D3FFF2F1F1FFF2F0F0FFF2F0F0FFD7D7DEFFF2F0F0FFF2F0F0FFF2F0F0FF8189
186 | CAFF6579FFFF6075FFFFCFD8F4AE000000000000000000000000000000000000
187 | 0000000000000000000000000000000000000000000000000000000000000000
188 | 000000000000000000000000000000000000F3E8E320B86744FFDB8F6DFFD065
189 | 34FFD06634FFD16734FFD26834FFFCF6F2FFFCF6F3FFD56E37FFD66F37FFD770
190 | 38FFD87138FFD87138FFC46430FFF6EAE42000000000C2CFCC3F70F1D1FD75F4
191 | D5FF75F4D7FF75F5D9FF75F5DBFF75F6DDFF75F6DEFF75F7E0FF74F6E0FF8AF0
192 | E0FF74F4E1FF74F4E2FBC4CDCC3D00000000F9FAFE0B516BFFFF4F67F2FFF5F4
193 | F3FFF3F2F2FFF3F2F2FFCACCDCFF5870FEFF828BCCFFF3F2F2FFF3F2F2FFF3F2
194 | F2FF7F8CE1FF576FFFFFCED7F4AF000000000000000000000000000000000000
195 | 0000000000000000000000000000000000000000000000000000000000000000
196 | 00000000000000000000000000000000000000000000CB9A848FCB8261FFD988
197 | 63FFD06534FFD06634FFD16634FFFCF6F2FFFCF6F2FFD36A35FFD46B36FFD46C
198 | 36FFD56D38FFCA6633FFD7A3888F0000000000000000FEFEFE018EBEB38D93F9
199 | E2FF94FAE4FF94FAE5FF94FAE6FF94FAE7FF94FAE8FF94FBEAFF94FBEBFF94FB
200 | ECFF93FBEDFF93B8B387FEFEFE0100000000000000004A67FFFF516EFFFF7A85
201 | CEFFF5F4F4FFC2C4DAFF4E6AFFFF526FFFFF526DFFFF7A85CEFFF5F4F4FFCACC
202 | DDFF4D6BFFFF4967FFFFE1E8F992000000000000000000000000000000000000
203 | 0000000000000000000000000000000000000000000000000000000000000000
204 | 00000000000000000000000000000000000000000000F9F3F110B56D4ECFCB82
205 | 61FFDB8F6CFFD16B3DFFD06634FFD37041FFD47041FFD26834FFD26A37FFD26D
206 | 40FFC76438FFC27852CFFAF4F110000000000000000000000000FCFCFC0396C0
207 | B78DA9FBEAFDAFFDEEFFAFFDEEFFAFFDEFFFAFFDF0FFAFFDF1FFAFFDF1FFA7FA
208 | EEFC96BBB587FBFBFB04000000000000000000000000B3BFFFFF4666FFFF4868
209 | FFFF6F82E7FF4564FFFF4767FFFF4767FFFF4767FFFF4868FFFF6C7FE6FF4363
210 | FFFF4767FFFF6D87FFFF00000000000000000000000000000000000000000000
211 | 0000000000000000000000000000000000000000000000000000000000000000
212 | 0000000000000000000000000000000000000000000000000000F9F3F110CB9A
213 | 848FB86743FFD48E6EFFD98C6AFFD5815BFFD27C54FFD17B54FFC87049FFBA5F
214 | 34FFD3A0868FFAF4F11000000000000000000000000000000000000000000000
215 | 0000CAD4D23D9BC7BFB2A6F3E6F4BBFEF3FFBBFEF4FFA4F1E6F296C4BDAFC9D2
216 | D13BFEFEFE0100000000000000000000000000000000FFFFFF0AC7D1FFFF5673
217 | FFFF2B54FFFF2B54FFFF2B54FFFF2B54FFFF2B54FFFF2B54FFFF2B54FFFF486A
218 | FFFFA6B4FFFFFFFFFF4D00000000000000000000000000000000000000000000
219 | 0000000000000000000000000000000000000000000000000000000000000000
220 | 0000000000000000000000000000000000000000000000000000000000000000
221 | 0000F3E8E320CC9B858FB76F4ECFB5603AFFB45F38FFBA714FCFD09D868FF4E9
222 | E420000000000000000000000000000000000000000000000000000000000000
223 | 00000000000000000000F7F7F708DEE3E221DEE3E221F7F7F708000000000000
224 | 0000000000000000000000000000000000000000000000000000000000000000
225 | 0000000000000000000000000000000000000000000000000000000000000000
226 | 0000000000000000000000000000000000000000000000000000000000000000
227 | 0000000000000000000000000000000000000000000000000000000000000000
228 | 000000000000000000000000000000000000424D3E000000000000003E000000
229 | 2800000040000000100000000100010000000000800000000000000000000000
230 | 000000000000000000000000FFFFFF00F00FF81FFFFF0000C003E007C0070000
231 | 8001C00380030000800180018001000000008001800100000000000000010000
232 | 0000000000010000000000000001000000000000000100000000000000010000
233 | 0000000000010000000080010001000080018001800100008001C00380030000
234 | C003F00780030000F00FFC3FFFFF000000000000000000000000000000000000
235 | 000000000000}
236 | end
237 | object pmSections: TPopupMenu
238 | Left = 291
239 | Top = 33
240 | object miCreateSectionsNow: TMenuItem
241 | Caption = 'Create now'
242 | OnClick = miCreateSectionsNowClick
243 | end
244 | end
245 | end
246 |
--------------------------------------------------------------------------------
/Unit2.pas:
--------------------------------------------------------------------------------
1 | unit Unit2;
2 |
3 | interface
4 |
5 | uses
6 | Windows, Messages, SysUtils, Variants, Classes, Graphics,
7 | Controls, Forms, Dialogs, StdCtrls, Debugger, ComCtrls, ImgList, Utils, System.ImageList,
8 | Vcl.Menus;
9 |
10 | type
11 | TThemidaUnpackerWnd = class(TForm)
12 | btnUnpack: TButton;
13 | OD: TOpenDialog;
14 | LV: TListView;
15 | ImageList1: TImageList;
16 | btnShrink: TButton;
17 | btnDumpProcess: TButton;
18 | cbDataSections: TCheckBox;
19 | pmSections: TPopupMenu;
20 | miCreateSectionsNow: TMenuItem;
21 | procedure btnDumpProcessClick(Sender: TObject);
22 | procedure btnUnpackClick(Sender: TObject);
23 | procedure btnShrinkClick(Sender: TObject);
24 | procedure miCreateSectionsNowClick(Sender: TObject);
25 | procedure FormCreate(Sender: TObject);
26 | private
27 | procedure Log(MsgType: TLogMsgType; const Msg: string);
28 | end;
29 |
30 | var
31 | ThemidaUnpackerWnd: TThemidaUnpackerWnd;
32 |
33 | implementation
34 |
35 | uses Patcher;
36 |
37 | {$R *.dfm}
38 |
39 | procedure GUILog(MsgType: TLogMsgType; const Msg: string);
40 | begin
41 | ThemidaUnpackerWnd.Log(MsgType, Msg);
42 | end;
43 |
44 | procedure TThemidaUnpackerWnd.FormCreate(Sender: TObject);
45 | begin
46 | Utils.Log := GUILog;
47 | end;
48 |
49 | procedure TThemidaUnpackerWnd.btnUnpackClick(Sender: TObject);
50 | begin
51 | if OD.Execute then
52 | begin
53 | TDebugger.Create(OD.FileName, '', cbDataSections.Checked).FreeOnTerminate := True;
54 | end;
55 | end;
56 |
57 | procedure TThemidaUnpackerWnd.btnShrinkClick(Sender: TObject);
58 | begin
59 | if OD.Execute then
60 | with TPatcher.Create(OD.FileName) do
61 | begin
62 | ProcessShrink();
63 | Free;
64 | end;
65 | end;
66 |
67 | procedure TThemidaUnpackerWnd.miCreateSectionsNowClick(Sender: TObject);
68 | begin
69 | if OD.Execute then
70 | with TPatcher.Create(OD.FileName) do
71 | begin
72 | try
73 | ProcessMkData;
74 | finally
75 | Free;
76 | end;
77 | end;
78 | end;
79 |
80 | procedure TThemidaUnpackerWnd.btnDumpProcessClick(Sender: TObject);
81 | var
82 | PIDInput: string;
83 | PID: NativeInt;
84 | hProcess: THandle;
85 | begin
86 | PIDInput := InputBox('Dump Olly Process', 'PID:', '');
87 | if PIDInput = '' then
88 | Exit;
89 |
90 | PID := StrToInt(PIDInput);
91 |
92 | hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
93 | if hProcess = 0 then
94 | RaiseLastOSError;
95 |
96 | if OD.Execute then
97 | with TPatcher.Create(OD.FileName) do
98 | begin
99 | try
100 | DumpProcessCode(hProcess);
101 | finally
102 | Free;
103 | end;
104 | end;
105 | end;
106 |
107 | procedure TThemidaUnpackerWnd.Log(MsgType: TLogMsgType; const Msg: string);
108 | begin
109 | with LV.Items.Add do
110 | begin
111 | Caption := Msg;
112 | ImageIndex := Integer(MsgType);
113 | MakeVisible(False);
114 | end;
115 | end;
116 |
117 | end.
118 |
--------------------------------------------------------------------------------
/Utils.pas:
--------------------------------------------------------------------------------
1 | unit Utils;
2 |
3 | interface
4 |
5 | uses Windows, SysUtils;
6 |
7 | type
8 | TLogMsgType = (ltInfo, ltGood, ltFatal);
9 | TLogProc = procedure(MsgType: TLogMsgType; const Msg: string);
10 |
11 | var
12 | /// Global log proc, must be set before doing anything!
13 | Log: TLogProc;
14 |
15 | function NtQueryInformationProcess(ProcessHandle: THandle; ProcessInformationClass: DWORD;
16 | ProcessInformation: Pointer; ProcessInformationLength: DWORD; ReturnLength: PCardinal): Integer; stdcall; external 'ntdll.dll';
17 | function NtQueryInformationThread(ThreadHandle: THandle; ThreadInformationClass: DWORD;
18 | ThreadInformation: Pointer; ThreadInformationLength: DWORD; ReturnLength: PCardinal): Integer; stdcall; external 'ntdll.dll';
19 | //function DebugActiveProcessStop(PID: Cardinal): BOOL; stdcall; external kernel32;
20 | function OpenThread(dwDesiredAccess: Cardinal; bInheritHandle: BOOL; dwThreadId: Cardinal): THandle; stdcall; external kernel32;
21 |
22 | const
23 | STATUS_SUCCESS = Integer(0);
24 |
25 | type
26 | TProcessBasicInformation = packed record
27 | ExitStatus: Cardinal;
28 | PebBaseAddress: Pointer;
29 | AffinityMask: PULONG;
30 | BasePriority: DWORD;
31 | UniqueProcessId: ULONG;
32 | InheritedFromUniqueProcessId: ULONG;
33 | end;
34 |
35 | TThreadBasicInformation = packed record
36 | ExitStatus: Cardinal;
37 | TebBaseAddress: Pointer;
38 | UniqueProcess: THandle;
39 | UniqueThread: THandle;
40 | AffinityMask: PULONG;
41 | Priority: DWORD;
42 | BasePriority: DWORD;
43 | end;
44 |
45 | function FindDynamic(const APattern: AnsiString; ABuf: PByte; ASize: Cardinal): Cardinal;
46 | function FindStatic(const APattern: AnsiString; ABuf: PByte; ASize: Cardinal): Cardinal;
47 |
48 | implementation
49 |
50 | function FindDynamic(const APattern: AnsiString; ABuf: PByte; ASize: Cardinal): Cardinal;
51 | var
52 | bWC: Cardinal;
53 | B: TArray;
54 | i, j: Cardinal;
55 | Max: PByte;
56 | begin
57 | bWC := 0;
58 |
59 | SetLength(B, Length(APattern) div 2);
60 | for i := 1 to Length(APattern) div 2 do
61 | if APattern[i * 2 - 1] <> AnsiChar('?') then
62 | Val('$' + string(APattern[i * 2 - 1] + APattern[i * 2]), B[i - 1], j)
63 | else
64 | bWC := bWC or (1 shl (i - 1));
65 |
66 | i := Cardinal(ABuf);
67 | Max := ABuf + ASize - Length(B);
68 | while ABuf < Max do
69 | begin
70 | for j := 0 to High(B) do
71 | begin
72 | if ((bWC shr j) and 1 = 0) and (PByte(ABuf + j)^ <> B[j]) then
73 | Break;
74 |
75 | if j = UInt32(High(B)) then
76 | Exit(Cardinal(ABuf) - i);
77 | end;
78 |
79 | Inc(ABuf);
80 | end;
81 |
82 | Result := 0;
83 | end;
84 |
85 | function FindStatic(const APattern: AnsiString; ABuf: PByte; ASize: Cardinal): Cardinal;
86 | var
87 | B: TArray;
88 | i, j: Cardinal;
89 | Max: PByte;
90 | begin
91 | SetLength(B, Length(APattern) div 2);
92 | for i := 1 to Length(APattern) div 2 do
93 | Val('$' + string(APattern[i * 2 - 1] + APattern[i * 2]), B[i - 1], j);
94 |
95 | i := Cardinal(ABuf);
96 | Max := ABuf + ASize - Length(B);
97 | while ABuf < Max do
98 | begin
99 | if CompareMem(ABuf, @B[0], Length(B)) then
100 | Exit(Cardinal(ABuf) - i);
101 |
102 | Inc(ABuf);
103 | end;
104 |
105 | Result := 0;
106 | end;
107 |
108 | end.
109 |
--------------------------------------------------------------------------------
/fatal.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hendi48/Magicmida/58b895a1918d718d4c1d9383595dfbda8620dbf3/fatal.ico
--------------------------------------------------------------------------------
/good_or_tick.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hendi48/Magicmida/58b895a1918d718d4c1d9383595dfbda8620dbf3/good_or_tick.ico
--------------------------------------------------------------------------------
/information.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hendi48/Magicmida/58b895a1918d718d4c1d9383595dfbda8620dbf3/information.ico
--------------------------------------------------------------------------------
/scylla_hide.ini:
--------------------------------------------------------------------------------
1 | [SETTINGS]
2 | CurrentProfile=Magicmida
3 | [Magicmida]
4 | DLLNormal=1
5 | DLLStealth=0
6 | DLLUnload=0
7 | GetLocalTimeHook=0
8 | GetSystemTimeHook=0
9 | GetTickCount64Hook=0
10 | GetTickCountHook=0
11 | KiUserExceptionDispatcherHook=0
12 | NtCloseHook=0
13 | NtContinueHook=0
14 | NtCreateThreadExHook=0
15 | NtGetContextThreadHook=1
16 | NtQueryInformationProcessHook=1
17 | NtQueryObjectHook=0
18 | NtQueryPerformanceCounterHook=0
19 | NtQuerySystemInformationHook=1
20 | NtQuerySystemTimeHook=0
21 | NtSetContextThreadHook=0
22 | NtSetDebugFilterStateHook=0
23 | NtSetInformationThreadHook=1
24 | NtSetInformationProcessHook=0
25 | NtUserBlockInputHook=0
26 | NtUserBuildHwndListHook=0
27 | NtUserFindWindowExHook=0
28 | NtUserQueryWindowHook=0
29 | NtUserGetForegroundWindowHook=1
30 | NtYieldExecutionHook=0
31 | OutputDebugStringHook=0
32 | PebBeingDebugged=1
33 | PebHeapFlags=1
34 | PebNtGlobalFlag=1
35 | PebStartupInfo=0
36 | PebOsBuildNumber=0
37 | PreventThreadCreation=0
38 | RemoveDebugPrivileges=0
39 | AutostartServer=1
40 | ServerPort=1337
41 | BreakOnTLS=1
42 | FixOllyBugs=1
43 | RemoveEPBreak=0
44 | SkipEPOutsideCode=1
45 | X64Fix=1
46 | WindowTitle=Themida
47 |
--------------------------------------------------------------------------------
/tree_2.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hendi48/Magicmida/58b895a1918d718d4c1d9383595dfbda8620dbf3/tree_2.ico
--------------------------------------------------------------------------------