import
os
import
sys
import
re
import
struct
def
get_ppc_base_by_switch_table(image_data, start_addr, max_gap
=
1
<<
16
):
offset
=
start_addr
gap
=
0
jmp_table_addr
=
struct.unpack_from(
">i"
, image_data, offset)[
0
]
if
jmp_table_addr
=
=
0
:
return
-
1
jmp_table_addrs
=
[]
while
gap < max_gap:
jmp_table_addrs.append(jmp_table_addr)
offset
=
offset
+
4
addr
=
struct.unpack_from(
">i"
, image_data, offset)[
0
]
gap
=
abs
(addr
-
jmp_table_addr)
jmp_table_addr
=
addr
jmp_table_addrs.sort()
file_loc1_addr
=
offset
true_loc1_addr
=
jmp_table_addrs[
0
]
ppc_base
=
true_loc1_addr
-
file_loc1_addr
return
ppc_base
def
get_switch_code_addrs(image_data):
re_switch_opcode
=
b
"\x7d.{1}\x03\xA6\x4E\x80\x04\x20"
bytes_data
=
bytearray(image_data)
re_pattern
=
re.
compile
(re_switch_opcode)
addrs
=
[]
for
match_obj
in
re_pattern.finditer(bytes_data):
addrs.append(match_obj.start()
+
8
)
return
addrs
def
ppc_base_count(ppc_bases):
freq_dict
=
{}
for
ppc_base
in
ppc_bases:
freq_dict[ppc_base]
=
freq_dict.get(ppc_base,
0
)
+
1
return
freq_dict
def
print_success(ppc_bases):
ppc_base_freq
=
ppc_base_count(ppc_bases)
ppc_base_freq
=
sorted
(ppc_base_freq.items(), key
=
lambda
kv:(kv[
0
], kv[
1
]))
for
base
in
ppc_base_freq:
print
(
'%#x:%d'
%
(base[
0
], base[
1
]))
print
(
"The rebase address is:%#x"
%
ppc_base_freq[
0
][
0
])
def
find_ppc_rebase(firmware_path):
f
=
open
(firmware_path,
"rb"
)
image_data
=
f.read()
f.close()
addrs
=
get_switch_code_addrs(image_data)
if
len
(addrs)
=
=
0
:
print
(
"[-] error find switch table addrs"
)
return
ppc_bases
=
[]
for
addr
in
addrs:
ppc_base
=
get_ppc_base_by_switch_table(image_data, addr)
if
ppc_base <
0
:
continue
ppc_bases.append(ppc_base)
if
len
(ppc_bases) >
0
:
print
(firmware_path
+
" firmware base addr:\n"
)
print_success(ppc_bases)
else
:
print
(
"find rebase address failed, you can see the fllow addr use ida pro:"
)
for
inx, val
in
enumerate
(addrs):
if
inx >
5
:
break
print
(
"%#x"
%
(val
-
16
))
print
(
"press key C, find addi ra,rb, eg:addi r9, r11, 0x71A4 # 0x271A4"
)
print
(
"base = \"0x271A4\" - %#x"
%
addrs[
0
])
def
usage():
print
(
"ppc_rebase.py firmware_path"
)
def
main():
if
len
(sys.argv) <
2
:
usage()
else
:
firmware_path
=
sys.argv[
1
]
if
not
os.path.exists(firmware_path):
usage()
else
:
find_ppc_rebase(firmware_path)
if
__name__
=
=
"__main__"
:
main()