Jump to content
Tuts 4 You

[Help] Process Dumper - Delphi


steve10120

Recommended Posts

Hi, I'm trying to make a dumper, but run into some problems.

program Delphi;uses
Windows, SysUtils;{$R *.res}type
TByteArray = array of Byte;var
hMod: THandle;
hOpen: THandle;
hFile: THandle;
IDH: TImageDosHeader;
INH: TImageNtHeaders;
ISH: TImageSectionHeader;
dRead: DWORD;
dWritten: DWORD;
dSize: DWORD;
bBuff: TByteArray;
i: integer;
begin
hMod := GetModuleHandle(nil);
hOpen := GetCurrentProcess;
if ReadProcessMemory(hOpen, Ptr(hMod), @IDH, SizeOf(IDH), dRead) then
begin
hFile := CreateFile(PChar('dumped.exe'), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
SetLength(bBuff, SizeOf(IDH));
ZeroMemory(bBuff, SizeOf(IDH));
ReadProcessMemory(hOpen, Ptr(hMod), @bBuff[0], SizeOf(IDH), dRead);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil);
if ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew), @INH, SizeOf(INH), dRead) then
begin
SetLength(bBuff, SizeOf(INH));
ZeroMemory(bBuff, SizeOf(INH));
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew), @bBuff[0], SizeOf(INH), dRead);
SetFilePointer(hFile, 64, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], 248, dWritten, nil);
for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((i) * 40)), @ISH, SizeOf(ISH), dRead);
dSize := GetFileSize(hFile, nil);
SetFilePointer(hFile, dSize, nil, FILE_BEGIN);
WriteFile(hFile, ISH, SizeOf(ISH), dWritten, nil);
end;
for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((i) * 40)), @ISH, SizeOf(ISH), dRead);
SetLength(bBuff, ISH.Misc.VirtualSize);
ZeroMemory(bBuff, ISH.Misc.VirtualSize);
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((INH.FileHeader.NumberOfSections - 1) * 40) + ISH.VirtualAddress), @bBuff[0], ISH.Misc.VirtualSize, dRead);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil); // MessageBox(0, PChar(IntToHex(ISH.Misc.VirtualSize, 8)), nil, 0);
end;
CloseHandle(hFile);
end;
end;
end;
end.

I'm obviously doing something wrong somewhere, can't work out where.

ps: pls excuse the mess, I've changed things around while trying to fix it. And I will add the dos stub.

Thanks.

Link to comment

So, what is your tool doing then? Does it dump anything?

As a little tip, you could use after each ReadProcessMemory the value of dRead variable to check if the number of bytes read matches with length of buffer receiving those bytes...

There is a good debugger within the Delphi environment, it would be a good idea using it and go tracing with F8 to check variable values.

Best regards

Nacho_dj

Link to comment

Thanks for the reply.

Yes I have done that, all values are correct, if you run the code you'll see it runs fine, dumps IDH, INH, and all ISH's, my problem is the sections themselves I think, or not?

Link to comment

You have missed in your dump the bytes between the end of ImageDosHeader and the start of ImageNtHeaders.

Again, it is happening the same with bytes between the end of the last element of ImageSectionHeader and the address of the content of the first section.

To check this you could just dump with any tool to dump and compare this dump with the one made by your code.

So, it is easy to fix. :)

Best regards

Nacho_dj

Link to comment

Excellent thanks. Think I've fixed that now.

