Reverse engineering in Linux

This is a walkthrough: of:

  • Understanding linux executables

  • Reversing an ELF file

  • Virtualisation in Linux – an analysis of a Windows executable under a Linux host

Install VCodium or VSCode, or another IDE, or just use vim. Also, gcc.

Create a “hello world!” in C. I named it hello.c:

#include <stdio.h>
void main(void)
{
printf ("hello world!\n");
}

Compilation

┌──(kali㉿kali)-[~/Development/C]
└─$ gcc -o hello hello.c

The hello file is the Linux executable that displays the message “hello world!” in the console.

┌──(kali㉿kali)-[~/Development/C]
└─$ ./hello
hello world!

Identification

┌──(kali㉿kali)-[~/Development/C]
└─$ file hello   
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8207bd08cd906af9829fcbadd2a0ae7a35b68546, for GNU/Linux 3.2.0, not stripped

It uses a 64-bit ELF file-format. Take a look at text strings:

┌──(kali㉿kali)-[~/Development/C]
└─$ strings hello                                   
/lib64/ld-linux-x86-64.so.2
puts
__libc_start_main
__cxa_finalize
libc.so.6
GLIBC_2.2.5
GLIBC_2.34
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
PTE1
u+UH
hello world!
;*3$"
GCC: (Debian 12.2.0-9) 12.2.0
Scrt1.o
__abi_tag
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.0
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
hello.c
__FRAME_END__
_DYNAMIC
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_start_main@GLIBC_2.34
_ITM_deregisterTMCloneTable
puts@GLIBC_2.2.5
_edata
_fini
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
_end
__bss_start
main
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@GLIBC_2.2.5
_init
.symtab
.strtab
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.got.plt
.data
.bss
.comment

The strings are listed in order from the start of the file. The first part of the list contains the message and the compiler information. The first two lines show what libraries are used.

objdump

Using the -d parameter of the objdump command, disassemble the executable code (AT&T syntax):

┌──(kali㉿kali)-[~/Development/C]
└─$ objdump -d hello > disassembly.asm

To get Intel syntax, use the -M intel parameter:

┌──(kali㉿kali)-[~/Development/C]
└─$ objdump -M intel -d hello > disassembly-intel.asm

The disassembly of the code is usually in the .text section. Because this is a gcc-compiled program, skip all the initialisation code and look at the main function where the code is.

Moving into dynamic analysis, use ltrace, strace, and gdb.

ltrace

┌──(kali㉿kali)-[~/Development/C]
└─$ ltrace ./hello
puts("hello world!"hello world!
)                                                         = 13
+++ exited (status 13) +++

The output shows a readable code of what the program did. ltrace logged library functions that the program called and received. It called puts to display a message. And it received an exit status of 13 when the program terminated.

strace

strace logged every system call that happened, starting from when it was being executed by the system. execve is the first system call that was logged:

