Skip to content

Ropper misses forward edges of jumps that lead to ret #180

Description

@MyEyes

When a function ends with a switch statement you often see a lot of jumps to a static address that then just returns.
Below is an example of this pattern.

    1170:       c7 45 f8 01 00 00 00    movl   $0x1,-0x8(%rbp)
    1177:       eb 3e                   jmp    11b7 <main+0x8e>
    1179:       c7 45 f8 02 00 00 00    movl   $0x2,-0x8(%rbp)
    1180:       eb 35                   jmp    11b7 <main+0x8e>
    1182:       c7 45 f8 03 00 00 00    movl   $0x3,-0x8(%rbp)
    1189:       eb 2c                   jmp    11b7 <main+0x8e>
    118b:       c7 45 f8 04 00 00 00    movl   $0x4,-0x8(%rbp)
    1192:       eb 23                   jmp    11b7 <main+0x8e>
    1194:       c7 45 f8 05 00 00 00    movl   $0x5,-0x8(%rbp)
    119b:       eb 1a                   jmp    11b7 <main+0x8e>
    119d:       c7 45 f8 06 00 00 00    movl   $0x6,-0x8(%rbp)
    11a4:       eb 11                   jmp    11b7 <main+0x8e>
    11a6:       c7 45 f8 07 00 00 00    movl   $0x7,-0x8(%rbp)
    11ad:       eb 08                   jmp    11b7 <main+0x8e>
    11af:       c7 45 f8 08 00 00 00    movl   $0x8,-0x8(%rbp)
    11b6:       90                      nop
    11b7:       8b 45 f8                mov    -0x8(%rbp),%eax
    11ba:       5d                      pop    %rbp
    11bb:       c3                      retq

Ropper misses these gadgets, I'm assuming because the search doesn't follow forward edges.
Even when using very permissive search results it doesn't find these gadgets.

Here are the example code I used to generate the test binary and the command I ran to check for gadgets.

#define CASE_RET(x) case x: return_val = (x+1); break;

int main(int argc, char** argv)
{
    int x = 0;
    int return_val = 0;
    switch(x)
    {
        CASE_RET(0)
        CASE_RET(1)
        CASE_RET(2)
        CASE_RET(3)
        CASE_RET(4)
        CASE_RET(5)
        CASE_RET(6)
        CASE_RET(7)
    }
    return return_val;
}

Compiling and checking for ret type gadgets that start with mov only finds the last switch case and the mov from [rbp-8] to eax but doesn't find all other integer moves into [rbp-8}

gcc test.c
ropper -f a.out --type rop --quality 100 --inst-count 20 --nocolor | grep ': mov'
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
0x000000000000110c: mov byte ptr [rip + 0x2efd], 1; pop rbp; ret; 
0x00000000000011af: mov dword ptr [rbp - 8], 8; nop; mov eax, dword ptr [rbp - 8]; pop rbp; ret; 
0x00000000000011b7: mov eax, dword ptr [rbp - 8]; pop rbp; ret; 
0x0000000000001009: mov eax, dword ptr [rip + 0x2fd9]; test rax, rax; je 0x1016; call rax; add rsp, 8; ret; 
0x00000000000010f7: mov ebp, esp; je 0x1107; mov rdi, qword ptr [rip + 0x2f06]; call 0x1030; call 0x1070; mov byte ptr [rip + 0x2efd], 1; pop rbp; ret; 
0x00000000000010fc: mov edi, dword ptr [rip + 0x2f06]; call 0x1030; call 0x1070; mov byte ptr [rip + 0x2efd], 1; pop rbp; ret; 
0x0000000000001008: mov rax, qword ptr [rip + 0x2fd9]; test rax, rax; je 0x1016; call rax; add rsp, 8; ret; 
0x00000000000010f6: mov rbp, rsp; je 0x1107; mov rdi, qword ptr [rip + 0x2f06]; call 0x1030; call 0x1070; mov byte ptr [rip + 0x2efd], 1; pop rbp; ret; 
0x00000000000010fb: mov rdi, qword ptr [rip + 0x2f06]; call 0x1030; call 0x1070; mov byte ptr [rip + 0x2efd], 1; pop rbp; ret;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions