Hello, World 출력 Shellcode
printf를 이용하여 콘솔에 Hello, World를 출력하는 프로그램은 쉽게 짤 수 있다.
#include
int main()
{
printf("Hello, World");
return 0;
}
windows 시스템에서 printf 함수는 msvcrt.dll에 포함되어 있다. Shellcode를 만들기 위해서 해당라이브러리를 로딩하는 코드를 작성해야 한다. 라이브러리 로딩함수는 LoadLibrary함수를 사용하고, 이 함수는 kernel32.dll에서는 LoadLibraryA로 정의되어 있다.
kernel32.dll은 따로 로딩할 필요가 없으므로, kernel32.dll에 있는 LoadLibraryA위치를 찾으면 된다.
함수의 위치를 찾는 코드는 다음과 같다.
#include
#include
/***************************************
arwin - win32 address resolution program
by steve hanna v.01
vividmachines.com
shanna@uiuc.edu
you are free to modify this code
but please attribute me if you
change the code. bugfixes & additions
are welcome please email me!
to compile:
you will need a win32 compiler with
the win32 SDK
this program finds the absolute address
of a function in a specified DLL.
happy shellcoding!
***************************************/
int main(int argc, char** argv)
{
HMODULE hmod_libname;
FARPROC fprc_func;
printf("arwin - win32 address resolution program - by steve hanna - v.01n");
if(argc < 3)
{
printf("%s n",argv[0]);
exit(-1);
}
hmod_libname = LoadLibrary(argv[1]);
if(hmod_libname == NULL)
{
printf("Error: could not load library!n");
exit(-1);
}
fprc_func = GetProcAddress(hmod_libname,argv[2]);
if(fprc_func == NULL)
{
printf("Error: could find the function in the library!n");
exit(-1);
}
printf("%s is located at 0x%08x in %sn",argv[2],(unsigned int)fprc_func,argv[1]);
}
위 코드로 얻은 kernel32.dll에 있는 LoadLibraryA의 주소는 0x771d395c 이다.
LoadLibraryA 함수는 로드할 dll을 매개변수로 받으므로, 어셈블 코드에서는 이름을 스택에 넣어주면 된다.
같은 방식으로 msvcrt.dll 에 있는 printf함수의 주소를 찾고 어셈블로 콜하면 된다.
콘솔 프로그램은 exit함수를 호출해야 정상 종료가 되므로, msvcrt.dll 에 있는 exit함수의 주소를 찾아서 콜해주면 Hello, World용 어셈블 코드를 얻을 수 있다.
[SECTION .text]
global _start
_start:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
jmp short GetLibrary
LibraryReturn:
pop ecx
mov [ecx + 10], dl
mov ebx, 0x771d395c
push ecx
call ebx
jmp short PrintfFunc
PrintfFuncReturn:
pop ecx
xor edx, edx
mov [ecx+12], dl
push ecx
mov ebx, 0x76c3c5b9
call ebx
xor eax,eax
push eax
mov eax, 0x76c336aa ;exitprocess(exitcode);
call eax
GetLibrary:
call LibraryReturn
db 'msvcrt.dllN'
PrintfFunc:
call PrintfFuncReturn
db 'Hello, WorldN'
이것을 nasm으로 컴파일하고 objdump를 이용하여 기계어 코드를 뽑아낸다. (cygwin에서 작업 혹은 Linux 시스템에서)
nasm -f elf hello.asm; ld -o hello hello.obj; objdump -d hello
objdump 결과
hello: file format pei-i386
Disassembly of section .text:
00401000 <_start>:
401000: 31 c0 xor %eax,%eax
401002: 31 db xor %ebx,%ebx
401004: 31 c9 xor %ecx,%ecx
401006: 31 d2 xor %edx,%edx
401008: eb 26 jmp 401030 <_start+0x30>
40100a: 59 pop %ecx
40100b: 88 51 0a mov %dl,0xa(%ecx)
40100e: bb 5c 39 1d 77 mov $0x771d395c,%ebx
401013: 51 push %ecx
401014: ff d3 call *%ebx
401016: eb 28 jmp 401040 <_start+0x40>
401018: 59 pop %ecx
401019: 31 d2 xor %edx,%edx
40101b: 88 51 0c mov %dl,0xc(%ecx)
40101e: 51 push %ecx
40101f: bb b9 c5 c3 76 mov $0x76c3c5b9,%ebx
401024: ff d3 call *%ebx
401026: 31 c0 xor %eax,%eax
401028: 50 push %eax
401029: b8 aa 36 c3 76 mov $0x76c336aa,%eax
40102e: ff d0 call *%eax
401030: e8 d5 ff ff ff call 40100a <_start+0xa>
401035: 6d insl (%dx),%es:(%edi)
401036: 73 76 jae 4010ae <__DTOR_LIST__+0x54>
401038: 63 72 74 arpl %si,0x74(%edx)
40103b: 2e cs
40103c: 64 fs
40103d: 6c insb (%dx),%es:(%edi)
40103e: 6c insb (%dx),%es:(%edi)
40103f: 4e dec %esi
401040: e8 d3 ff ff ff call 401018 <_start+0x18>
401045: 48 dec %eax
401046: 65 gs
401047: 6c insb (%dx),%es:(%edi)
401048: 6c insb (%dx),%es:(%edi)
401049: 6f outsl %ds:(%esi),(%dx)
40104a: 2c 20 sub $0x20,%al
40104c: 57 push %edi
40104d: 6f outsl %ds:(%esi),(%dx)
40104e: 72 6c jb 4010bc <__DTOR_LIST__+0x62>
401050: 64 fs
401051: 4e dec %esi
00401052 <__CTOR_LIST__>:
401052: ff (bad)
401053: ff (bad)
401054: ff (bad)
401055: ff 00 incl (%eax)
401057: 00 00 add %al,(%eax)
...
0040105a <__DTOR_LIST__>:
40105a: ff (bad)
40105b: ff (bad)
40105c: ff (bad)
40105d: ff 00 incl (%eax)
40105f: 00 00 add %al,(%eax)
...
_start 부분만 16진수로 얻은 코드를 테스트 해보면 정상적으로 실행이 된다.
char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xeb\x26\x59\x88\x51\x0a\xbb\x5c\x39\x1d\x77\x51\xff\xd3\xeb\x28\x59\x31\xd2\x88\x51\x0c\x51\xbb\xb9\xc5\xc3\x76\xff\xd3"
"\x31\xc0\x50\xb8\xaa\x36\xc3\x76\xff\xd0\xe8\xd5\xff\xff\xff\x6d\x73\x76\x63\x72\x74\x2e\x64\x6c\x6c\x4e\xe8\xd3\xff\xff\xff"
"\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x4e";
int main(int argc, char **argv)
{
int *code;
code = (int *)shellcode;
__asm {
jmp code;
}
return 0;
}
[참고자료]
http://www.vividmachines.com/shellcode/shellcode.html