┌──(kali㉿kali)-[~/Development/C]
└─$ strace ./hello
execve("./hello", ["./hello"], 0x7ffd1d6a5f10 /* 65 vars */) = 0
brk(NULL)                               = 0x55d79226d000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f714f6fb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=87170, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 87170, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f714f6e5000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0Ps\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=1922136, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 1970000, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f714f504000
mmap(0x7f714f52a000, 1396736, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000) = 0x7f714f52a000
mmap(0x7f714f67f000, 339968, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17b000) = 0x7f714f67f000
mmap(0x7f714f6d2000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ce000) = 0x7f714f6d2000
mmap(0x7f714f6d8000, 53072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f714f6d8000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f714f501000
arch_prctl(ARCH_SET_FS, 0x7f714f501740) = 0
set_tid_address(0x7f714f501a10)         = 164087
set_robust_list(0x7f714f501a20, 24)     = 0
rseq(0x7f714f502060, 0x20, 0, 0x53053053) = 0
mprotect(0x7f714f6d2000, 16384, PROT_READ) = 0
mprotect(0x55d790bed000, 4096, PROT_READ) = 0
mprotect(0x7f714f72d000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7f714f6e5000, 87170)           = 0
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x2), ...}, AT_EMPTY_PATH) = 0
getrandom("\xc7\xf6\xe3\x84\x6a\xda\x5c\x57", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x55d79226d000
brk(0x55d79228e000)                     = 0x55d79228e000
write(1, "hello world!\n", 13hello world!
)          = 13
exit_group(13)                          = ?
+++ exited with 13 +++

Calling execve runs a program pointed to by the filename in its function argument: open and read are system calls that are used to read files. mmap, mprotect, and brk are responsible for memory activities such as allocation, permissions, and segment boundary setting.

Inside the code of puts, it executes a write system call. writing data to the object it was pointed to. write’s first parameter has a value of 1, denoting STDOUT. The second parameter is the message.

gdb

gdb can be used to show the disassembly of specified functions with the disass command (AT&T syntax):

┌──(kali㉿kali)-[~/Development/C]
└─$ gdb ./hello
GNU gdb (Debian 13.1-2) 13.1
[...]
Reading symbols from ./hello...
(No debugging symbols found in ./hello)
(gdb) disass main
Dump of assembler code for function main:
   0x0000000000001139 <+0>:     push   %rbp
   0x000000000000113a <+1>:     mov    %rsp,%rbp
   0x000000000000113d <+4>:     lea    0xec0(%rip),%rax        # 0x2004
   0x0000000000001144 <+11>:    mov    %rax,%rdi
   0x0000000000001147 <+14>:    call   0x1030 <puts@plt>
   0x000000000000114c <+19>:    nop
   0x000000000000114d <+20>:    pop    %rbp
   0x000000000000114e <+21>:    ret
End of assembler dump.
(gdb) 

To set gdb to use Intel syntax, use:

set disassembly-flavor intel

To place a breakpoint at the main function:

(gdb) b *main
Breakpoint 1 at 0x1139
(gdb) run
Starting program: /home/kali/Development/C/hello 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000555555555139 in main ()
(gdb) 

To get the current values of the registers:

(gdb) info registers
rax            0x555555555139      93824992235833
rbx            0x7fffffffdf38      140737488346936
rcx            0x555555557dd8      93824992247256
rdx            0x7fffffffdf48      140737488346952
rsi            0x7fffffffdf38      140737488346936
rdi            0x1                 1
rbp            0x1                 0x1
rsp            0x7fffffffde28      0x7fffffffde28
r8             0x0                 0
r9             0x7ffff7fcf6a0      140737353938592
r10            0x7ffff7fcb878      140737353922680
r11            0x7ffff7fe18c0      140737354012864
r12            0x0                 0
r13            0x7fffffffdf48      140737488346952
r14            0x555555557dd8      93824992247256
r15            0x7ffff7ffd020      140737354125344
rip            0x555555555139      0x555555555139 <main>
eflags         0x246               [ PF ZF IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
k0             0x40000000          1073741824
k1             0x1400421           20972577
k2             0x0                 0
k3             0x0                 0
k4             0x0                 0
k5             0x0                 0
k6             0x0                 0
k7             0x0                 0
(gdb) 

Now being at main, we can run each instruction with step into (the stepi (si) command and step over (the nexti (ni) command). Follow this with the info registers command to see what values changed.

(gdb) si
0x000055555555513a in main ()
(gdb) disass
Dump of assembler code for function main:
   0x0000555555555139 <+0>:     push   %rbp
=> 0x000055555555513a <+1>:     mov    %rsp,%rbp
   0x000055555555513d <+4>:     lea    0xec0(%rip),%rax        # 0x555555556004
   0x0000555555555144 <+11>:    mov    %rax,%rdi
   0x0000555555555147 <+14>:    call   0x555555555030 <puts@plt>
   0x000055555555514c <+19>:    nop
   0x000055555555514d <+20>:    pop    %rbp
   0x000055555555514e <+21>:    ret
End of assembler dump.
(gdb) 

The => indicates where the instruction pointer is located.

(gdb) info registers
rax            0x555555555139      93824992235833
rbx            0x7fffffffdf38      140737488346936
rcx            0x555555557dd8      93824992247256
rdx            0x7fffffffdf48      140737488346952
rsi            0x7fffffffdf38      140737488346936
rdi            0x1                 1
rbp            0x1                 0x1
rsp            0x7fffffffde20      0x7fffffffde20
r8             0x0                 0
r9             0x7ffff7fcf6a0      140737353938592
r10            0x7ffff7fcb878      140737353922680
r11            0x7ffff7fe18c0      140737354012864
r12            0x0                 0
r13            0x7fffffffdf48      140737488346952
r14            0x555555557dd8      93824992247256
r15            0x7ffff7ffd020      140737354125344
rip            0x55555555513a      0x55555555513a <main+1>
eflags         0x246               [ PF ZF IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
k0             0x40000000          1073741824
k1             0x1400421           20972577
k2             0x0                 0
k3             0x0                 0
k4             0x0                 0
k5             0x0                 0
k6             0x0                 0
k7             0x0                 0
(gdb) 

radare2

To get the filesize, timestamp, and sha512 hash of the hello world binary file:

┌──(kali㉿kali)-[~/Development/C]
└─$ ls -l hello
-rwxr-xr-x 1 kali kali 15952 Apr 14 06:33 hello
                                                                                                                                                                                                        
┌──(kali㉿kali)-[~/Development/C]
└─$ rahash2 -asha512 hello
hello: 0x00000000-0x00003e4f sha512: 1739c9e1d818fa6f74aaff31373e7ddc4b5fa3d231c0acce02eab96bbce7759300aa7792c015f6d1eb91dcbd535766074eab1575784436a3526b65c980091701                  

rabin2 can extract static information from a file:

┌──(kali㉿kali)-[~/Development/C]
└─$ rabin2 -I hello
arch     x86
baddr    0x0
binsz    13965
bintype  elf
bits     64
canary   false
class    ELF64
compiler GCC: (Debian 12.2.0-9) 12.2.0
crypto   false
endian   little
havecode true
intrp    /lib64/ld-linux-x86-64.so.2
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  AMD x86-64 architecture
nx       true
os       linux
pic      true
relocs   true
relro    partial
rpath    NONE
sanitize false
static   false
stripped false
subsys   linux
va       true

The bintype, class, havecode, and os fields indicate that the file is an executable 64-bit ELF file that runs in Linux. arch, bits, endian, and machine suggest that the file was built with x86 code. In addition, the lang field indicates that the file was compiled from C.

To list imported functions:

┌──(kali㉿kali)-[~/Development/C]
└─$ rabin2 -i hello
[Imports]
nth vaddr      bind   type   lib name
―――――――――――――――――――――――――――――――――――――
1   0x00000000 GLOBAL FUNC       __libc_start_main
2   0x00000000 WEAK   NOTYPE     _ITM_deregisterTMCloneTable
3   0x00001030 GLOBAL FUNC       puts
4   0x00000000 WEAK   NOTYPE     __gmon_start__
5   0x00000000 WEAK   NOTYPE     _ITM_registerTMCloneTable
6   0x00001040 WEAK   FUNC       __cxa_finalize

__libc_start_main is a function that initialises the stack frame, sets up the registers and some data structures, sets up error handling, and then calls the main() function.

To get the ELF header info:

┌──(kali㉿kali)-[~/Development/C]
└─$ rabin2 -H hello
0x00000000  ELF64       0x464c457f
0x00000010  Type        0x0003
0x00000012  Machine     0x003e
0x00000014  Version     0x00000001
0x00000018  Entrypoint  0x00001050
0x00000020  PhOff       0x00000040
0x00000028  ShOff       0x00003690
0x00000030  Flags       0x00000000
0x00000034  EhSize      64
0x00000036  PhentSize   56
0x00000038  PhNum       13
0x0000003a  ShentSize   64
0x0000003c  ShNum       31
0x0000003e  ShrStrndx   30

If only interested in the strings from the data section:

┌──(kali㉿kali)-[~/Development/C]
└─$ rabin2 -z hello
[Strings]
nth paddr      vaddr      len size section type  string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0   0x00002004 0x00002004 12  13   .rodata ascii hello world!

Using the radare2 debugger:

──(kali㉿kali)-[~/Development/C]
└─$ r2 -d hello    
[0x7fd4218f39c0]> 

aaa analyses the code for function calls, flags, references and tries to generate constructive function names:

[0x7fd4218f39c0]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Finding and parsing C++ vtables (avrr)
[x] Skipping type matching analysis in debugger mode (aaft)
[x] Propagate noreturn information (aanr)
[x] Finding function preludes
[x] Enable constraint types analysis for variables

Visual mode allows easy navigation, has a cursor mode for selecting bytes, and offers numerous key bindings to simplify debugger use.

The V command sets the console to visual mode to debug the program while having an interactive view of the registry and the stack. Entering : shows a command console. Pressing Enter takes back to visual mode. To exit from visual mode back to command line, press q.

Radare 2 Visual mode

Getting a password

┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ ls -la         
total 16
drwxr-xr-x 2 kali kali 4096 Apr 15 02:24 .
drwxr-xr-x 4 kali kali 4096 Apr 15 02:24 ..
-rw-r--r-- 1 kali kali 7520 Apr 15 02:23 passcode

The tools need access:

┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ chmod +wx passcode

Static

                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ ls -l passcode
-rw-r--r-- 1 kali kali 7520 Apr 15 02:23 passcode
                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rahash2 -a md5,sha256 passcode
passcode: 0x00000000-0x00001d5f md5: b365e87a6e532d68909fb19494168bed
passcode: 0x00000000-0x00001d5f sha256: 68d6db63b69a7a55948e9d25065350c8e1ace9cd81e55a102bd42cc7fc527d8f
                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rabin2 -I passcode
arch     x86
baddr    0x8048000
binsz    6280
bintype  elf
bits     32
canary   true
class    ELF32
compiler GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
crypto   false
endian   little
havecode true
intrp    /lib/ld-linux.so.2
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  Intel 80386
nx       true
os       linux
pic      false
relocs   true
relro    partial
rpath    NONE
sanitize false
static   false
stripped false
subsys   linux
va       true
                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rabin2 -i passcode
[Imports]
nth vaddr      bind   type   lib name
―――――――――――――――――――――――――――――――――――――
1   0x080483b0 GLOBAL FUNC       printf
2   0x080483c0 GLOBAL FUNC       __stack_chk_fail
3   0x080483d0 GLOBAL FUNC       puts
4   0x00000410 WEAK   NOTYPE     __gmon_start__
5   0x080483e0 GLOBAL FUNC       strlen
6   0x080483f0 GLOBAL FUNC       __libc_start_main
7   0x08048400 GLOBAL FUNC       __isoc99_scanf

                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rabin2 -H passcode
0x00000000  ELF MAGIC   0x464c457f
0x00000010  Type        0x0002
0x00000012  Machine     0x0003
0x00000014  Version     0x00000001
0x00000018  Entrypoint  0x08048420
0x0000001c  PhOff       0x00000034
0x00000020  ShOff       0x00001888
0x00000024  Flags       0x00000000
0x00000028  EhSize      52
0x0000002a  PhentSize   32
0x0000002c  PhNum       9
0x0000002e  ShentSize   40
0x00000030  ShNum       31
0x00000032  ShrStrndx   28
                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rabin2 -z passcode
[Strings]
nth paddr      vaddr      len size section type  string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0   0x000006a0 0x080486a0 16  17   .rodata ascii Enter password: 
1   0x000006b4 0x080486b4 17  18   .rodata ascii Correct password!
2   0x000006c6 0x080486c6 19  20   .rodata ascii Incorrect password!

Dynamic

                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ ls -l passcode
-rw-r--r-- 1 kali kali 7520 Apr 15 02:23 passcode
                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rahash2 -a md5,sha256 passcode
passcode: 0x00000000-0x00001d5f md5: b365e87a6e532d68909fb19494168bed
passcode: 0x00000000-0x00001d5f sha256: 68d6db63b69a7a55948e9d25065350c8e1ace9cd81e55a102bd42cc7fc527d8f
                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rabin2 -I passcode
arch     x86
baddr    0x8048000
binsz    6280
bintype  elf
bits     32
canary   true
class    ELF32
compiler GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
crypto   false
endian   little
havecode true
intrp    /lib/ld-linux.so.2
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  Intel 80386
nx       true
os       linux
pic      false
relocs   true
relro    partial
rpath    NONE
sanitize false
static   false
stripped false
subsys   linux
va       true
                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rabin2 -i passcode
[Imports]
nth vaddr      bind   type   lib name
―――――――――――――――――――――――――――――――――――――
1   0x080483b0 GLOBAL FUNC       printf
2   0x080483c0 GLOBAL FUNC       __stack_chk_fail
3   0x080483d0 GLOBAL FUNC       puts
4   0x00000410 WEAK   NOTYPE     __gmon_start__
5   0x080483e0 GLOBAL FUNC       strlen
6   0x080483f0 GLOBAL FUNC       __libc_start_main
7   0x08048400 GLOBAL FUNC       __isoc99_scanf

                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rabin2 -H passcode
0x00000000  ELF MAGIC   0x464c457f
0x00000010  Type        0x0002
0x00000012  Machine     0x0003
0x00000014  Version     0x00000001
0x00000018  Entrypoint  0x08048420
0x0000001c  PhOff       0x00000034
0x00000020  ShOff       0x00001888
0x00000024  Flags       0x00000000
0x00000028  EhSize      52
0x0000002a  PhentSize   32
0x0000002c  PhNum       9
0x0000002e  ShentSize   40
0x00000030  ShNum       31
0x00000032  ShrStrndx   28
                                                                                                                                                                      
┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ rabin2 -z passcode
[Strings]
nth paddr      vaddr      len size section type  string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0   0x000006a0 0x080486a0 16  17   .rodata ascii Enter password: 
1   0x000006b4 0x080486b4 17  18   .rodata ascii Correct password!
2   0x000006c6 0x080486c6 19  20   .rodata ascii Incorrect password!

Moving to radare2:

$ radare2 -d passcode
glibc.fc_offset = 0x00148
[0xf7eed450]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Finding and parsing C++ vtables (avrr)
[x] Skipping type matching analysis in debugger mode (aaft)
[x] Propagate noreturn information (aanr)
[x] Finding function preludes
[x] Enable constraint types analysis for variables
[0xf7eed450]> s sym.main
[0x0804851b]> VVV
[0x0804851b]>  # int main (char **argv); 

This opens up a graphical representation of the disassembly code blocks from the main function. Scroll down , and ha!, the Correct password! text string:

password

In the 0x80485d3 block, where the Correct password! string is, the message was displayed using puts. Going to that block is a red line from the 0x80485c7 block, in which the value in local_418h was compared to 0x2de (or 734 in decimal format). If equal to 734, the flow goes to the Correct password! block.

There is a loop (blue lines), and to exit the loop, the value at local_414h must be greater than or equal to the value at local_410h. The loop exits to the 0x80485c7 block.

At the 0x8048582 block, both values, at local_418h and local_414h are initialised to 0. These values are compared in the 0x80485b9 block.

In the 0x8048598 block, there are three variables of concern: local_40ch, local_414h, and local_418h. local_414h seems to be a pointer of the data pointed to by local_40c. local_418 starts from 0, and each byte from local_40ch is added.

Now looking at the main block:

password

There are three named functions: printf(), scanf(), and strlen(), and local_40ch is the second parameter for scanf, while the data at the 0x80486b1 address should contain the format expected.

To retrieve the data at 0x80486b1, enter a colon (:), enter s 0x80486b1, then return back to the visual mode. Press q again to view the data:

password

The code likely looks something like this:

    ...
    printf ("Enter password: ");
    scanf ("%s", local_40ch);
    local_410h = strlen(local_40ch);
    if (local_410h != 7)
        puts ("Incorrect password!);
    else
    {
        int local_418h = 0;
        for (int local_414h = 0; local_414h < local_410h; local_414++)
        {
            local_418h += local_40ch[local_414h];
        }
        if (local_418h == 734)
            puts("Correct password!)
    }

The entered password should have a size of 7 characters and the sum of all characters in the password should be equal to 734. The password can be anything, as long as it satisfies these conditions.

┌──(kali㉿kali)-[~/Development/C/passcode]
└─$ ltrace ./passcode 
__libc_start_main(0x804851b, 1, 0xffab2254, 0x8048620 <unfinished ...>
printf("Enter password: ")                                                                            = 16
__isoc99_scanf(0x80486b1, 0xffab1d7c, 0xf7f3cbac, 1Enter password: hiiiiii
)                                                  = 1
strlen("hiiiiii")                                                                                     = 7
puts("Correct password!"Correct password!
)                                                                             = 18
+++ exited (status 0) +++