Shfloder.dll Source by pony
[HIDE="5"]
library shfolder;
uses
Windows;
{$R *.res}
var
CrcTable: Array [0 .. 255] of DWORD;
ModHandle: THandle;
SysPath: PChar;
pSHGetFolderPathA: Pointer;
pSHGetFolderPathW: Pointer;
AdrValueCmp, FinalizeArrayAdr: DWORD;
TrustPatched: Boolean;
TrustPatchData: array [0 .. 4] of byte = ( $33, $C0, $C2, $0C, $00 );
procedure SHGetFolderPathA;
asm
jmp pSHGetFolderPathA
end;
procedure SHGetFolderPathW;
asm
jmp pSHGetFolderPathW
end;
// CRC32
procedure MakeCrcTable;
var
i, j, Crc: DWORD;
begin
for i := 0 to 255 do
begin
Crc := i;
for j := 0 to 7 do
begin
if (Crc and 1) <> 0 then
Crc := (Crc shr 1) xor $EDB88320
else
Crc := Crc shr 1;
end;
CrcTable := Crc;
end;
end;
function CalcFileCRC(FileName: string): DWORD;
var
F: file;
BytesRead: DWORD;
CRC32: DWORD;
Buffer: array [1 .. 65500] of byte;
i: Word;
begin
MakeCrcTable;
FileMode := 0;
CRC32 := $FFFFFFFF;
{$I-}
AssignFile(F, FileName);
Reset(F, 1);
if IoResult = 0 then
begin
repeat
BlockRead(F, Buffer, Sizeof(Buffer), BytesRead);
for i := 1 to BytesRead do
CRC32 := (CRC32 shr 8) xor CrcTable
[Buffer xor (CRC32 and $000000FF)];
until BytesRead = 0;
end;
CloseFile(F);
{$I+}
Result := not CRC32;
end;
procedure AsmCode;
asm
push eax
mov eax, AdrValueCmp
cmp eax, dword ptr [esp+$4]
jnz @LeaveASm
mov eax, dword ptr [ebp-$4C]
mov byte ptr [eax], $1
@LeaveASm:
pop eax
jmp FinalizeArrayAdr
end;
function PatchTrustVerify: Boolean;
var
HdlTrust: THandle;
ApiAddress: Pointer;
vOldProtect: DWORD;
begin
HdlTrust := LoadLibrary('wintrust.dll');
if HdlTrust <> 0 then
begin
ApiAddress := GetProcAddress(HdlTrust, 'WinVerifyTrust');
if ApiAddress <> nil then
begin
VirtualProtect(ApiAddress, 5, PAGE_EXECUTE_READWRITE, @vOldProtect);
Move(TrustPatchData[0], ApiAddress^, 5);
VirtualProtect(ApiAddress, 5, vOldProtect, @vOldProtect);
end;
ApiAddress := GetProcAddress(HdlTrust, 'WinVerifyTrustEx');
if ApiAddress <> nil then
begin
VirtualProtect(ApiAddress, 5, PAGE_EXECUTE_READWRITE, @vOldProtect);
Move(TrustPatchData[0], ApiAddress^, 5);
VirtualProtect(ApiAddress, 5, vOldProtect, @vOldProtect);
end;
TrustPatched := True;
end
else
TrustPatched := False;
Result := TrustPatched;
end;
procedure PatchRadioStudio;
var
HModule: THandle;
ModuleCrc, vOldProtect: DWORD;
ModName: array [0 .. MAX_PATH] of WideChar;
pModName: PWideChar;
AdrValueMod: PDWORD;
begin
HModule := GetModuleHandleW(nil);
GetModuleFileNameW(HModule, ModName, Length(ModName));
pModName := @ModName[0];
while pModName^ <> #0 do
begin
Inc(pModName);
end;
while pModName^ <> #$5C do
begin
Dec(pModName);
end;
Inc(pModName);
if lstrcmpiW(pModName, 'bds.exe') = 0 then
begin
ModuleCrc := CalcFileCRC(ModName);
if ModuleCrc = $1EB2EB86 then // CRC32 Value of bds.exe
begin
AdrValueCmp := HModule + $1E7D5; //the function call return address
AdrValueMod := ptr(HModule + $26886C); // find the import data
// &rtl250.System::FinalizeArray
FinalizeArrayAdr := AdrValueMod^; // get the real FinalizeArray api address
VirtualProtect(AdrValueMod, 4, PAGE_EXECUTE_READWRITE, @vOldProtect);
AdrValueMod^ := DWORD(@AsmCode); // set a hook of the api
VirtualProtect(AdrValueMod, 4, vOldProtect, @vOldProtect);
end;
end;
end;
exports
SHGetFolderPathW,
SHGetFolderPathA;
procedure LoadSysVersion;
begin
GetMem(SysPath, MAX_PATH);
GetSystemDirectory(SysPath, MAX_PATH);
SysPath := lstrcat(SysPath, '\shfolder.dll');
ModHandle := LoadLibrary(SysPath);
if ModHandle > 0 then
begin
pSHGetFolderPathA := GetProcAddress(ModHandle, 'SHGetFolderPathA');
pSHGetFolderPathW := GetProcAddress(ModHandle, 'SHGetFolderPathW');
PatchRadioStudio;
end;
end;
procedure DllMainEntry(dwResaon: DWORD);
begin
case dwResaon of
DLL_PROCESS_DETACH:
;
DLL_PROCESS_ATTACH:
LoadSysVersion;
DLL_THREAD_ATTACH:
if not TrustPatched then
PatchTrustVerify;
DLL_THREAD_DETACH:
if not TrustPatched then
PatchTrustVerify;
end;
end;
begin
DllProc := @DllMainEntry;
DllMainEntry(DLL_PROCESS_ATTACH);
end.
**"***"**
placeholder for the source detail.
Tools:
x64dbg
How to find AdrValueMod $26886C
Use x32dbg to load bds.exe, Press F9 to start it, the debugger will stop in some exceptions
repeat press F9, about 3 or 4 times,
switch to he Symbols panel, chose the bds.exe module and double click,
at $401398 you can find the jmp code..
50063E24 is the address of rtl250.System.FinalizeArray
our patch will change the value at 66886c to redirect the function.
66886c - 400000 = 26886C 400000 is the bds handle
thus when bds call FinalizeArray, it will goto our function first.
0x0041E7D0 is the address which bds call the FinalizeArray after the license verification.
How to find it ? it's a littile complete, maybe someone can explain it. I can't explain it well. lot's of code are in vm.
0041E7B4 <bds | 8D 45 B8 | lea eax,dword ptr ss:[ebp-48] |
0041E7B7 | 8B 15 64 96 41 00 | mov edx,dword ptr ds:[419664] |
0041E7BD | E8 CE 2B FE FF | call <bds.System@@FinalizeRecord$qqrpvt1> |
0041E7C2 | 8D 45 F4 | lea eax,dword ptr ss:[ebp-C] | [ebp-C]:&"ntrol@GetAction$qqrv"
0041E7C5 | 8B 15 F8 55 41 00 | mov edx,dword ptr ds:[4155F8] |
0041E7CB | B9 03 00 00 00 | mov ecx,3 |
0041E7D0 | E8 C3 2B FE FF | call <bds.System@@FinalizeArray$qqrpvt1ui> |
0041E7D5 | C3 | ret |
[/hide]