blackd0t () started working on his own PE packer and reached the moment where everything is fine, but MSVC++ 2005 floating point files refuse to work and end up with the runtime error: “R6002: floating point not loaded error” . it’s a common problem. many commercial packers meet the same bug.
well, let’s find out what’s this bug all about! first of all I wrote a simple floating-point program and translated it with Microsoft Visual C++ 2008 (Express). the source code is followed (if don’t have MS VC under your hands, just download the archive):
int a; double x = 1.2f;
for (a = 0; a < 10; a++) x += sin(x); cout << x;
ok. run it and get 3.14159. the program runs fine! now, we’re going to make “.rdata” writable. why? blackd0t mentioned what he already found out: if “.rdata” is writable, we get the error. the question is why?! maybe there is a bug: if .rdata section is writable - floating point library damages critical data, maybe not, who knows?
open exe with HIEW, press ENTER to go to hex-mode, F8 to call PE-header, F6 for ObjTable, move cursor to “.rdata”, F3 to edit, find “Attributes” there, F3 to edit, change the highest bit from 0 to 1 and press F9 twice to save changes. ESC (twice) to exit.
ops! now we see:
runtime error R6002
- floating point support not loaded
ok. run HIEW and restore the attributes back. everything works fine as before. load exe into OllyDbg, View -> Memory, find “.rdata” and set memory breakpoint on write. run the program. the program runs fine, nobody tries to write something to “.rdata” section. hm… strange…
ok, ask HIEW to make “.rdata” writable again, reload the file into OllyDbg and run it (with memory breakpoint). the program does not work (the same error), but our breakpoint has been not triggered. what’s a helll?!
make “.rdata” non-writable, reload the file into OllyDbg, View -> Memory and change access of “.rdata” section to RW. run the file. no error! the program works fine.
ok. we got it!!! the floating point library checks not access attributes themselves, but verifies PE-header. go to dump windows (in Olly). press CTRL-G and type the address of the header (400000h in this case). find “.rdata” there and move cursor to 40 00 00 40 (the last DWORD before “.data”). set hardware breakpoint on access and press F9 to run the program, the breakpoint is triggered!!!
how do you like this:
.text:0040E780 __IsNonwritableInCurrentImage proc near
.text:0040E782 push ebp
.text:0040E783 mov ebp, esp
.text:0040E7C1 call __ValidateImageBase
.text:0040E7D6 push 400000h
.text:0040E7DB call __FindPESection
.text:0040E7E0 add esp, 8
.text:0040E7E3 test eax, eax
.text:0040E7E5 jz short loc_40E822
.text:0040E7E7 mov eax, [eax+24h] ; !!! breakpoint is triggered here !!!
.text:0040E7EA shr eax, 1Fh
_IsNonwritableInCurrentImage() reads PE-header in order to checks - if its argument belongs to non-writable section.
so, packers are obligated to keep original PE sections layout (or restore only PE header in memory) unless they want to crash floating point applications translated with MS VC and maybe other compilers.
thanks blackd0t for the interesting question!
I wonder: how may packers/protectors will be unable to process this file? going to find out. plz, test all packers/protectors you only have under your hands and leave comments. time to send bug reports :-)
first of all it’s bug of MS RTL - bitch should check real page attributes, not just PE-header!
second of all: numerous packers/protectors do not restore PE-header or damage it to prevent dumping or… disables all PE-header pages (PAGE_NO ACCESS)