Is there any way to find from a binary file means from assembly code that whether in a function, an array parameter has been passed or not? - binaryfiles

I am doing binary ananlysis and I hav many objectives like to know the types of function paramter whether its an array or pointer or char or int type. Also, my objctive is to find whether an array has been passed as a function parameter.
Here is my C program.
#include<stdio.h>
#include<string.h>
void concat(char s1[], char s2[]) {
int i, j;
i = strlen(s1);
for (j = 0; s2[j] != '\0'; i++, j++) {
s1[i] = s2[j];
}
s1[i] = '\0';
}
int main() {
char a[] = "Hello";
char b[] = "World";
concat(a, b);
return (0);
}
Here is my assembly code
0000000000001169 <concat>:
1169: endbr64
116d: pushq %rbp
116e: movq %rsp,%rbp
1171: subq $0x20,%rsp
1175: movq %rdi,-0x18(%rbp)
1179: movq %rsi,-0x20(%rbp)
117d: movq -0x18(%rbp),%rax
1181: movq %rax,%rdi
1184: callq 1060 <strlen#plt> //since calls destination is eax //
1189: movl %eax,-0x8(%rbp)
118c: movl $0x0,-0x4(%rbp) //local argument
1193: jmp 11bc <concat+0x53>
1195: movl -0x4(%rbp),%eax
1198: movslq %eax,%rdx //hint that 32bit source moved to 64 bit sign extended
119b: movq -0x20(%rbp),%rax
119f: addq %rdx,%rax
11a2: movl -0x8(%rbp),%edx
11a5: movslq %edx,%rcx
11a8: movq -0x18(%rbp),%rdx
11ac: addq %rcx,%rdx
11af: movzbl (%rax),%eax
11b2: movb %al,(%rdx)
11b4: addl $0x1,-0x8(%rbp)
11b8: addl $0x1,-0x4(%rbp)
11bc: movl -0x4(%rbp),%eax
11bf: movslq %eax,%rdx
11c2: movq -0x20(%rbp),%rax
11c6: addq %rdx,%rax
11c9: movzbl (%rax),%eax
11cc: testb %al,%al
11ce: jne 1195 <concat+0x2c>
11d0: movl -0x8(%rbp),%eax
11d3: movslq %eax,%rdx
11d6: movq -0x18(%rbp),%rax
11da: addq %rdx,%rax
11dd: movb $0x0,(%rax)
11e0: nop
11e1: leaveq
11e2: retq
From the assembly code how can I tell whether an array has been passed or not in a function?
I am trying to understand the reverse enginnering tools.

Related

printf gets stuck in an infinite loop with AL = 10 on x86-64 Linux with older gcc

