waliedassar Posted September 24, 2012 Posted September 24, 2012 (edited) It seems that Scylla has a bug when trying to fix a dump with an unusual SizeOfOptionalHeader value.For example (with Scylla 0.6):If the PE has the "SizeOfOptionalHeader" field set to 0x148 and the "NumberOfRvaAndSizes" field set to 0x1D, Scylla sets the "NumberOfRvaAndSizes" to 0x10 but leave the "SizeOfOptionalHeader" field as it is and this is why the fixed dumped is rejected by PE loader.Scylla 0.7 beta:If the PE has the "SizeOfOptionalHeader" field set to 0x148 and the "NumberOfRvaAndSizes" field set to 0x1D, Scylla moves the section table just after the 16th data directory without modifying the "SizeOfOptionalHeader" field.It should do the reverse, set the "SizeOfOptionalHeader" field to 0xE0 and leave "NumberOfRvaAndSizes" untouched.Or it should just follow this for 32-bit PE's:SizeOfOptionalHeader = (NumberOfRvaAndSizes*0x8)+0x60 Edited September 24, 2012 by waliedassar
deepzero Posted September 24, 2012 Posted September 24, 2012 NumberOfRvaAndSizes is hardcoded to 0x10.Havent checked the rest yet.
Aguila Posted September 24, 2012 Posted September 24, 2012 I thought NumberOfRvaAndSizes must always be 0x10? Is a value more or less than 0x10 allowed? Because there are only 16: http://msdn.microsoft.com/en-us/library/windows/desktop/ms680305(v=vs.85).aspx
deepzero Posted September 24, 2012 Posted September 24, 2012 (edited) yes, that is correct.SizeOfOptionalHeader is just the size of the optional header, which includes an array of 16 DataDirectories, consisting of 1 RVA + int32 for size (==> 2*4=8 bytes on x86 and x64).Above calculation is correct for x86 PE32 files:SizeOfOptionalHeader = (NumberOfRvaAndSizes*0x8)+0x60=>SizeOfOptionalHeader = 0x10*0x08+0x60 = 0xE0.Hence, SizeOfOptionalHeader should always be 0xE0 for x86 PE32 files.in the windows header files:#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16and in the IMAGE_OPTIONAL_HEADER definition: IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];(used both for the x64 and the x86 definitions)THe x64 IMAGE_OPTIONAL_HEADE has some fields expanded to 64 bits, so its overall size is 0xF0.edit:going back to the original problem:If the PE has the "SizeOfOptionalHeader" field set to 0x148 and the "NumberOfRvaAndSizes" field set to 0x1D, Scylla moves the section table just after the 16th data directory without modifying the "SizeOfOptionalHeader" field.It should do the reverse, set the "SizeOfOptionalHeader" field to 0xE0 and leave "NumberOfRvaAndSizes" untouched.Imo, i shouldnt touch the section table, but change the two fields to 0xE0 and 0x10, respectively. Edited September 24, 2012 by deepzero
Aguila Posted September 24, 2012 Posted September 24, 2012 (edited) I think this is the only valid solution:NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);I like constants more than some weird calculations.Thanks for your help. Edited September 24, 2012 by Aguila
waliedassar Posted September 24, 2012 Author Posted September 24, 2012 (edited) I think this is the only valid solution: NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER); I like constants more than some weird calculations. Thanks for your help. No, sir. Let me save you some time. The "SizeOfOptionalHeader" field is used by the PE loader to locate the section table. So, changing the "NumberOfRvaAndSizes" field to 0x10 and leaving the "SizeOfOptionalHeader" field unchanged causes the PE loader to get a different section table . On the other side, the "NumberOfRvaAndSizes" field is used by the PE loader e.g. the ntdll "RtlImageDirectoryEntryToData" function when checking/parsing a specific data directory. If the requested data directory index < NumberOfRvaAndSizes, then it is okay and continue checking/parsing. else, return an error and don't parse that data directory. Imagine a PE with the "NumberOfRvaAndSizes" field set to 0xA and data directories number 0xA, 0xB, 0xC, 0xD, 0xE, and 0xF are filled with garbage values. 1) If you only set the "NumberOfRvaAndSizes" field to 0x10, then PE loader gets a wrong section table. 2) If you set the "SizeOfOptionalHeader" and "NumberOfRvaAndSizes" fields to 0xE0 and 0x10, then any attempt by the PE loader to get IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 0xA will result in the garbage values being read and the PE will be rejected. The solution should be: 1) Leaving "NumberOfRvaAndSizes" field unchanged and setting the "SizeOfOptionalHeader" field to 0xE0. 2) Setting the "NumberOfRvaAndSizes" field to 0x10, the "SizeOfOptionalHeader" field to 0xE0, and filling the space in between with zeros. I remember that OllyDbg v1.10 has some issue with the "SizeOfOptionalHeader" and "NumberOfRvaAndSizes" fields. This is why i used this weird calculation to bypass that issue. Edited September 24, 2012 by waliedassar
Aguila Posted September 24, 2012 Posted September 24, 2012 thank you waliedassar.I think zeroing is the best solution. https://github.com/NtQuery/Scylla/blob/master/Scylla/PeParser.cpp -> line 920
deepzero Posted September 24, 2012 Posted September 24, 2012 I disagree. field unchanged causes the PE loader to get a different section table . no. the NumberOfRvaAndSizes isnt actually used here, you can set it to -1, too. Only SizeOfOptHeader is used to get the section header table. will result in the garbage values being read and the PE will be rejected. precisely so, it`s an invalid PE file. As i said above, the optional header contains a field of hardcoded 16 DataDirectories. If you dont use one of these directories, it should be set to zero. Else it is seen as "registered". 1) Leaving "NumberOfRvaAndSizes" field unchanged and setting the "SizeOfOptionalHeader" field to 0xE0. No. I was wrong when i said the SizeOfOptHeader is hardcoded. It`s not, although it should be in a "perfect" PE file. SizeOfOPtionalHeader is NOT sizeof(SizeOfOPtionalHeader)! Rather, it is the offset of the section header table relative to the PE header. As such, it has to include potentially additional space that someone may have inserted additionally to the actual OptionalHeader. (althouhg that someone really shouldnt have done that....) 2) Setting the "NumberOfRvaAndSizes" field to 0x10, the "SizeOfOptionalHeader" field to 0xE0, and filling the space in between with zeros. no. in that case, the space should be physically removed from the file to get the offsets right. The non-used DataDirecotires should be zero already. Lastly, although the NumberOfRvaAndSizes is hardocded to 16, the pe loader of WinXpSp3 uses the actual value from the pe file to check whether a directory access is in-range or not. So one could use >=0x10...although the definitions guarantee that there should be 16 directories. here`s the actual data from the winapis: check on OptHeaderSizeOf:7C910300 81FA 00000010 CMP EDX,10000000 Check on NumberOfRvaAndSizes of pe file: 7C91039B 3B48 74 CMP ECX,DWORD PTR DS:[EAX+74] a data entry is valid if non-zero: 7C9103A4 8B54C8 78 MOV EDX,DWORD PTR DS:[EAX+ECX*8+78] 7C9103A8 85D2 TEST EDX,EDX 7C9103AA 0F84 EC030000 JE 7C91079C
waliedassar Posted September 24, 2012 Author Posted September 24, 2012 I disagree. no. the NumberOfRvaAndSizes isnt actually used here, you can set it to -1, too. Only SizeOfOptHeader is used to get the section header table. You misunderstood it. Rephrasing it again. If you go for placing the section table after the sixteenth data directory, setting the "NumberOfRvaAndSizes" field to 0x10, and leaving the "SizeOfOptionalHeader" field unchanged, then you get a different section table. (This happens with Scylla v0.6).
waliedassar Posted September 24, 2012 Author Posted September 24, 2012 (edited) no.in that case, the space should be physically removed from the file to get the offsets right.The non-used DataDirecotires should be zero already.With the "Space in between", i mean space starting from the first unused data directory to just before the first section header.Also, i forgot the "OR"The solution should be:1) Leaving "NumberOfRvaAndSizes" field unchanged and setting the "SizeOfOptionalHeader" field to 0xE0. OR2) Setting the "NumberOfRvaAndSizes" field to 0x10, the "SizeOfOptionalHeader" field to 0xE0, and filling the space in between with zeros. Edited September 24, 2012 by waliedassar
deepzero Posted September 24, 2012 Posted September 24, 2012 (edited) If you go for placing the section table after the sixteenth data directory, setting the "NumberOfRvaAndSizes" field to 0x10, and leaving the "SizeOfOptionalHeader" field unchanged, then you get a different section table. (This happens with Scylla v0.6). true. you cant move the section table around freely. But the NumberOfRvaAndSIzes has nothing to do with that (s.a.), just the SizeOfOptionalHeader. In your first post, both v0.6 and v0.7 should produce invalid dumps, due to an invalid start of the section table. You are right, if you delete/overwrite data that was placed right after the optional header (ie "after the 16th DD") then you can use sizeof(ImageOPtionalHeader). But this might have unwanted side effects. (in theory, you could e.g. place a DD there). As for 1), i would argue that NumberOfRvaAndSIzes is fixed to 16 for Pe32 and PE32+, any other value indicates wired custom modifications or a new derivative of the PE file format. (although windows internally uses the actual value from the header for some reason, s.a.) As for 2), i agree (although unused directories should be zeroed, i suppose it s good for rebuilding purposes). BUT, you have to take into account potential space inserted additionally to the ImageOptionalHeader. Scylla does no do that right now. d. Edited September 24, 2012 by deepzero
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