I try to parse all the Calls and Rets from an executable with ptrace. Conforming the the x64opcode, I found opcodes for Calls: 0xe8 and for Rets: 0xc3, 0xc2, 0xca, 0xcb.
Since I parsed them I found more Rets than Calls.
There is the program I trace:
void func()
{
write(1, "i", 1);
}
int main(int ac)
{
func();
return(0);
}
There is my tracer:
int tracer(t_info *info)
{
int status;
long ptr;
int ret = 0;
int call = 0;
waitpid(info->pid, &status, 0);
while (WIFSTOPPED(status))
{
ptrace(PTRACE_GETREGS, info->pid, NULL, info->regs);
ptr = ptrace(PTRACE_PEEKDATA, info->pid, info->regs->rip);
if (((ptr & 0x000000ff) == 0xe8)) // Opcode for call
{
call++;
}
else if (((ptr & 0x000000ff) == 0xc3) // Opcodes for rets
|| ((ptr & 0x000000ff) == 0xc2)
|| ((ptr & 0x000000ff) == 0xca)
|| ((ptr & 0x000000ff) == 0xcb))
{
ret++;
}
ptrace(PTRACE_SINGLESTEP, info->pid, 0, 0);
waitpid(info->pid, &status, 0);
}
printf("Calls: %i\nRets: %i\nDiff: %i\n", call, ret, call - ret);
return (0);
}
There is my output:
Calls: 656
Rets: 666
Diff: -10
Why is there not the same number of rets and calls ? Do I miss some opcodes ? Is there functions that not return?
You for example miss indirect calls like
which use other opcodes. Libc standard initialization routines make use of these. Depending on the expression several opcodes are possible, two examples:
It's probably not easy to get them all. Maybe it would be easier and cleaner to decode the instructions with a library like libbfd and libopcodes