Very simple assembly introduction code.
Seems to compile ok through gcc -o prog1 prog1.s, then ./prog1 just skips a line and shows nothing, like waiting an input the code doesn't ask. What's wrong?
Using gcc (Debian 4.7.2-5) 4.7.2 in 64-bit gNewSense running on VMware.
Code:
/*
int nums[] = {10, -21, -30, 45};
int main() {
int i, *p;
for (i = 0, p = nums; i != 4; i++, p++)
printf("%d\n", *p);
return 0;
}
*/
.data
nums: .int 10, -21, -30, 45
Sf: .string "%d\n" # string de formato para printf
.text
.globl main
main:
/********************************************************/
/* mantenha este trecho aqui e nao mexa - prologo !!! */
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq %rbx, -8(%rbp)
movq %r12, -16(%rbp)
/********************************************************/
movl $0, %ebx /* ebx = 0; */
movq $nums, %r12 /* r12 = &nums */
L1:
cmpl $4, %ebx /* if (ebx == 4) ? */
je L2 /* goto L2 */
movl (%r12), %eax /* eax = *r12 */
/*************************************************************/
/* este trecho imprime o valor de %eax (estraga %eax) */
movq $Sf, %rdi /* primeiro parametro (ponteiro)*/
movl %eax, %esi /* segundo parametro (inteiro) */
call printf /* chama a funcao da biblioteca */
/*************************************************************/
addl $1, %ebx /* ebx += 1; */
addq $4, %r12 /* r12 += 4; */
jmp L1 /* goto L1; */
L2:
/***************************************************************/
/* mantenha este trecho aqui e nao mexa - finalizacao!!!! */
movq $0, %rax /* rax = 0 (valor de retorno) */
movq -8(%rbp), %rbx
movq -16(%rbp), %r12
leave
ret
/***************************************************************/
tl;dr: do xorl %eax, %eax before call printf.
printf is a varargs function. Here's what the System V AMD64 ABI has to say about varargs functions:
For calls that may call functions that use varargs or stdargs (prototype-less
calls or calls to functions containing ellipsis (. . . ) in the declaration) %al18 is used
as hidden argument to specify the number of vector registers used. The contents
of %al do not need to match exactly the number of registers, but must be an upper
bound on the number of vector registers used and is in the range 0–8 inclusive.
You broke that rule. You'll see that the first time your code calls printf, %al is 10, which is more than the upper bound of 8. On your gNewSense system, here's a disassembly of the beginning of printf:
printf:
sub $0xd8,%rsp
movzbl %al,%eax # rax = al;
mov %rdx,0x30(%rsp)
lea 0x0(,%rax,4),%rdx # rdx = rax * 4;
lea after_movaps(%rip),%rax # rax = &&after_movaps;
mov %rsi,0x28(%rsp)
mov %rcx,0x38(%rsp)
mov %rdi,%rsi
sub %rdx,%rax # rax -= rdx;
lea 0xcf(%rsp),%rdx
mov %r8,0x40(%rsp)
mov %r9,0x48(%rsp)
jmpq *%rax # goto *rax;
movaps %xmm7,-0xf(%rdx)
movaps %xmm6,-0x1f(%rdx)
movaps %xmm5,-0x2f(%rdx)
movaps %xmm4,-0x3f(%rdx)
movaps %xmm3,-0x4f(%rdx)
movaps %xmm2,-0x5f(%rdx)
movaps %xmm1,-0x6f(%rdx)
movaps %xmm0,-0x7f(%rdx)
after_movaps:
# nothing past here is relevant for your problem
A quasi-C translation of the important bits is goto *(&&after_movaps - al * 4); (see Labels as Values). For efficiency, gcc and/or glibc didn't want to save more vector registers than you used, and it also doesn't want to do a bunch of conditional branches. Each instruction to save a vector register is 4 bytes, so it takes the end of the vector register saving instructions, subtracts al * 4 bytes, and jumps there. This results in just enough of the instructions executing. Since you had more than 8, it ended up jumping too far back, and landing before the jump instruction it just took, thus creating an infinite loop.
As for why it's not reproducible on modern systems, here's a disassembly of the beginning of their printf:
printf:
sub $0xd8,%rsp
mov %rdi,%r10
mov %rsi,0x28(%rsp)
mov %rdx,0x30(%rsp)
mov %rcx,0x38(%rsp)
mov %r8,0x40(%rsp)
mov %r9,0x48(%rsp)
test %al,%al # if(!al)
je after_movaps # goto after_movaps;
movaps %xmm0,0x50(%rsp)
movaps %xmm1,0x60(%rsp)
movaps %xmm2,0x70(%rsp)
movaps %xmm3,0x80(%rsp)
movaps %xmm4,0x90(%rsp)
movaps %xmm5,0xa0(%rsp)
movaps %xmm6,0xb0(%rsp)
movaps %xmm7,0xc0(%rsp)
after_movaps:
# nothing past here is relevant for your problem
A quasi-C translation of the important bits is if(!al) goto after_movaps;. Why did this change? My guess is Spectre. The mitigations for Spectre make indirect jumps really slow, so it's no longer worth doing that trick. Or not; see comments. Instead, they do a much simpler check: if there's any vector registers, then save them all. With this code, your bad value of al isn't a disaster, since it just means the vector registers will be unnecessarily copied.

How to save registers state just before instruction call?