program Delphi;uses
Windows, SysUtils;{$R *.res}type
TByteArray = array of Byte;var
hMod: THandle;
hOpen: THandle;
hFile: THandle;
IDH: TImageDosHeader;
INH: TImageNtHeaders;
ISH: TImageSectionHeader;
dRead: DWORD;
dWritten: DWORD;
dSize: DWORD;
bBuff: TByteArray;
i: integer;
SectionStart: integer;
EndOfHeaders: integer;
begin
hMod := GetModuleHandle(nil);
hOpen := GetCurrentProcess;
if ReadProcessMemory(hOpen, Ptr(hMod), @IDH, SizeOf(IDH), dRead) then
begin
hFile := CreateFile(PChar('dumped.exe'), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
SetLength(bBuff, SizeOf(IDH));
ZeroMemory(bBuff, SizeOf(IDH));
ReadProcessMemory(hOpen, Ptr(hMod), @bBuff[0], SizeOf(IDH), dRead);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil); SetLength(bBuff, IDH._lfanew - 64);
ZeroMemory(bBuff, IDH._lfanew - 64);
ReadProcessMemory(hOpen, Ptr(hMod + 64), @bBuff[0], IDH._lfanew - 64, dRead);
SetFilePointer(hFile, 64, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], IDH._lfanew - 64, dWritten, nil); if ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew), @INH, SizeOf(INH), dRead) then
begin
SetLength(bBuff, SizeOf(INH));
ZeroMemory(bBuff, SizeOf(INH));
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew), @bBuff[0], SizeOf(INH), dRead);
SetFilePointer(hFile, IDH._lfanew, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], 248, dWritten, nil); for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((i) * 40)), @ISH, SizeOf(ISH), dRead);
dSize := GetFileSize(hFile, nil);
SetFilePointer(hFile, dSize, nil, FILE_BEGIN);
WriteFile(hFile, ISH, SizeOf(ISH), dWritten, nil);
end;
////
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((0) * 40)), @ISH, SizeOf(ISH), dRead);
//MessageBox(0, PChar(IntToHex(ISH.VirtualAddress, 8)), nil, 0);
EndOfHeaders := IDH._lfanew + 248 + ((INH.FileHeader.NumberOfSections - 1) * 40);
SectionStart := EndOfHeaders + ISH.VirtualAddress;
SetLength(bBuff, SectionStart - EndOfHeaders);
ZeroMemory(bBuff, SectionStart - EndOfHeaders);
ReadProcessMemory(hOpen, Ptr(hMod + EndOfHeaders), @bBuff[0], SectionStart - EndOfHeaders, dRead); dSize := GetFileSize(hFile, nil);
SetFilePointer(hFile, dSize, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil);
//MessageBox(0, PChar(IntToStr(IDH._lfanew + ((INH.FileHeader.NumberOfSections - 1) * 40))), nil, 0);
/////
for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((i) * 40)), @ISH, SizeOf(ISH), dRead);
SetLength(bBuff, ISH.Misc.VirtualSize);
ZeroMemory(bBuff, ISH.Misc.VirtualSize);
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((INH.FileHeader.NumberOfSections - 1) * 40) + ISH.VirtualAddress), @bBuff[0], ISH.Misc.VirtualSize, dRead);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil); //MessageBox(0, PChar(IntToHex(ISH.Misc.VirtualSize, 8)), nil, 0);
end;
CloseHandle(hFile);
end;
end;
end;
end.

Although there is still a problem, I don't think its grabbing the sections properly, there is more data than there should be and the EP code is wrong. Also there is a 17kb size difference to a LordPE dump :wacko:

Link to comment
Although there is still a problem, I don't think its grabbing the sections properly, there is more data than there should be and the EP code is wrong. Also there is a 17kb size difference to a LordPE dump :wacko:

Make sure to run a rountine on the dumped file that adjusts the

* SizeOfRawData to match the VirtualSize

* PointerToRawData to match the VirtualAddress

for each sections.

The Size difference to LordPE could be because LordPE may realign the sections depending on your settings.

