невозможно извлечь константы и 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:

  1. 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 for main:

            main:
        movl $0, %eax
        ret
    

    So the constant 2.2 may well not be in the executable at all.

  2. 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.

Другие вопросы по тегам