-
Member
reversing the return address check in 2.5.4.42940
here's a cleanish c implementation that is easier to understand.
the return address check starts at 0x1422BAE10 (base 0x140000000)
Code:
/*
- TBC 2.5.4.42940
- imagebase is 0x140000000
- returns:
1: if the arg is a valid return address
0: if not
*/
int
check_retaddr(uint8_t *ret)
{
uint8_t *mem = 0;
/* check 1. return address is inside .text */
if (ret < (uint8_t*)0x14001000 || ret > (uint8_t*)0x142400B75)
return 0;
/* check 2. invoked from a call. rop check? */
/* patterns: 0xe8, 0xff 0x1x, 0xff 0x5x, 0xff 0x9x, 0xff 0xdx */
int iscall = 0;
uint64_t reti = (uint64_t)ret;
if (mem[reti-5] == 0xe8) // call off4
iscall = 1;
if (mem[reti-6] == 0xff && (((mem[reti-5] & 0x38) - 16 ) & 0xf7) == 0) // call [reg + off4]
iscall = 1;
if (mem[reti-3] == 0xff && (((mem[reti-2] & 0x38) - 16 ) & 0xf7) == 0) // call [reg + off1]
iscall = 1;
if (mem[reti-2] == 0xff && (((mem[reti-1] & 0x38) - 16 ) & 0xf7) == 0) // call reg, call [reg]
iscall = 1;
if (! iscall)
return 0;
/* check 3. the return address is on the good list */
/* step 1. get the array of good return addresses */
uint32_t *rettab = (void*)0x01400BBC84;
uint64_t ret_offset = (uint64_t)ret - 0x140000000;
uint32_t array_offset = rettab[ret_offset / 0x4000];
if (array_offset == 0)
return 0;
/* step 2. traverse the array. check if this address is listed */
uint32_t *pgoodaddr = (uint32_t *)&rettab[array_offset/4];
while (*pgoodaddr > 0) {
if ( (*pgoodaddr - ret_offset) <= 64)
return 1;
pgoodaddr++;
}
return 0;
}
-
Post Thanks / Like - 3 Thanks
-
★ Elder ★
Originally Posted by
thateuler
here's a cleanish c implementation that is easier to understand.
the return address check starts at 0x1422BAE10 (base 0x140000000)
Code:
/*
- TBC 2.5.4.42940
- imagebase is 0x140000000
- returns:
1: if the arg is a valid return address
0: if not
*/
int
check_retaddr(uint8_t *ret)
{
uint8_t *mem = 0;
/* check 1. return address is inside .text */
if (ret < (uint8_t*)0x14001000 || ret > (uint8_t*)0x142400B75)
return 0;
/* check 2. invoked from a call. rop check? */
/* patterns: 0xe8, 0xff 0x1x, 0xff 0x5x, 0xff 0x9x, 0xff 0xdx */
int iscall = 0;
uint64_t reti = (uint64_t)ret;
if (mem[reti-5] == 0xe8) // call off4
iscall = 1;
if (mem[reti-6] == 0xff && (((mem[reti-5] & 0x38) - 16 ) & 0xf7) == 0) // call [reg + off4]
iscall = 1;
if (mem[reti-3] == 0xff && (((mem[reti-2] & 0x38) - 16 ) & 0xf7) == 0) // call [reg + off1]
iscall = 1;
if (mem[reti-2] == 0xff && (((mem[reti-1] & 0x38) - 16 ) & 0xf7) == 0) // call reg, call [reg]
iscall = 1;
if (! iscall)
return 0;
/* check 3. the return address is on the good list */
/* step 1. get the array of good return addresses */
uint32_t *rettab = (void*)0x01400BBC84;
uint64_t ret_offset = (uint64_t)ret - 0x140000000;
uint32_t array_offset = rettab[ret_offset / 0x4000];
if (array_offset == 0)
return 0;
/* step 2. traverse the array. check if this address is listed */
uint32_t *pgoodaddr = (uint32_t *)&rettab[array_offset/4];
while (*pgoodaddr > 0) {
if ( (*pgoodaddr - ret_offset) <= 64)
return 1;
pgoodaddr++;
}
return 0;
}
Additional little comment: You will see multiple versions and functions of the return address checks in the binary. Sometimes inlined, sometimes not. Sometimes without the check in the array and sometimes without.