Flag: Tornado!
Hurricane!
|
|
Topic created on: December 1, 2008 19:31 CST by nezumi .
Hi all!
I found a bug in PE-loader allows to hide code/data inside EXE/DLL/SYS files, so IDA-Pro shows nothing. ok, this is not a bug, this is a documented feature, but PE-specification does not explain it well, so most of disassembler-writers missed the point.
to demonstrate this I created a simple proof-of-concept. plz, check it out.
try to reverse/debug this stuff. it bypasses IDA-Pro, HIEW, OllyDbg, Soft-Ice, Syser, DUMPBIN, etc. proc. dumpers don't work too.
I tested my crack-me under W2K, S2K3, XP, Vista and it works fine.
(if you have Vista under your hands, plz, run it and tell me if it works or not)
P.S. explanations will follow...
SizeOfRawdata is 1 for data & text sections. Doing some guesswork, loader uses defaults to load such executable where as disasms/debuggers will not. Changing SizeOfRawData for above sections fixes the executable. At least for IDA. The TLSCallBack is pretty clear in IDA after this fixup but it does not work for some other tiny exes where I tried to modify the SizeOfRawData to 1.
|
ulldevice
> SizeOfRawdata is 1 for data & text sections.
> Doing some guesswork, loader uses defaults
> to load such executable where as disasms/debuggers will not.
not exactly. the point is:
OS loads ALIGN_UP(SizeOfRawdata, FileAlignment) bytes, where IDA-Pro, HIEW, DUMPBIN - only SizeOfRawdata, thus if ALIGN_UP(SizeOfRawdata, FileAlignment) > SizeOfRawdata - IDA-Pro misses "ALIGN_UP(SizeOfRawdata, FileAlignment) - SizeOfRawdata" bytes, so it's possible to hide code/data in any section.
see another example. this program calls two message boxes with two different strings, but IDA-Pro shows only one! malware might use it to hide malicious code, so always use IDA-Pro 5.3 and manual load.
> Changing SizeOfRawData for above sections fixes the executable.
yes, it does.
> The TLSCallBack is pretty clear in IDA
there is a couple anti-debugger tricks:
1) TLSCallback checks if *EntryPoint == CCh (INT 03) and executes infinitive loop to abuse OllyDbg and some other debuggers. however, we can pause the debugger (F12), set _hardware_ breakpoint at TLS callback and restart the process (CTRL-F2) - enjoy!
2) I use MOV EAX, EAX/MOV EAX, [EAX] instead of RETN and it works great. no custom SEH handlers are installed, but Windows suppresses exceptions raised inside TLS callbacks;
3) since TLS Callback is called more than once and I don't want to see the same message box over and over, I use IsDebuggerPresent PEB field as a counter;
> it does not work for some other tiny exes
> where I tried to modify the SizeOfRawData to 1.
it should work for any exe/dll/sys regardless of its size, if you set SizeOfRawData to 1 - FileAlignment bytes will be loaded.
|
The SizeOfRawData technique is known and in use already by some packers. Also, if you use Atli Gudmindsson's pe_sections.idc, then all data will be shown.
nulldevice is correct that the technique does not work for small files - if you use SectionAlignment < 4kb, then it will fail.
|
PeterFerrie:
yeah, it's a known trick. I'm developing an interactive unpacker and testing a lot of different packers/protectors. the unpacker has an independent engine and interfaces to IDA-Pro and OllyDbg.
the problem was - a few malware samples fail to unpack with IDA-Pro, coz IDA-Pro loads only SizeOfRawData bytes, while OllyDbg uses System Loader and loads them all.
Manual Loading solves this problem and IDA-Pro 5.3 works well even without custom scripts.
I'm not the first who has found this, I just want to point out: dealing with malware always use manual load or check section size to be sure it has no hidden code/data. hope this advice will be useful. um, maybe not. ok, never mind.
|
just something to share:
http://opcode0x90.wordpress.com/2007/04/22/windows-loader-does-it-differently/
|
Zarul, thanks for sharing!
# Windows loader does it differently
> Loader will map 0x1D33 bytes of section data
> into memory and ignores the SizeOfRawData.
not exactly, but close. according to MS PE specification:
# SizeOfRawData
...Because the SizeOfRawData field is rounded
but the VirtualSize field is not, it is possible for
SizeOfRawData to be greater than VirtualSize
System Loader works like this:
if (SizeOfRawData > VirtualSize)
LOAD(SizeOfRawData);
else
LOAD(VirtualSize);
of course, the real life is more complicated and like PeterFerrie mentioned above, it's possible to create a file with SectionAlignment < 4kb.
if SectionAlignment < 4kb, File Alignment must be the same as Section Alignment and can take any value equal to a power of two (for example, 20h).
the virtual and physical addresses of all sections must match, meaning that the memory image must correspond to disk image. there are, however, exceptions to any rule, and the virtual size of sections can be smaller than their physical size. this difference cannot be greater than Section Alignment - 1 bytes though
btw,
I just checked the example described in the link above.
* IDA 4.7 - crashes, IDA 5.2+ works well;
* OllyDbg 1.10 displays the warning, but works well (no crash);
P.S. the crack-me has been updated, Vista incompatibly is fixed now (Vista doesn't allow us to call USER32!MessageBox from TLS-callback, MS warned us not to do this, but it worked before)
|
The link above was really meant to show that this stuff has already been around for quite some times now... :)
|
hi,
I've got another question concerning PE loading.
The file comes with section alignment as well as file alignment of 0x1000.
Hence, I think, that the PointerToRawData and the VirtualAddress of each section has to be aligned to this value (0x1000).
Unfortunately, I found counter samples.
They are loaded by the PE loader and the PointerToRawData is rounded down to fit to the next alignment.
In a sample having the first section unaligned the Olly puts the sections together in one section.
I also have a sample with an unaligned 3rd section. In this case the data from this PointerToRawData is loaded to the VirutalAddress. But in this case the PointerToRawData has not been aligned before.
Does someone of you know under which circumstances the sections are allowed to be unaligned iff the Sectionalignment is not below 4KB?
thank you for your help.
|
windows loader uses mask = ~(SectAlign > 0x200 ? 0x1ff : SectAlign-1) with section->PointertoRawData when loading.
it is not necessary to be aligned with value 0x1000, so in your case alignment mask is 0x1ff and not 0x1000.
|
> In a sample having the first section unaligned the Olly puts the sections together in one section.
>
> I also have a sample with an unaligned 3rd section. In this case the data from this PointerToRawData is loaded to the VirutalAddress. But in this case the PointerToRawData has not been aligned before.
>
I dont think i follow your question, can you explain it? or share the samples?
|
> neoxfx: windows loader uses mask = ~(SectAlign > 0x200 ? 0x1ff : SectAlign-1) with section->PointertoRawData when loading.
>
> it is not necessary to be aligned with value 0x1000, so in your case alignment mask is 0x1ff and not 0x1000.
I just send you an email with two samples.
The masking you mentioned works fine for some samples. But not for all.
Is the file alignment thus never taken into consideration?
I expected it to be verified. Or is it just used for the purpose of size alignment?
I'll give you more details: (sample1)
file- and section-alignment = 0x1000
Section:
v. offset : 0x9a000
v. size: 0x20000
f. offset: 0x26600
f. size: 0x00df2
Apparently, the masking you proposed handles the section loading.
If I change f. offset being 0x26600 to be 0x26601 the file is not loadable any more.
Why?
(sample2)
file-alignment = 0x200
section-alignment = 0x1000
v. offset : 0x1000
v. size: 0x9000
f. offset: 0x0401
f. size: 0x4e00
In this case, the loading works fine. I can even modify the file offset and the mask you mentioned (~0x1ff) will handle the loading. But in contrast to the first sample above, the sections are loadable
In which cases is the mask used to detect an invalid PE file and when is it used to just load the data?
Do you know why these different behaviors occur?
I mean, I do not only want to load a given file, but also distinguish between valid and invalid ones.
|
load error occurred because you only did partial modification.
you modified last section raw-offset from 0x26600 to 0x26601, which is ok, as long as you've modified the physical size in accordance. i.e., from 0xdf2 to 0xdf1. that way file will not be smaller than the size that PE header mentions.
hope this helps
|
> neoxfx: > hope this helps
you're right!
thank you
|
Note: Registration is required to post to the forums.
|
|
|
There are 31,321 total registered users.
|
|