ㅇ예제는 저번에 사용했던 reverse.asm 을 사용하고
1. reverse(스택)
-문자 배열
C언어
int main()
{
char buffer[1024]={0,};
int len = 0;
printf("input:");
gets(buffer);
while (buffer[len] != 0) {
len++;
}
len --;
while(len>=0){
printf("c",buffer[len]);
len--;
}
printf("\n");
return 0;
}
어셈블리 언어
extern printf
extern gets
segment .data
prompt1 db 'input:',00
prompt2 db '%c',00
prompt3 db 10,00
prompt4 db '%s',10,00
segment .text
global main
main:
push ebp
mov ebp, esp
sub esp, 1028
mov ecx, 256
xor eax, eax
lea edi, [ebp-1024]
rep stosd
mov dword [ebp-1028], 0
push prompt1
call printf
add esp, 4
lea eax, [ebp-1024]
;mov eax, ebp
;sub eax, 1024
push eax
call gets
add esp, 4
while1:
mov ebx, dword [ebp-1028]
cmp byte [ebp-1024 + ebx * 1], 0
je .end
inc dword [ebp-1028]
jmp while1
.end:
dec dword [ebp-1028]
while2:
mov ebx, dword [ebp-1028]
cmp ebx, 0
jl .end
movzx eax, byte [ebp-1024 + ebx * 1]
push eax
push prompt2
call printf
add esp, 8
dec dword [ebp-1028]
jmp while2
.end
push prompt3
call printf
add esp, 4
xor eax, eax
leave
ret
배열의 시작주소는 지정된 크기중 가장 낮은 주소에 위치한다.
처음 부터 확인해 보면
push ebp
mov ebp, esp
sub esp, 1028
프롤로그 함수와 변수 2개의 공간을 확보한다.
그림으로 확인해 보면
len 시작 위치는 dword [ebp-1028]
1024 buffer buffer 시작위치는 byte [ebp-1024]
saved ebp
saved eip
배열의 시작주소는 지정된 크기중 가장 낮은 주소에 위치한다.
배열이 시작하는 위치를 알아야 불러오는게 가능하다
byte [ebp-1024]
byte [ebp-1023]
byte [ebp-1022]
byte [ebp-1021]
지역변수는 꼭 초기화로 해주어야 한다.
stack은 여러 프로그램이 사용하기 때문에 꼭 초기화 해주어야한다.
배열의 크기가 작을때는
mov dword [ebp-1024], 0
mov dword [ebp-1020], 0
...
이런식으로 초기화 해준다.
mov ecx, 256
xor eax, eax
lea edi, [ebp-1024]
rep stosd
ecx 카운터
edi 목적지 주소
한칸에 4바이트씩 구성되어 있기 때문에 256 번 반복을 해서 ecx에 256을 대입하고
eax 를 xor을 이용해서 초기화 시켜준다
lea edi, [ebp-1024]
배열의 시작 주소인 [ebp-1024] 를 edi에 저장한다
edi는 목적지 주소이다
rep stosd 반복한다
그렇치 않으면 ESI, EDI:STOS, LORD, REP ... 레지스터를 이용해서 초기화 한다.
extern printf
extern gets
초기화 하는 방법
char buffer[1024]={0,};
main:
push ebp
mov ebp, esp
sub esp, 1028
mov ecx, 1024
xor eax, eax
mov al, 65
lea edi, [ebp-1024]
rep stosb
lea eax, [ebp-1024]
push eax
push prompt4
call printf
add esp, 8
leave
ret
;mov edi, [ebp-1024] //메모리의 값을 가지고온다.
lea edi, [ebp-1024] //[]있다고 메모리가 아닌 주소의 값을 가지고온다.
mov dword [ebp-1028], 0
의미 : OPER2의 내용을 OPER1에 복사한다. 이때, 확장되고 채워지지 않는 나머지 비트(공간)를 '0'으로 채운다.
위 MOV 같은 경우는 OPER1과 OPER2의 사이즈가 동일하여야지 가능하다. 하지만 이 명령어는 두 OPER 간의 사이즈가 다를 경우 사용된다. 기본적으로, 복사하는 곳의 사이즈가 OPER1의 사이즈가 OPER2의 사이즈보다 커야한다. 때문에, MOVZ'X'의 'X'가 확장의 의미이다.
2. 배열의 총합(스택)
-숫자 배열
-int sum(int *array, int len);
1), C 언어
[ebp+8] [ebp+12]
int sum(int *array, int len)
{
int sum=0; [ebp-4]
len --;
for( ; len > 0; len--){
sum = sum + array[len];
}
return sum;
}
int main( )
{
int array[ ]={10,20,30,40,50};
int result = 0;
result = sum( array,5 );
printf("sum:%d\n",result);
return 0;
}
2). 어셈블리
extern printf
segment .data
prompt db 'sum:%d',10,00
segment .text
global main
sum:
push ebp
mov ebp, esp
sub esp, 4
mov dword [ebp-4], 0
dec dword [ebp+12]
for:
mov ebx, dword [ebp+12]
cmp ebx, 0
jl end
mov edx, dword [ebp+8]
mov eax, [ edx + ebx *4 ]
add dword [ebp-4],eax
dec dword [ebp+12]
jmp for
end:
mov eax, dword [ebp-4]
leave
ret
main:
push ebp
mov ebp, esp
sub esp, 24
mov dword [ebp-4], 10
mov dword [ebp-8], 20
mov dword [ebp-12], 30
mov dword [ebp-16], 40
mov dword [ebp-20], 50
mov dword [ebp-24], 0
push 5
lea eax, [ebp-20]
push eax
call sum
add esp, 8
mov dword [ebp-24],eax
push dword [ebp-24]
push prompt
call printf
add esp, 8
xor eax, eax
leave
ret
이것도 하나하나 분석해보면
main:
push ebp
mov ebp, esp
sub esp, 24
배열 20바이트에 result 4 바이트해서 총 24 바이트 값을 확보한다
배열이 초기화가 되어 있는 경우에는 반복문으로 입력하는게 아니라 하나하나 입력해준다
mov dword [ebp-4], 10
mov dword [ebp-8], 20
mov dword [ebp-12], 30
mov dword [ebp-16], 40
mov dword [ebp-20], 50
mov dword [ebp-24], 0
배열의 시작 위치는 ebp-20 이고
시작부터 반대로 대입시켜 준다 50,40,30,20,10 순서대로 초기화 시켜주고
dword [ebp-24] result 값을 0으로 초기화 시켜준다
이제 sum 함수를 출력하는데
result = sum( array,5 );
push 5
lea eax, [ebp-20]
push eax
뒤에서 부터 입력하고 call 해주어야 한다
우선 숫자 값인 5를 push 하고 array의 시작 주소인 [ebp-20] 를 eax에 넣고 push 시켜준다.
call sum
add esp, 8
이제 sum 함수를 호출 시켜주고 push push 에 대한 esp 메모리를 회수한다
call 함수는
push eip +jmp sum = call sum
복귀 주소인 eip를 저장하고 jmp sum 하는 의미를 가지고 있다
sum:
push ebp
mov ebp, esp
sub esp, 4
mov dword [ebp-4], 0
dec dword [ebp+12]
for:
mov ebx, dword [ebp+12]
cmp ebx, 0
jl end
mov edx, dword [ebp+8]
mov eax, [ edx + ebx *4 ]
add dword [ebp-4],eax
dec dword [ebp+12]
jmp for
end:
mov eax, dword [ebp-4]
leave
ret
sum 함수로 와서 보면
int sum=0;
지역 변수가 있으니까 프롤로그 하고 sub 4 로 공간을 확보 했다
mov dword [ebp-4], 0
dec dword [ebp+12]
sum 변수 값을 초기화 시켜주고
push 5 값인 ebp+12 를 1 감소 시켜준다.
mov ebx, dword [ebp+12]
cmp ebx, 0
jl end
mov edx, dword [ebp+8]
mov eax, [ edx + ebx *4 ]
add dword [ebp-4],eax
dec dword [ebp+12]
jmp for
이제 위에 했던거 처럼 반복문을 수행하고 main으로 리턴 시켜준다
'시스템 해킹' 카테고리의 다른 글
[시스템 해킹] 시스템 콜 (0) | 2018.01.27 |
---|---|
[시스템 해킹] main 함수의 인자 (0) | 2018.01.27 |
[시스템 해킹] 어셈블리 함수 표현 (Stack) (0) | 2018.01.23 |
[시스템 해킹] 어셈블리 반복문 (0) | 2018.01.18 |
[시스템 해킹] 어셈블리 형변환, 분기문 (0) | 2018.01.17 |