Here is my DumpFix routine used in my WTLoader program (it's in VB6 but i hope it helps anyway)

Private Function FixDump(Filename As String)
OutputText "Performing DumpFix on file"
Dim DWORD(1 To 4) As Byte
Dim WORD(1 To 2) As Byte Open Filename For Binary Access Read As #1
Get #1, Val("&h3D"), DWORD
Close
For x = 4 To 1 Step -1
y = y & IIf(Len(Hex(DWORD(x))) > 1, Hex(DWORD(x)), "0" & Hex(DWORD(x)))
Next x
peHeader = Val("&h" & y)
Open Filename For Binary Access Read As #1
Get #1, peHeader + 7, WORD
Close
y = ""
For x = 2 To 1 Step -1
y = y & IIf(Len(Hex(WORD(x))) > 1, Hex(WORD(x)), "0" & Hex(WORD(x)))
Next x
NumSections = Val("&h" & y) FirstSection = peHeader + 248
currentsection = FirstSection
Dim sectionName As String
For x = 1 To NumSections
Open Filename For Binary Access Read Write Lock Read Write As #1
sectionName = Space(8)
Get #1, currentsection + 1, sectionName
sectionName = Left(sectionName, InStr(1, sectionName, Chr(0)) - 1)
OutputText "Adjusting " & sectionName & " section"
Get #1, currentsection + 8, DWORD()
Put #1, currentsection + 16, DWORD()
Get #1, currentsection + 12, DWORD()
Put #1, currentsection + 20, DWORD()
Close
currentsection = currentsection + 40
Next x
OutputText "DumpFix complete"
End Function
Link to comment

This parameter of PE header must be fixed to the following value:

SizeOfImage = VirtualAddress of last section + VirtualSize of last section

And this coincidence must be true:

SizeOfFileDumped = RawAddress of last section + RawSize of last section

SizeOfFileDumped must be divisible by FileAlignment. If no, padd as many zeroes as needed to reach this condition.

Cheers

Nacho_dj

Edited by Nacho_dj
Link to comment

Thanks again, looking much better now, still not working 100% tho.

program Delphi;uses
Windows, SysUtils, TlHelp32, PsAPI;{$R *.res}type
TByteArray = array of Byte;function GetBaseAddress(PID:DWORD):DWORD;
var
hOpen: THandle;
hMod: THandle;
MODINFO: MODULEINFO;
null: DWORD;
begin
hOpen := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, PID);
if hOpen <> INVALID_HANDLE_VALUE then
begin
EnumProcessModules(hOpen, @hMod, SizeOf(hMod), null);
GetModuleInformation(hOpen, hMod, @MODINFO, SizeOf(MODINFO));
Result := Cardinal(MODINFO.lpBaseOfDll);
CloseHandle(hOpen);
end;
end;var
hMod: THandle;
hOpen: THandle;
hFile: THandle;
IDH: TImageDosHeader;
INH: TImageNtHeaders;
ISH: TImageSectionHeader;
dRead: DWORD;
dWritten: DWORD;
dSize: DWORD;
bBuff: TByteArray;
i: integer;
iSpace: integer;
SectionStart: integer;
EndOfHeaders: integer;
begin
hMod := GetBaseAddress(2616);
hOpen := OpenProcess(PROCESS_VM_READ, FALSE, 2616);
if ReadProcessMemory(hOpen, Ptr(hMod), @IDH, SizeOf(IDH), dRead) then
begin
hFile := CreateFile(PChar('dumped.exe'), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
SetLength(bBuff, SizeOf(IDH));
ZeroMemory(bBuff, SizeOf(IDH));
ReadProcessMemory(hOpen, Ptr(hMod), @bBuff[0], SizeOf(IDH), dRead);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil); SetLength(bBuff, IDH._lfanew - 64);
ZeroMemory(bBuff, IDH._lfanew - 64);
ReadProcessMemory(hOpen, Ptr(hMod + 64), @bBuff[0], IDH._lfanew - 64, dRead);
SetFilePointer(hFile, 64, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], IDH._lfanew - 64, dWritten, nil); if ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew), @INH, SizeOf(INH), dRead) then
begin
SetLength(bBuff, SizeOf(INH));
ZeroMemory(bBuff, SizeOf(INH));
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew), @bBuff[0], SizeOf(INH), dRead);
SetFilePointer(hFile, IDH._lfanew, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], 248, dWritten, nil); for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((i) * 40)), @ISH, SizeOf(ISH), dRead);
dSize := GetFileSize(hFile, nil);
ISH.SizeOfRawData := ISH.Misc.VirtualSize;
ISH.PointerToRawData := ISH.VirtualAddress;
if i = INH.FileHeader.NumberOfSections - 1 then
begin
iSpace := INH.OptionalHeader.SizeOfImage - (ISH.PointerToRawData + ISH.SizeOfRawData);
ISH.SizeOfRawData := ISH.SizeOfRawData + iSpace;
end;
SetFilePointer(hFile, dSize, nil, FILE_BEGIN);
WriteFile(hFile, ISH, SizeOf(ISH), dWritten, nil);
end;
////
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((0) * 40)), @ISH, SizeOf(ISH), dRead);
//MessageBox(0, PChar(IntToStr(IDH._lfanew + 248 + ((INH.FileHeader.NumberOfSections) * 40))), nil, 0);
EndOfHeaders := IDH._lfanew + 248 + ((INH.FileHeader.NumberOfSections) * 40);
SectionStart := EndOfHeaders + ISH.VirtualAddress;
SetLength(bBuff, SectionStart - EndOfHeaders);
ZeroMemory(bBuff, SectionStart - EndOfHeaders);
ReadProcessMemory(hOpen, Ptr(hMod + EndOfHeaders), @bBuff[0], SectionStart - EndOfHeaders, dRead); //MessageBox(0, PChar(IntToStr(SectionStart - EndOfHeaders)), nil, 0); dSize := GetFileSize(hFile, nil);
SetFilePointer(hFile, dSize, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil);
//MessageBox(0, PChar(IntToStr(IDH._lfanew + ((INH.FileHeader.NumberOfSections - 1) * 40))), nil, 0);
/////
for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + ((i) * 40)), @ISH, SizeOf(ISH), dRead);
SetLength(bBuff, ISH.Misc.VirtualSize);
ZeroMemory(bBuff, ISH.Misc.VirtualSize);
ReadProcessMemory(hOpen, Ptr(hMod + IDH._lfanew + 248 + (INH.FileHeader.NumberOfSections * 40) + ISH.VirtualAddress), @bBuff[0], ISH.Misc.VirtualSize, dRead);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil);
end;
dSize := GetFileSize(hFile, nil);
if dSize < INH.OptionalHeader.SizeOfImage then
begin
SetLength(bBuff, INH.OptionalHeader.SizeOfImage - dSize);
ZeroMemory(bBuff, INH.OptionalHeader.SizeOfImage - dSize);
SetFilePointer(hFile, dSize, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], Length(bBuff), dWritten, nil);
end;
CloseHandle(hFile);
end;
end;
end;
end.

