Repository navigation
Conversation
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head
Corpus measurement, one environment per side, each built through the collection from the trees
Caveats, one line each:
|
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Full metadata-region list and CFG for the image whose SHA-256 is Both blocks are one run of the same script against the same file, printing the same queries in Before — five pointer arrays out of the load-config directory land outside the image, cle master 5d5929eAfter — the five are gone, every remaining region is inside the image, and the same call recovers 144 functions: with this change 23e28a7The second sample, |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_862 |
A data directory's address and extent are whatever the file says. `_meta_load_config` reads the four guard tables, and on a 32-bit image the SE handler table as well, straight out of the load-config directory; each is built when its address and count are both non-zero, which rejects an empty table and nothing else. So an image whose load-config is not a load-config -- a packer wrote over it, the file ends inside it -- hands pefile string bytes and gets pointer arrays back, at addresses the object does not cover and with sizes in the gigabytes. A consumer that believes those numbers loses the whole image rather than the one directory. angr's `CFGFast._process_metadata_regions` marks each metadata region as data in its segment list, so a single region spanning the image leaves no address code: every block is lifted with size 0 and the CFG comes back empty for a binary whose entry point decodes on the first try. `_clip_meta_regions` runs after `_register_sections`, where the extent is known. A region that starts outside the object is dropped; one that starts inside and runs past the end is shortened, because the tail is the part that is not there, and dropping it would throw away the directory in front of it. `PointerArray` and `StructArray` keep `count` consistent with the new size.
a80a9c0 to
23e28a7
Compare
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
CFGFastreturns an empty model for a Windows image whose entry point decodes on thefirst try. Two 32-bit samples enter at
0x4bf000and0x10001f71, both inside a sectioncle reports executable.
project.factory.block(proj.entry)lifts 14 instructions at thefirst and 4 at the second, each ending in a
call, and the CFG is still empty:No function means no decompilation, no calling conventions and no cross references.
Root cause
PE._meta_load_configbuilds pointer arrays out of the load-config directory's own fields --the four guard tables, and on a 32-bit image the SE handler table as well. Each is built when
its address and count are both non-zero, which rejects an empty table and nothing else:
Where the load-config is not a load-config -- a packer wrote over it, the file ends inside it --
pefile hands back whatever bytes are there and those become regions. On
7b00ec19...all fiveland outside the object, which spans
0x400000-0x4c2bff: one at0x61696c41(the ASCII ofAlia), one at0x6564declaring 6,796,609,364 bytes.The numbers do not stay in the loader. angr's
CFGFast._process_metadata_regionsmarksevery metadata region as data in its segment list, so one region spanning the image leaves
no address code:
_generate_cfgnodetakes its block size from_seg_list.next_pos_with_sort_not_in(addr, {"code"}), that returns the address itself, andevery lift is asked for 0 bytes. Measured on both samples, the segment list reports sort
unknownat the entry and every traced_liftcall asks forsize=0. One junk directorycosts the whole image.
Fix
PE._clip_meta_regionsholds each region and sub-region to the image: a region that startsoutside the object is dropped, one that starts inside and runs past the end is shortened, and
PointerArrayandStructArraykeepcountconsistent with the new size. It runs after_register_sectionsbecause the extent ismax_addr, read off the sections and cached onfirst access.
Shortening rather than dropping is the whole of the difference on a well-formed image.
tests/i386/windows/9f2ef84bde1e4ef445708cc5a605a09226363d502b1f5b5bf4a1cfc6dd5fc41edeclares 29,696 bytes of resource directory where the image has 4,096 left. Shortened, its
CFG is the one master already recovers, function for function: with angr at
3f5717544, 197functions, 1,278 blocks and 1,862 edges on both sides, the same function addresses. Dropped, it
becomes 199 functions, and the two extra are at
0x409204and0x409243, inside the resourcespan the dropped region would have left unmarked.
Testing
tests/test_pe_meta_regions.py::TestPEMetaRegionsHeldToTheImageasserts that no region orsub-region of that tracked image leaves it, and that its resource directory is shortened to
0x1000rather than dropped. Both fail on master: the first on the containment assertion,the second on
assert 29696 == 4096.MEASURE.pyloads each object in its own process and runs theCFGFastcall above; its argumentnames the output file. The two arms are two builds of cle,
pe.pyreverted to the base and thenrestored, and in each build the installed
pe.pyis byte-identical to that revision's blob whileevery other family package hashes the same.
On the two samples,
CFGFastgoes from 0 functions to 144 on the one above (290 blocks,367 edges) and to 59 on the other (531 blocks, 827 edges); 5 out-of-range regions become 0
on each. The samples are live malware and cannot be shared, so they are identified by
SHA-256:
7b00ec194518b62bc726966c0a45c3d992736cf8e75f4d12cf4bd3842bd90aafis the one thatenters at
0x4bf000, and3d7fe603def5bc06941033d5e687a990f423947d8d88fe5396f9d359b8930413enters at0x10001f71.Over all 123 files
angr/binariestracks at67c892ca8be2whose header is a PE -- found bymagic, not by directory -- the clip shortens one region on one object, drops none, leaves none
outside its image and creates no zero-size region. The regression set is 88 objects -- 80 PE
samples from the corpus that already recovered functions, plus 8 of those tracked files -- and
not one function, block or edge changes on any of them. Counts are in the validation record.
Two other open changes in this repository bound a metadata region and neither subsumes this one.
#834 narrows a region that is oversized inside the image and touches only
_meta_imports; itsays as much itself, that the load-config sub-tables and the resource directory
Size"eachwants its own change with its own reproducer". #869 bounds the resource directory to the mapped
section that contains it, which is tighter than the image bound here and leaves the out-of-image
pointer arrays untouched. All three append their regression to
tests/test_pe_meta_regions.pyat the same anchor, so whichever lands after another needs arebase in that one file;
merge-treeputs each of the other two into master cleanly.Validation: #862 (comment)
session: sharpen