невозможно извлечь константы и argc для функций для двоичного файла ELF Linux
Я использую последнюю версию angr (9,0,'gitrollling'). [У меня такое же поведение с версией angr (9, 0, 4663)].
Используя gcc 9.3.0, я создал двоичный файл ELF для этой простой программы на C:
float func3(float y) {
float temp = 5.5; // expected angr to find this constant
return y + temp;
}
int main(int argc, char *argv[]) {
float ans;
ans = func3(2.2); // expected angr to find this constant
}
Затем я использовал angr для извлечения констант в моих функциях (а именно «func3» и «main»), а также количества аргументов для функций. К сожалению, ответы, которые я получаю для констант («const» в выводе ниже) или для «argc», не имеют смысла. Я получил:
name main const [8, 32, 8, 32, 18446744073709551596, 18446744073709551584, 0, 4202504, 4202504,
8, 4198767, 128, 4198697, 18446744073709551612, 0, 8, 8, 128] argc -1
name func3 const [8, 18446744073709551596, 4202500, 4202500, 18446744073709551612,
18446744073709551596, 0, 18446744073709551612, 8, 8, 128] argc -1
Мой код Angr:
#!/usr/bin/env python3
import angr
from angrutils import *
def get_attributes(cfg, addr):
if addr in cfg.kb.functions:
func = cfg.kb.functions.get_by_addr(addr)
if func:
name = func.demangled_name
if name != 'main' and name != 'func3':
return # only care about these 2 funcs
const = func.code_constants
argc = len(func.arguments) if func.arguments else -1
print(' name %s const %s argc %s ' % (name, const, argc))
return
proj = angr.Project('simple', main_opts={'backend': 'elf'}, load_options={'auto_load_libs':False})
main = proj.loader.main_object.get_symbol('main')
start_state = proj.factory.blank_state(addr=main.rebased_addr)
start_state.stack_push(0x0)
with hook0(proj):
cfg = proj.analyses.CFGFast() # using CFGEmulated() also does not change the answer!
#cfg = proj.analyses.CFGEmulated(fail_fast=False, starts=[main.rebased_addr], context_sensitivity_level=1, enable_function_hints=False, keep_state=True, enable_advanced_backward_slicing=False, enable_symbolic_back_traversal=False,normalize=True)
d=dict()
for src, dst in cfg.kb.functions.callgraph.edges():
if not d.get(src): # only need to do this once.
src_attr = get_attributes(cfg, src)
d[src] = True # mark completed
if not d.get(dst): # only need to do this once.
dst_attr = get_attributes(cfg, dst)
d[dst] = True # mark completed
Где я ошибаюсь?
1 ответ
I have no experience with angr, but based on inspecting the assembly generated for your program, I have some hypotheses for what went wrong:
has no side effects and does not use the value of
ans
, so the compiler can eliminate the call to entirely, e.g. on x86-64 I get this formain
:main: movl $0, %eax ret
So the constant 2.2 may well not be in the executable at all.
Floating point constants usually have to be emitted into memory and loaded by reference, e.g. on x86-64 I get this assembly for
func3
:.section .text func3: addss .LC0(%rip), %xmm0 ret .section .rodata .LC0: .long 1085276160
In a fully linked executable the cross-reference
.LC0
becomes a relative offset:1125: f3 0f 58 05 d7 0e 00 00 addss 0xed7(%rip),%xmm0 112d: c3 retq
It is possible that angr does not recognize this offset as a constant to be extracted, or that it can only extract this offset and not the value in .rodata that it refers to. And even if it could pull out the value in .rodata, the only way it could know that the value should be interpreted as a single-precision float rather than an integer, is if it decoded the instruction that uses the value.