I've compared mine and LordPE's dump, the only difference in the headers was the SizeOfHeaders value. My dump was 400, LordPE's was 1000. Is there an sum I need todo to get SizeOfHeaders new value?

Link to comment
I've compared mine and LordPE's dump, the only difference in the headers was the SizeOfHeaders value. My dump was 400, LordPE's was 1000. Is there an sum I need todo to get SizeOfHeaders new value?
Well, Delphi executables normally have got that value as 400. And because of this, they have the first section raw address equal to 400, that is, from the address where there is no more pe header.

If your dump has got the first section raw address to 1000, you should adjust SizeOfHeaders to 1000 also...

Good work, now you can dump any executable. :)

Kind regards

Nacho_dj

Link to comment

Figured another way todo it, not dumping correctly on all, but thought I'd share anyway. Thanks to all that helped in this thread btw. :)

program Dumper;uses
Windows, PsAPI;type
TByteArray = array of Byte;var
hOpen: THandle;
hFile: THandle;
bBuff: TByteArray;
dSize: DWORD;
dBaseAddr: DWORD;
dRead: DWORD;
dWritten: DWORD;{$R *.res}function GetInfo(PID:DWORD; var dBaseAddr:DWORD; var dSize:DWORD):Boolean;
var
hOpen: THandle;
hMod: THandle;
MODINFO: MODULEINFO;
null: DWORD;
begin
Result := FALSE;
hOpen := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, PID);
if hOpen <> INVALID_HANDLE_VALUE then
begin
EnumProcessModules(hOpen, @hMod, SizeOf(hMod), null);
if GetModuleInformation(hOpen, hMod, @MODINFO, SizeOf(MODINFO)) then
begin
dSize := Cardinal(MODINFO.SizeOfImage);
dBaseAddr := Cardinal(MODINFO.lpBaseOfDll);
Result := TRUE;
end;
CloseHandle(hOpen);
end;
end;begin
if GetInfo(292, dBaseAddr, dSize) then
begin
hOpen := OpenProcess(PROCESS_VM_READ, FALSE, 292);
if hOpen <> INVALID_HANDLE_VALUE then
begin
SetLength(bBuff, dSize);
ReadProcessMemory(hOpen, Ptr(dBaseAddr), @bBuff[0], dSize, dRead);
CloseHandle(hOpen); hFile := CreateFile(PChar('dump.exe'), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
WriteFile(hFile, bBuff[0], dSize, dWritten, nil);
CloseHandle(hFile);
end;
end;
end;
end.
Link to comment
  • 2 weeks later...

lol, all this posts and no one cared about this line ?

if hFile <> INVALID_HANDLE_VALUE then

You don't need to check for invalid handle because you're always creating the file (overwriting if exists), this condition should be used if you're using OPEN_EXISTING in my opinion.

Link to comment
lol, all this posts and no one cared about this line ?

if hFile <> INVALID_HANDLE_VALUE then

You don't need to check for invalid handle because you're always creating the file (overwriting if exists), this condition should be used if you're using OPEN_EXISTING in my opinion.

Better coding practice to check it imo. What's going to happen if (however unlikely) the file could not be created and he doesn't?. Personally I would include seh and check the return, its just lazy not to.

Link to comment

If you don't use that condition you are risking to get an exception in the case of the file having been opened in write mode or if it is in execution...

Best regards

Nacho_dj

Link to comment
If you don't use that condition you are risking to get an exception in the case of the file having been opened in write mode or if it is in execution...

Best regards

Nacho_dj

Then use Try/Except condition.

Link to comment

Nah sorry I will always use that condition, Try/Except is good to handle unexpected errors, but not for a whole function especially when you need to debug it constantly like I did.

And oh yeah, Merry Christmas. :lol:

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...