steve10120 Posted December 2, 2008 Posted December 2, 2008 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;varhMod: 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.
Nacho_dj Posted December 2, 2008 Posted December 2, 2008 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 regardsNacho_dj
steve10120 Posted December 2, 2008 Author Posted December 2, 2008 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?
Nacho_dj Posted December 2, 2008 Posted December 2, 2008 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
steve10120 Posted December 2, 2008 Author Posted December 2, 2008 Excellent thanks. Think I've fixed that now. program Delphi;uses Windows, SysUtils;{$R *.res}type TByteArray = array of Byte;varhMod: 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
Nieylana Posted December 3, 2008 Posted December 3, 2008 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 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
steve10120 Posted December 4, 2008 Author Posted December 4, 2008 Thanks for the reply. Fixed the SizeOfRawData and PointerToRawData values. But there is still a problem, PE Explorer says the SizeOfRawData on the last section is bigger than the file.http://img185.imageshack.us/img185/2472/picsh4.jpg65536 is the SizeOfImage value, and also the size of my LordPE dump.
Nacho_dj Posted December 4, 2008 Posted December 4, 2008 (edited) This parameter of PE header must be fixed to the following value:SizeOfImage = VirtualAddress of last section + VirtualSize of last sectionAnd this coincidence must be true:SizeOfFileDumped = RawAddress of last section + RawSize of last sectionSizeOfFileDumped must be divisible by FileAlignment. If no, padd as many zeroes as needed to reach this condition.CheersNacho_dj Edited December 4, 2008 by Nacho_dj
steve10120 Posted December 5, 2008 Author Posted December 5, 2008 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;varhOpen: 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;varhMod: 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?
Nacho_dj Posted December 5, 2008 Posted December 5, 2008 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
steve10120 Posted December 13, 2008 Author Posted December 13, 2008 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;varhOpen: 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.
0xFF Posted December 26, 2008 Posted December 26, 2008 lol, all this posts and no one cared about this line ?if hFile <> INVALID_HANDLE_VALUE thenYou 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.
pseudonym Posted December 26, 2008 Posted December 26, 2008 lol, all this posts and no one cared about this line ?if hFile <> INVALID_HANDLE_VALUE thenYou 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.
Nacho_dj Posted December 26, 2008 Posted December 26, 2008 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 regardsNacho_dj
0xFF Posted December 27, 2008 Posted December 27, 2008 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 regardsNacho_djThen use Try/Except condition.
Killboy Posted December 27, 2008 Posted December 27, 2008 No worries, should have mentioned that part ^^ I'll just delete the last few posts lol It's Christmas, no need to fight
steve10120 Posted December 29, 2008 Author Posted December 29, 2008 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.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now