├── .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 |
ThemidaUnpackerWnd
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 --------------------------------------------------------------------------------