More robust PackWcle::decodeFixups()
https://github.com/upx/upx/issues/455 modified: p_wcle.cpp
This commit is contained in:
committed by
Markus F.X.J. Oberhumer
parent
21d102c84f
commit
00139caf43
+27
-10
@@ -599,23 +599,40 @@ void PackWcle::decodeFixups()
|
|||||||
set_le32(wrkmem+ic*8,0xFFFFFFFF); // end of 32-bit offset fixups
|
set_le32(wrkmem+ic*8,0xFFFFFFFF); // end of 32-bit offset fixups
|
||||||
tmpbuf.dealloc();
|
tmpbuf.dealloc();
|
||||||
|
|
||||||
// selector fixups and self-relative fixups
|
// selector fixups then self-relative fixups
|
||||||
const upx_byte *selector_fixups = p;
|
const upx_byte *selector_fixups = p;
|
||||||
const upx_byte *selfrel_fixups = p;
|
|
||||||
|
|
||||||
while (*selfrel_fixups != 0xC3) {
|
// Find selfrel_fixups by skipping over selector_fixups.
|
||||||
// FIXME: Heuristic defense for running off the end.
|
const upx_byte *q = selector_fixups;
|
||||||
// End is unknown, but all-zero definitely is bad.
|
// The code is a subroutine that ends in RET (0xC3).
|
||||||
|
while (*q != 0xC3) {
|
||||||
|
// Defend against tampered selector_fixups; see PackWcle::preprocessFixups().
|
||||||
|
// selector_fixups[] is x386 code with 9-byte blocks of 2 instructions each:
|
||||||
|
// "\x8C\xCB\x66\x89\x9D" // mov bx, cs ; mov [xxx+ebp], bx
|
||||||
|
// "\x8C\xCA\x66\x89\x95"
|
||||||
|
// and where byte [+1] also can be '\xDA' or '\xDB'.
|
||||||
|
if (0x8C != q[0]
|
||||||
|
|| 0x66 != q[2]
|
||||||
|
|| 0x89 != q[3]) { // Unexpected; tampering?
|
||||||
|
// Try to recover by looking for the RET.
|
||||||
|
upx_byte const *q2 = (upx_byte const *)memchr(q, 0xC3, 9);
|
||||||
|
if (q2) { // Assume recovery
|
||||||
|
q = q2; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Guard against run-away.
|
||||||
static unsigned char const blank[9] = {0};
|
static unsigned char const blank[9] = {0};
|
||||||
if (!memcmp(blank, selfrel_fixups, sizeof(blank))) {
|
if (q > (oimage + ph.u_len - sizeof(blank)) // catastrohpic worst case
|
||||||
|
|| !memcmp(blank, q, sizeof(blank)) // no-good early warning
|
||||||
|
) {
|
||||||
char msg[50]; snprintf(msg, sizeof(msg),
|
char msg[50]; snprintf(msg, sizeof(msg),
|
||||||
"bad selfrel_fixups +%#zx", selfrel_fixups - p);
|
"bad selector_fixups +%#zx", q - selector_fixups);
|
||||||
throwCantPack(msg);
|
throwCantPack(msg);
|
||||||
}
|
}
|
||||||
selfrel_fixups += 9;
|
q += 9;
|
||||||
}
|
}
|
||||||
selfrel_fixups++;
|
unsigned selectlen = ptr_diff(q, selector_fixups)/9;
|
||||||
unsigned selectlen = ptr_diff(selfrel_fixups, selector_fixups)/9;
|
const upx_byte *selfrel_fixups = 1+ q; // Skip the 0xC3
|
||||||
|
|
||||||
ofixups = New(upx_byte, fixupn*9+1000+selectlen*5);
|
ofixups = New(upx_byte, fixupn*9+1000+selectlen*5);
|
||||||
upx_bytep fp = ofixups;
|
upx_bytep fp = ofixups;
|
||||||
|
|||||||
Reference in New Issue
Block a user