For arbitrary function in C, how to save registers state just before the call instruction?
Consider the example below (assume it's x86_64),
// We don't know what the `func` is.
#define run(func) \
do {func;} while(0)
// Say the `func` is `add`
int64_t add(int64_t a, int64_t b) {
return a + b
}
int main(void) {
run(add(1, 2));
}
The generated assembly code in gcc may be something like,
main:
push %rbp
movq %rsp, %rbp
movq $1, %rdi
movq $2, %rsi
# The question is:
# how can we save registers like %rdi, %rsi etc. here in C code?
call add
movq %rbp, %rsp
popq %rbp

x86-64 function calls using stack gdb debugging error cannot access memory at location xxx

I am writing a program calling 2 pre-given functions min.c and conv.c, also of course a main.c
min.s goes as follows:
.file "min.c"
.text
.p2align 4,,15
.globl min
.type min, #function
min:
.LFB0:
.cfi_startproc
cmpl %esi, %edi
movl %esi, %eax
cmovle %edi, %eax
ret
.cfi_endproc
.LFE0:
.size min, .-min
.ident "GCC: (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0"
.section .note.GNU-stack,"",#progbits
conv.c:
char conv(char *, char *, int);
char conv(char *x, char *h, int n) {
char ret = 0;
int i;
for (i = 0; i < n; i++) {
ret += x[i] * h[n-i-1];
}
return ret;
}
min.c:
int min(int, int);
int min(int a, int b) {
if (a < b) return a;
return b;
}
and conv.s goes as follows:
.file "conv.c"
.text
.p2align 4,,15
.globl conv
.type conv, #function
conv:
.LFB0:
.cfi_startproc
testl %edx, %edx
jle .L4
movslq %edx, %rax
leaq -1(%rsi,%rax), %rcx
leaq -2(%rsi,%rax), %rsi
leal -1(%rdx), %eax
xorl %edx, %edx
subq %rax, %rsi
.p2align 4,,10
.p2align 3
.L3:
movzbl (%rdi), %eax
subq $1, %rcx
addq $1, %rdi
mulb 1(%rcx)
addl %eax, %edx
cmpq %rcx, %rsi
jne .L3
movl %edx, %eax
ret
.p2align 4,,10
.p2align 3
.L4:
xorl %edx, %edx
movl %edx, %eax
ret
.cfi_endproc
.LFE0:
.size conv, .-conv
.ident "GCC: (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0"
.section .note.GNU-stack,"",#progbits
also my small basic piece of code is trying to just go after a pre-given algorithm:
for i from 0 to n+m-2 do
ladj <- min(i+1, m)
radj <- m - min(m+n-(i+1), m)
result[i] <- conv(x + (i+1-ladj), h + radj, ladj-radj)
so i wrote:
.globl conv_arr
conv_arr:
movq $0, %rax # zero out the result
movq $0, %rbx # %rbx is set to 0 to be the counter for the loop, i.e. int i
addq %rsi, %rbp
addq %rcx, %rbp
subq $2, %rbp # 3 lines of code to set a limit for the counter, i.e. n + m - 2
loop: # loop label
cmpq %rbx, %rbp # comparing to keep the loop in scope from i = 0 to n + m - 2
jle return # jump to return label if the counter reaches the limit
pushq %rdi
pushq %rsi # saving all the registers before calling function min( int, int)
movq %rbx, %r10 # copying the value of %rbx into the value of %r10
addq $1, %r10 # adding 1 to the value of %r10
movq %r10, %rdi # changing the value of %rdi ( in this case the first parameter
# to the function min() ) to i + 1
movq %rcx, %rsi # changing the value of %rsi ( in this case the second parameter to
# the function min() ) to m
call min # calling the function min() with the two parameters %rdi, %rsi
popq %rsi
popq %rdi # restoring the values of %rdi and %rsi to their initial values
movq %rax, %r12 # copying the value of the result from function min() to %r12,
# the register which is now set up to be the value of ladj
pushq %rdi
pushq %rsi # saving the values of %rdi and %rsi before calling function min()
movq %rcx, %rdi # copying the value of %rcx ( int m ) into the value of %rdi
addq %rsi, %rdi # adding the value of %rsi ( int n ) into the value of %rdi
subq %rbx, %rdi # subtracting the value of %rbx ( int i ) from the value of %rdi
subq $1, %rdi # subtracting 1 from the value of %rdi
movq %rcx, %rsi # copying the value of %rcx ( int m ) into the value of %rsi
call min # calling the function min() with two parameters %rdi, %rsi
popq %rsi
popq %rdi # restoring the values of %rdi and %rsi to their initial values
movq %rcx, %r13 # copying the value of %rcx ( int m ) into the value of
# register %r13
subq %rax, %r13 # subtracting the value of %rax ( min( m + n - ( i + 1 ), m ) )
# from the value of %rcx ( m )
movq %r13, %r14 # copying the value of %r13 ( m - min( m + n - ( i + 1 ), m ) # ) into the value of %r14, the register which is now set up
# to be the value of radj
pushq %rdi
pushq %rsi
pushq %rdx
pushq %rcx # saving the values of %rdi, %rsi, %rdx and %rcx before calling
# function conv( char*, char*, int )
addq %rbx, %rdi # adding the value of %rbx ( i ) to the value of %rdi ( char* x )
addq $1, %rdi # adding 1 to the value of %rdi
subq %r12, %rdi # subtracting the value of %r12 ( ladj ) from the value of %rdi
movq %rdx, %rsi # copying the value of %rdx ( char* h ) to the value of %rsi
addq %r14, %rsi # adding the value of %r14 ( radj ) to the value of %rsi
movq %r12, %rdx # copying the value of %r12 ( ladj ) to the value of %rdx
subq %r14, %rdx # subtracting the value of %r14 ( radj ) from the value of %rdx
call conv # calling the function conv() with three parameters %rdi, %rsi
# and %rdx
popq %rcx
popq %rdx
popq %rsi
popq %rdi # restoring the values of %rdi, %rsi, %rdx and %rcx to their # initial values
movq %rax, %r8 # copying the value of %rax ( result after calling function conv() # ) into the value of the index that %r8 ( char* result) is # pointing to
incq %rbx # incrementing the value of %rbx ( i ) by 1
incq %r8 # incrementing the value of %r8 ( char* result ) according to the
# value of %rbx ( i ), i.e. result[i]
jmp loop # jump back to the loop label when all the procedures are done
return: # return label
ret
all the comments are given to keep track of what i was attempting to do, i know it needs a lot more research and attention.
When i ran the program it gave a segmentation fault, i ran gdb with it and it says the error was cannot access memory at address xxx:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400757 in conv (x=0x601050 <signal> "",
h=0xffffffff80601050 <error: Cannot access memory at address 0xffffffff601050> n=15) at conv.c:8.
8 ret += x[i] * h[n-i-1];
I tried breakpoints at lines using conv.c and it went backwards when counting, i.e. when the program reached n=3 it started going back to n=2, n=1 and then all the way back to n=-12 even further.
****IF ANYONE HAS ANY SUGGESTIONS I WOULD REALLY APPRECIATE IT****.

Load floating-point number from pointer to float and push on stack

This is a homework task. I've got a C program that calls a function calc(int, float*, float*, float*, float*) implemented with NASM. I want to do floating-point division with the data passed from C, but first I wanted to check if I access the data correctly.
This is an excerpt from the C program:
printf("read.c: F data1[0]=%f\n", data1[0]);
printf("read.c: X data1[0]=%X\n", *(int*)(&data1[0]));
calc(nlines, data1, data2, result1, result2);
For testing, I wanted to print out exactly the same from the assembler code, but whatever I tried, it wouldn't give me the right results. To be precise, outputting the %X format gives the same result, but the %f format gives some incredibly huge number.
global calc
extern printf
; -----------------------------------------------------------------------
; extern void calc(int nlines, float* data1, float* data2,
; float* result1, float* result2)
; -----------------------------------------------------------------------
calc:
section .data
.strf db "calc.asm: F data1[0]=%f", 10, 0
.strx db "calc.asm: X data1[0]=%X", 10, 0
section .text
enter 0, 0
; Move the value of float* data1 into ecx.
mov ecx, [esp + 12]
; Move the contents of data1[0] into esi.
mov esi, [ecx]
push esi
push .strf
call printf
add esp, 8
push esi
push .strx
call printf
add esp, 8
leave
ret
Outputs
read.c: F data1[0]=20.961977
read.c: X data1[0]=41A7B221
calc.asm: F data1[0]=-8796958457989122902187458235483374032941932827208012972482327255932202912296419757153331437662235555722313731094096197990916443553479942683040096290755684437514827018615169352974748429901549205109479495668937369584705401541113350145698235773041651907978442730240007381959397006695721667307435228446926569472.000000
calc.asm: X data1[0]=41A7B221
I've also looked into fld, but I couldn't find out how I can push the loaded value on stack. This didnt work:
; Move float* data1 into ecx
mov ecx, [esp + 12]
; Load the floating point number into esi.
fld dword [ecx]
fst esi
How to do it right?
I've stripped down read.c to this code
#include <stdio.h>
#include <stdlib.h>
#define MAXLINES 1024
extern void calc(int, float*, float*, float*, float*);
int main(int argc, char** argv)
{
int nlines;
float* data1 = malloc(sizeof(float)*MAXLINES);
float*data2, *results1, *results2;
printf("read.c: F data1[0]=%f\n", data1[0]);
printf("read.c: X data1[0]=%X\n", *(int*)(&data1[0]));
calc(nlines, data1, data2, results1, results2);
return 0;
}
and this is the assembler output:
.file "test.c"
.section .rodata
.LC0:
.string "read.c: F data1[0]=%f\n"
.LC1:
.string "read.c: X data1[0]=%X\n"
.text
.globl main
.type main, #function
main:
.LFB2:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $64, %esp
movl $4096, (%esp)
call malloc
movl %eax, 44(%esp)
movl 44(%esp), %eax
flds (%eax)
fstpl 4(%esp)
movl $.LC0, (%esp)
call printf
movl 44(%esp), %eax
movl (%eax), %eax
movl %eax, 4(%esp)
movl $.LC1, (%esp)
call printf
movl 60(%esp), %eax
movl %eax, 16(%esp)
movl 56(%esp), %eax
movl %eax, 12(%esp)
movl 52(%esp), %eax
movl %eax, 8(%esp)
movl 44(%esp), %eax
movl %eax, 4(%esp)
movl 48(%esp), %eax
movl %eax, (%esp)
call calc
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE2:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
.section .note.GNU-stack,"",#progbits
.LC1:
.string "read.c: F data1[0]=%f\n"
.LC2:
.string "read.c: X data1[0]=%X\n"
.text
.globl main
.type main, #function
main:
.LFB4:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $64, %esp
movl 44(%esp), %eax
flds (%eax)
fstpl 4(%esp)
movl $.LC1, (%esp)
call printf
movl 44(%esp), %eax
movl (%eax), %eax
movl %eax, 4(%esp)
movl $.LC2, (%esp)
call printf
movl 60(%esp), %eax
movl %eax, 16(%esp)
movl 56(%esp), %eax
movl %eax, 12(%esp)
movl 52(%esp), %eax
movl %eax, 8(%esp)
movl 44(%esp), %eax
movl %eax, 4(%esp)
movl 48(%esp), %eax
movl %eax, (%esp)
call calc
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE4:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
.section .note.GNU-stack,"",#progbits
Ok, I've now had a chance to test this and verify that what I suggested in my comment works. Here's my modified version of the assembly code, with some comments to explain the things I've added/changed:
global _calc
extern _printf
; -----------------------------------------------------------------------
; extern void calc(int nlines, float* data1, float* data2,
; float* result1, float* result2)
; -----------------------------------------------------------------------
_calc:
section .data
.strf db "calc.asm: F data1[0]=%f", 10, 0
.strx db "calc.asm: X data1[0]=%X", 10, 0
section .text
enter 0, 0
; Move the value of float* data1 into ecx.
mov ecx, [esp + 12]
; Move the contents of data1[0] into esi.
mov esi, [ecx]
fld dword [ecx] ; Load a single-precision float onto the FP stack.
sub esp,8 ; Make room for a double on the stack.
fstp qword [esp] ; Store the top of the FP stack on the regular stack as
; a double, and pop it off the FP stack.
push .strf
call _printf
add esp, 12 ; 12 == sizeof(char*) + sizeof(double)
push esi
push .strx
call _printf
add esp, 8
leave
ret

Does gcc (or any other compiler) change (n%2==1) for (n&1==1)?

To test if a number is odd or even,
It is my understanding that a test using
(n%2==1)
Is the same thing as
(n&1==1)
I assume the first test is faster (please correct me if I'm wrong), but does any compiler recognize this and "correct" it? Does this makes any difference in performance?
void main()
{
int n = 5;
int i = n & 1;
}
call __main
movl $5, -4(%rbp)
movl -4(%rbp), %eax
andl $1, %eax
movl %eax, -8(%rbp)
addq $48, %rsp
popq %rbp
ret
void main()
{
int n = 5;
int i = n % 2;
}
call __main
movl $5, -4(%rbp)
movl -4(%rbp), %eax
cltd
shrl $31, %edx
addl %edx, %eax
andl $1, %eax
subl %edx, %eax
movl %eax, -8(%rbp)
addq $48, %rsp
popq %rbp
ret
Tried with gcc.exe (GCC) 4.9.2 using -S -O0
So it seams that & 1 to check parity is slightly better.
Actually
(n%2==1)
is not the same as
(n&1==1)
if type of n is signed int, so the compiler code(gcc 5.1, -Ofast, 64bit):
int f(int n)
{
return (n % 2) == 1;
0: 89 f8 mov %edi,%eax
2: c1 e8 1f shr $0x1f,%eax
5: 01 c7 add %eax,%edi
7: 83 e7 01 and $0x1,%edi
a: 29 c7 sub %eax,%edi
c: 31 c0 xor %eax,%eax
e: 83 ff 01 cmp $0x1,%edi
11: 0f 94 c0 sete %al
}
14: c3 retq
So main part looks like(pseudo code):
uint64_t edi = eax;
eax >>= 0x1f;
edi += eax;
edi &= 1;
edi -= eax;
But if type of n is "unsigned int" all looks great(gcc 5.1, -Ofast):
0000000000000000 <f>:
unsigned char f(unsigned int n)
{
return (n % 2) == 1;
0: 83 e7 01 and $0x1,%edi
}
3: 89 f8 mov %edi,%eax
5: c3 retq

Resources