'공부/리버싱'에 해당하는 글 11건

32비트 cpu일떄는 함수 호출규약이 여러개 있었지만

64비트로올라오면서 한개로 통합이 되었다

기존 fastcall(함수의 인자가 레지스터로 전달되는방식)호출규약을 이용한다.


64비트 레지스터로는 기존의 레지스터에서 확장된 레지스터를 사용하고(rax, rbx ,rsp등등..)

8개의 레지스터가 추가되었다 (r8~r15)


스택프레임

다음과 같은 C코드를 짠다고 했을 떄

1
2
3
4
5
6
7
8
9
long myfunc(long a, long b, long c, long d,
            long e, long f, long g, long h)
{
    long xx = a * b * c * d * e * f * g * h;
    long yy = a * b * c * d * e * f * g * h;
    long zz = utilfunc(xx, yy, xx % yy);
    return zz + 20;
}
            


다음과 같은 모양에 스택프레임이 형성이 된다


함수를 호출할 때 최초 6개의 정수나 포인터 인자의 경우에는 RDI, RSI, RDX, RCX, R8, R9 에 순서대로

넘겨지게 되고, 더 많은 숫자의 인자가 들어오게 된다면 스태을 통해 전달되게 된다.

실수 인자는 xmm0~xmm7까지 총 8개를 순서대로 사용하고 8개가 넘어갈시 스택을 통해 전달된다.

리턴값은 rax, rdx를 사용한다.


근데 x86 스택프레임에서는 볼 수 없었던 red zone이 생기게 된다.

AMD ABI에 정의된 바로는



원문

The 128-byte area beyond the location pointed to by %rsp is considered to be reserved and shall not be modified by signal or interrupt handlers. Therefore, functions may use this area for temporary data that is not needed across function calls. In particular, leaf functions may use this area for their entire stack frame, rather than adjusting the stack pointer in the prologue and epilogue. This area is known as the red zone.


발번역

%rsp가 가르키는 128byte의 공간(red zone)은 예비로 놔둔 공간이고  signal이나 인터럽트 핸들러를통해 변경되지 않습니다.

그러므로 함수 호출간에 보존될 필요가 없는 휘발성 데이터들이 이공간을 사용하게 됩니다.

특별히 말단함수(leaf function 다른 함수들을 호출하지 않는 함수들)들은 스택 포인터를 프롤로그와 에필로그로 조정하기 보다는 이 공간을 스택프레임 전체로 쓰기도 합니다.


간단하게 말하자면 red zone은 최적화라 볼 수 있다.

rsp아래 128byte가 시그널이나 인터럽트 핸들러를 통해 변경되지 않는다는 것을 안다면

http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/





저작자 표시 비영리 동일 조건 변경 허락
신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

x64 stack frame  (0) 2014.08.12
reversing.kr replace  (0) 2014.08.11
assem 분석 2  (0) 2014.05.12
리버싱문제 패스워드 숨기기  (0) 2014.05.06
assem 분석 1  (1) 2014.05.05
upx 언패킹 성공  (0) 2013.09.12

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
 
using namespace std;
 
int main(int argc, char * argv[])
{
    unsigned int adr = 0x601605c7;
    unsigned int i=0;
 
    adr+= 5;
    while(adr+i != 0x00401072)
    {
        i++;
    }
    cout << hex << adr+i <<endl;
    cout << hex << i <<endl;
    cout<< dec << i <<endl;
}

replace풀이

입력값을 받는다

0x601605c7을 더한다

+4 +5한지점을 nop처리 한다

nop해야할 지점은 congretulation을 하는부분을 막는 short jmp(2byte)

그래서 그지점을 구하는 위의 코드를 짜고

10초정도 기다리면 clear

저작자 표시 비영리 동일 조건 변경 허락
신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

x64 stack frame  (0) 2014.08.12
reversing.kr replace  (0) 2014.08.11
assem 분석 2  (0) 2014.05.12
리버싱문제 패스워드 숨기기  (0) 2014.05.06
assem 분석 1  (1) 2014.05.05
upx 언패킹 성공  (0) 2013.09.12

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

assem 분석 2

공부/리버싱 2014.05.12 02:18

http://www.hackerschool.org/HS_Boards/data/Lib_system/binary1.txt


혼자 공부하는거라 틀릴수도 있습니다


for문 ---------------------------------------------------- 0x8048460 <main>: push %ebp // 베이스 포인트 0x8048461 <main+1>: mov %esp,%ebp //현재 스택상태 복사 0x8048463 <main+3>: sub $0x8,%esp // 스택 확장 0x8048466 <main+6>: nop //아무것도 안함 0x8048467 <main+7>: movl $0x1,0xfffffffc(%ebp) // ebp에 1 (여기서는 변수 i) 0x804846e <main+14>: mov %esi,%esi 0x8048470 <main+16>: cmpl $0x9,0xfffffffc(%ebp) //9와 i를 비교 0x8048474 <main+20>: jle 0x8048478 <main+24> // 9가 i보다 작거나 같다면 0x8048476 <main+22>: jmp 0x8048494 <main+52> //0x8048494로 점프 0x8048478 <main+24>: sub $0x8,%esp    //스택확장 0x804847b <main+27>: pushl 0xfffffffc(%ebp) //i의 주소를 스택에 push 0x804847e <main+30>: push $0x8048508 // %d\t의 주소를 push 0x8048483 <main+35>: call 0x804833c <printf> //프린트 호출 0x8048488 <main+40>: add $0x10,%esp //스택정리 0x804848b <main+43>: lea 0xfffffffc(%ebp),%eax // eax값은 i 0x804848e <main+46>: incl (%eax) //eax ++ 0x8048490 <main+48>: jmp 0x8048470 <main+16> //main+16으로 점프 0x8048492 <main+50>: mov %esi,%esi 0x8048494 <main+52>: leave 0x8048495 <main+53>: ret //프로그램 종료 0x8048496 <main+54>: mov %esi,%esi 0x8048508 <_IO_stdin_used+4>: "%d\t" main() { int i; for(i = 1; i < 10; i++) printf("%d\t",i); } ---------------------------------------------------- 0x8048460 <main>: push %ebp 0x8048461 <main+1>: mov %esp,%ebp 0x8048463 <main+3>: sub $0x8,%esp //스택확장 0x8048466 <main+6>: movl $0x1,0xfffffffc(%ebp)

//1을 0xfffffffc에 집어 넣음    int i=1; 0x804846d <main+13>: movl $0xa,0xfffffff8(%ebp) //10을 0xfffffff8에 집어 넣음 int j = 10;

0x8048474 <main+20>: mov 0xfffffffc(%ebp),%eax

0xfffffffc를 eax에 이동    

0x8048477 <main+23>: cmp 0xfffffff8(%ebp),%eax

j와 i를 비교

0x804847a <main+26>: jle 0x8048480 <main+32> 0x804847c <main+28>: jmp 0x804849c <main+60>

j가 i보다 작거나 같으면 점프


0x804847e <main+30>: mov %esi,%esi 0x8048480 <main+32>: sub $0x8,%esp    //스택확장 0x8048483 <main+35>: lea 0xfffffffc(%ebp),%eax

eax 주소값을 0xffffffffc에 복사 0x8048486 <main+38>: push %eax //스택에 넣기 0x8048487 <main+39>: push $0x8048508 //스택에 넣기 0x804848c <main+44>: call 0x804833c <printf> //프린트 0x8048491 <main+49>: add $0x10,%esp //스택정리 0x8048494 <main+52>: lea 0xfffffffc(%ebp),%eax 0xffffffc의 주소를 eax에 복사 0x8048497 <main+55>: incl (%eax) eax++; 0x8048499 <main+57>: jmp 0x8048474 <main+20> //main+20으로 점프

0x804849b <main+59>: nop 0x804849c <main+60>: leave 0x804849d <main+61>: ret 0x804849e <main+62>: mov %esi,%esi main() { int i,j; i = 1; j = 10; for( ; i <= j ; i++) printf("%d\n",&i); } ---------------------------------------------------- 0x8048460 <main>: push %ebp 0x8048461 <main+1>: mov %esp,%ebp 0x8048463 <main+3>: sub $0x8,%esp //스택확장 0x8048466 <main+6>: nop 0x8048467 <main+7>: movl $0xa,0xfffffffc(%ebp) // 0x804846e <main+14>: mov %esi,%esi 0x8048470 <main+16>: cmpl $0x0,0xfffffffc(%ebp) 0x8048474 <main+20>: jg 0x8048478 <main+24> 0x8048476 <main+22>: jmp 0x8048494 <main+52> 0x8048478 <main+24>: sub $0x8,%esp 0x804847b <main+27>: pushl 0xfffffffc(%ebp) 0x804847e <main+30>: push $0x8048508 0x8048483 <main+35>: call 0x804833c <printf> 0x8048488 <main+40>: add $0x10,%esp 0x804848b <main+43>: lea 0xfffffffc(%ebp),%eax 0x804848e <main+46>: decl (%eax) 0x8048490 <main+48>: jmp 0x8048470 <main+16> 0x8048492 <main+50>: mov %esi,%esi 0x8048494 <main+52>: leave 0x8048495 <main+53>: ret 0x8048496 <main+54>: mov %esi,%esi main() { int i; for(i = 10; i > 0 ; i--) printf("%d\n",i); } ------------------------------------------------------------- 0x8048460 <main>: push %ebp 0x8048461 <main+1>: mov %esp,%ebp 0x8048463 <main+3>: sub $0x8,%esp 0x8048466 <main+6>: nop 0x8048467 <main+7>: movl $0xa,0xfffffffc(%ebp) 0x804846e <main+14>: mov %esi,%esi 0x8048470 <main+16>: cmpl $0x0,0xfffffffc(%ebp) 0x8048474 <main+20>: jns 0x8048478 <main+24> 0x8048476 <main+22>: jmp 0x8048494 <main+52> 0x8048478 <main+24>: sub $0x8,%esp 0x804847b <main+27>: pushl 0xfffffffc(%ebp) 0x804847e <main+30>: push $0x8048508 0x8048483 <main+35>: call 0x804833c <printf> 0x8048488 <main+40>: add $0x10,%esp 0x804848b <main+43>: lea 0xfffffffc(%ebp),%eax 0x804848e <main+46>: decl (%eax) 0x8048490 <main+48>: jmp 0x8048470 <main+16> 0x8048492 <main+50>: mov %esi,%esi 0x8048494 <main+52>: leave 0x8048495 <main+53>: ret 0x8048496 <main+54>: mov %esi,%esi main() { int i; for(i = 10; i >= 0 ; i--) printf("%d\n",i); } ==================================================================== 단일for문&비교문 정리 +------------------------------------------------------------------+ | nop | | int i = n; movl $0xn, 0xfffffffc(%ebp) | | mov %esi, %esi | | for(i = n ; i < k ; i++) cmpl $0xk-1,0xfffffffc(%ebp) | | jle 0x0804....(for문 안으로) | | jmp 0x0804....(for문 밖으로) | | for문안에 있는 내용 | | lea 0xfffffffc(%ebp),%eax | | lncl (%eax) | | jmp 0x0804....(for문 처음으로) | | mov %esi, %esi | +------------------------------------------------------------------+ | nop | | int i=1, movl $0x1,0xfffffffc(%ebp) | | j=10; movl $0xa,0xfffffff8(%ebp) | | mov 0xfffffffc(%ebp),%eax | | for(i = 1 ; i <= 10 ; i++) cmpl 0xfffffff8(%ebp),%eax | | jle 0x0804....(for문 안으로) | | jmp 0x0804....(for문 밖으로) | | for문안에 있는 내용 | | lea 0xfffffffc(%ebp),%eax | | lncl (%eax) | | jmp 0x0804....(for문 처음으로) | | mov %esi, %esi | +------------------------------------------------------------------+ | nop | | int i = k; movl $0xk, 0xfffffffc(%ebp) | | mov %esi, %esi | | for(i = k ; i > n ; i--) cmpl $0xn, 0xfffffffc(%ebp) | | jg 0x0804....(for문 안으로) | | jmp 0x0804....(for문 밖으로) | | for문안에 있는 내용 | | lea 0xfffffffc(%ebp), %eax | | decl (%eax) | | jmp 0x0804....(for문 처음으로) | | mov %esi, %esi | +------------------------------------------------------------------+ | nop | | int i = 10; movl $0xa,0xfffffffc(%ebp) | | mov %esi, %esi | | for(i = k ; i >= n ; i--) cmpl $0xn, 0xfffffffc(%ebp) | | jns 0x0804....(for문 안으로) | | jmp 0x0804....(for문 밖으로) | | for문안에 있는 내용 | | lea 0xfffffffc(%ebp), %eax | | decl (%eax) | | jmp 0x0804....(for문 처음으로) | | mov %esi, %esi | +------------------------------------------------------------------+ ===================================================================== -------------------------------------------------------------


저작자 표시 비영리 동일 조건 변경 허락
신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

x64 stack frame  (0) 2014.08.12
reversing.kr replace  (0) 2014.08.11
assem 분석 2  (0) 2014.05.12
리버싱문제 패스워드 숨기기  (0) 2014.05.06
assem 분석 1  (1) 2014.05.05
upx 언패킹 성공  (0) 2013.09.12

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

그냥 패스워드를 main안에서 배열로 지정할경우

int main()

{

char pw [] = "password";

~~~~주저리

}

code segment 에 소스와 같이 올라가기 떄문에 핵스 덤프만 떠도 패스워드가 나와버림

E.g. (dumpbin /RAWDATA:BYTES /SECTION:.data simple.exe >filename)


하지만 #pragma를 이용해 data segment에 있는 .bbs(비초기화 데이터 영역)에

올릴경우 핵스덤프를 해도 바로 나오지 않는다.

E.g.

int count=0;
// From now on, all the initialized variables will be
// located in the .kpnc section.
#pragma data_seg (."kpnc")
// Note that the period before the name
// isn't mandatory, just customary.
char passwd[ ]=PASSWORD;
#pragma data_seg ()
// Now all the initialized variables will again
// be located in the section by default (i.e., ."data").
char buff [PASSWORD_SIZE]=" ";
...
if (strcmp(&buff[0] , &passwd[0]))
> dumpbin /RAWDATA:BYTES /SECTION: .data simple2.exe >filename
RAW DATA #3
00406000: 00 00 00 00 00 00 00 00 00 00 00 00 45 11 40 00 ............E.@.
00406010: 04 41 40 00 00 00 00 00 00 00 00 00 40 12 40 00 .A@.........@.@.
00406020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00406030: 45 6E 74 65 72 20 70 61 73 73 77 6F 72 64 3A 00 Enter password:.
00406040: 57 72 6F 6E 67 20 70 61 73 73 77 6F 72 64 0A 00 Wrong password..
00406050: 50 61 73 73 77 6F 72 64 20 4F 4B 0A 00 00 00 00 Password OK.....
00406060: 20 6E 40 00 00 00 00 00 20 6E 40 00 01 01 00 00 n@..... n@......
00406070: 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 ................




신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

reversing.kr replace  (0) 2014.08.11
assem 분석 2  (0) 2014.05.12
리버싱문제 패스워드 숨기기  (0) 2014.05.06
assem 분석 1  (1) 2014.05.05
upx 언패킹 성공  (0) 2013.09.12
펌 리버싱을 위한 어셈정리  (0) 2013.08.13

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

assem 분석 1

공부/리버싱 2014.05.05 18:09

http://www.hackerschool.org/HS_Boards/data/Lib_system/binary1.txt

요고 보면서 정리중

Asm.pdf

이건 기본적인 어셈이 정리되어있는문서

+

http://download.intel.com/design/processor/manuals/253665.pdf

Intel® 64 and IA-32 Architectures Software Developer’s Manual V1 3장부터 보면 됩니다



개인적으로 정리하는 글입니다.

틀린부분이 있을 수 있습니다


if문


0x8048460 <main>: push %ebp // 스택 밑바닥 0x8048461 <main+1>: mov %esp,%ebp //현재 스택위치 표시 0x8048463 <main+3>: sub $0x8,%esp //스택 8byte확장 0x8048466 <main+6>: cmpl $0x1,0x8(%ebp) //1과 argc비교 0x804846a <main+10>: jg 0x8048478 <main+24> 1보타 argc가 클경우 jmp if(argc < 2) 0x804846c <main+12>: sub $0xc,%esp 0x804846f <main+15>: push $0x0 //스택에 0 push 0x8048471 <main+17>: call 0x8048348 <exit>//exit호출 0x8048476 <main+22>: mov %esi,%esi exit(0); 0x8048478 <main+24>: leave 0x8048479 <main+25>: ret //main 종료 0x804847a <main+26>: mov %esi,%esi


#include<stdio.h>

int main(int argc, char *argv)
{
        if(argc < 2) 
		exit(0);
}



0x8048460 <main>: push %ebp 0x8048461 <main+1>: mov %esp,%ebp 0x8048463 <main+3>: sub $0x8,%esp 0x8048466 <main+6>: cmpl $0x2,0x8(%ebp) //2와 argc비교 0x804846a <main+10>: jg 0x8048478 <main+24> //argc가 더 클경우 점프 if(argc <= 2 ) 0x804846c <main+12>: sub $0xc,%esp 0x804846f <main+15>: push $0x1 //1 push 0x8048471 <main+17>: call 0x8048348 <exit> // exit(1) (exit(0)과 다른점은 오류종료라는 점) 0x8048476 <main+22>: mov %esi,%esi 0x8048478 <main+24>: leave 0x8048479 <main+25>: ret //main의 끝 0x804847a <main+26>: mov %esi,%esi main(int argc, char *argv[]) { if(argc <= 2) exit(1); }


0x8048490 <main>: push %ebp 0x8048491 <main+1>: mov %esp,%ebp 0x8048493 <main+3>: sub $0x8,%esp 0x8048496 <main+6>: cmpl $0x2,0x8(%ebp)//2와 argc비교 0x804849a <main+10>: jle 0x80484a8 <main+24> // 작거나 같을때 점프 // if(argc > 2) 0x804849c <main+12>: sub $0xc,%esp 0x804849f <main+15>: push $0x0 0x80484a1 <main+17>: call 0x804837c <exit>//종료 0x80484a6 <main+22>: mov %esi,%esi // exit(0); 0x80484a8 <main+24>: sub $0xc,%esp 0x80484ab <main+27>: push $0x8048528 // "Input Arg\n" 문자열 주소 push 0x80484b0 <main+32>: call 0x804835c <printf> //프린트 0x80484b5 <main+37>: add $0x10,%esp //스택 축소 // printf("Input Arg\n"); 0x80484b8 <main+40>: leave 0x80484b9 <main+41>: ret //정리 0x80484ba <main+42>: mov %esi,%esi (gdb) x/s 0x8048528 0x8048528 <_IO_stdin_used+4>: "Input Arg\n" main(int argc, char *argv[]) { if(argc > 2) exit(0); printf("Input Arg\n"); }



0x8048460 <main>: push %ebp 0x8048461 <main+1>: mov %esp,%ebp 0x8048463 <main+3>: sub $0x8,%esp //int i 와 비교값을 위한 스택 확장 0x8048466 <main+6>: cmpl $0x1,0xfffffffc(%ebp)//비교 0x804846a <main+10>: jle 0x804847c <main+28>//1보다 작거나 같으면 점프 0x804846c <main+12>: sub $0xc,%esp 0x804846f <main+15>: push $0x80484e8 //문자열 push 0x8048474 <main+20>: call 0x804833c <printf> //문자역 출력 0x8048479 <main+25>: add $0x10,%esp //스택 정리 0x804847c <main+28>: leave 0x804847d <main+29>: ret //main정리 0x804847e <main+30>: mov %esi,%esi 0x80484e8 <_IO_stdin_used+4>: "I >=2\n" main() { int i; if(i >= 2) printf("I >=2\n"); }



0x8048490 <main>: push %ebp 0x8048491 <main+1>: mov %esp,%ebp 0x8048493 <main+3>: sub $0x8,%esp //argc argv확장 0x8048496 <main+6>: cmpl $0x2,0x8(%ebp) //2와 argc비교 0x804849a <main+10>: jne 0x80484a8 <main+24> argc와 2가 같지 않을경우 jmp 0x804849c <main+12>: sub $0xc,%esp 0x804849f <main+15>: push $0x0 //스택에 0 push 0x80484a1 <main+17>: call 0x804837c <exit> // 종료 0x80484a6 <main+22>: mov %esi,%esi 0x80484a8 <main+24>: sub $0xc,%esp 0x80484ab <main+27>: push $0x8048528 //문자열 push 0x80484b0 <main+32>: call 0x804835c <printf> // 문자열 print 0x80484b5 <main+37>: add $0x10,%esp //스택정리 0x80484b8 <main+40>: leave 0x80484b9 <main+41>: ret//프로그램 종료 0x80484ba <main+42>: mov %esi,%esi main(int argc, char *argv[]) { if(argc == 2) exit(0); printf("Input Arg\n"); }



저작자 표시 비영리
신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

assem 분석 2  (0) 2014.05.12
리버싱문제 패스워드 숨기기  (0) 2014.05.06
assem 분석 1  (1) 2014.05.05
upx 언패킹 성공  (0) 2013.09.12
펌 리버싱을 위한 어셈정리  (0) 2013.08.13
crackme3-abexcm3  (0) 2013.08.06

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글 하나 달렸습니다.
  1. 아 지금보니깐 cdecl형식이구나
secret

짱해커 분들이 보면 코웃음 칠 글이지만 드디어 upx에 언패킹에 성공했다

64bit 환경에서 계속 시도했으나 실패

이유는 iat 리커버리중 계속 오류가 떳다

그래서 vm 환경에서 xp 32bit에서 리커버리 시도

성공했다 ㅎㅎ

신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

리버싱문제 패스워드 숨기기  (0) 2014.05.06
assem 분석 1  (1) 2014.05.05
upx 언패킹 성공  (0) 2013.09.12
펌 리버싱을 위한 어셈정리  (0) 2013.08.13
crackme3-abexcm3  (0) 2013.08.06
crackme2-abexcm2  (0) 2013.07.19

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

1.어셈블리어
Push  : sp 레지스터를 조작하는 명령어중의 하나이다.
       스택에 데이터를 저장하는데 쓰인다.
ex:) Push eax : 스택에 Eax의 값을 스택에 저장한다.
ex:) Push 20 :즉석값인 20을 스택에 저장한다.
ex:) Push 401F47 : 메모리 오프셋 401F47의 값을 스택에 저장한다.

Pop  : 이또한 sp 레지스터를 조작하는 명령어중 하나이다.
스택에서 데이터를 꺼내는데 쓰인다.
ex:) Pop eax :스택에 가장 상위에 있는 값을 꺼내애서 eax에 저장한다.
주의점 : Push 의 역순으로 값은 스택에서 Pop 된다.

Mov  : 메모리나 레지스터의 값을 옮길 때[로 만들 때]쓰인다.
ex:) Mov eax,ebx    :ebx 레지스터의 값을 eax로 옮긴다[로 만든다].
ex:) Mov eax,20     :즉석값인 20을 eax레지스터 에 옮긴다[로 만든다].
ex:) Mov eax,dword ptr[401F47]   :메모리 오프셋 401F47 의 값을 eax에 옮긴다[로 만든다]

Lea  : 오퍼렌드1의 값을 오퍼렌드2의 값으로 만들어준다.
ex:) Lea eax,ebx    : eax레지스터의 값을 ebx의 값으로 만든다.

Inc  : 레지스터의 값을 1증가 시킨다.
ex:) Inc eax  : Eax 레지스터의 값을 1증가 시킨다.
Dec  : 레지스터의 값을 1 감소 시킨다.
ex:) Dec eax : Eax 레지스터의 값을 1 감소 시킨다.

Add  : 레지스터나 메모리의 값을 덧셈할떄 쓰임.
ex:) Add eax,ebx   :Eax 레지스터의 값에 ebx 값을 더한다.
ex:) Add eax,50    :Eax 레지스터에 즉석값인 50을 더한다.
ex:) Add eax,dword ptr[401F47]  : Eax 레지스터에 메모리 오프셋 401F47의 값을 더한다.
Sub  : 레지스터나 메모리의 값을 뻇셈할떄 쓰임.
ex:) Sub eax,ebx   : Eax 레지스터에서 ebx 레지스터의 값을 뺸다.
ex:) Sub eax,50
Eax  : 레지스터에서 즉석값 50을 뺸다.
ex:) Sub eax,dword ptr[401F47]    :Eax 레지스터에서 메모리 오프셋 401F47의 값을 뺸다.
Nop  : 아무동작도 하지 않는다. : 90
Call : 프로시저를 호출할떄 쓰인다.
ex:) Call dword ptr[401F47]    : 메모리 오프셋 401F47을 콜한다.
Ret : 콜한 지점으로 돌아간다.
Cmp : 레지스터와 레지스터혹은 레지스터 값을 비교하기위하여 쓰인다.
ex:) Cmp eax,ebx    :Eax 레지스터와 Ebx 레지스터의 값을 비교한다.
ex:) Cmp eax,50     :Eax 레지스터와 즉석값 50을 비교한다.
ex:) Cmp eax,dword ptr[401F47]
:Eax 레지스터와 메모리 오프셋 401F47의 값을 비교한다.
Jmp : 특정한 메모리 오프셋으로 이동할떄 쓰인다.
ex:) Jmp dword ptr[401F47]   :메모리 오프셋 401F47 로 점프한다.
조건부 점프: Cmp나 Test 같은 명령어의 결과에 따라점프한다.
  Je  : Cmp나 Test 의 결과가 같다면 점프
  Jne : Cmp나 Text 의 결과가 같지 않다면 점프
  Jz  : 왼쪽 인자의 값이 0 이라면 점프
Jnz  : 왼쪽 인자의 값이 0 이 아니라면 점프
Jl   : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작으면 점프(부호있는)
Jnl  : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작지 않으면(크거나 같으면) 점프 (부호있는)
Jb   : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작으면 점프(부호없는)
Jnb  : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작지 않으면(크거나 같으면) 점프 (부호없는)
Jg   : 왼쪽 인자의 값이 오른쪽 인자의 값보다 크면 점프
Jng  : 왼쪽 인자의 값이 오른쪽 인자의 값보다 크지 않으면 (작거나 같으면) 점프
Jle   : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작거나 같으면점프 (부호있는)
Jge  : 왼쪽 인자의 값이 오른쪽 인자의 값보다 크거나 같으면 점프
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
약 이정도의 명령어들이 가장 많이 나오는 것들임으로
최소한 위에 나온것들은 외워 두도록 하자.
3. 논리연산
이글에서는 5가지 논리연산에 대해서 쓸것이다.
논리연산자는 두 오퍼렌드의 값의 비트들을 대응시켜 명령에 따른 적절한 값을 구하여 첫번쨰 오퍼렌드의 값을 바꾸어 주는것이다.
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
AND 연산
대응되는 비트가 둘다 1이면 결과는 1이고 그외의 결과들은 모두 0 이 된다.
ex:) MOV EAX,8
AND EAX,10 :위를 계산하기 위해 우선 두 오퍼렌드의 값을 2진수로 바꾸어 주면 8은 1000 이 되고 10은 1010 이 되고 AND 연산은 둘다 1이여야 1이 됨으로 결과는 1000 이 됩니다.

OR 연산
대응되는 비트중 하나가 1 또는 둘다 1이면 결과는 1이고 그외는 모두 0이 된다.
ex:) MOV EAX,8
OR EAX,10
:위를 계산하기 위해 두 오퍼렌드의 값을 2진수로 바꾸어 주면 8은 1000이 되고 10은 1010이 되고 OR 연산은 한쪽 또는 양쪽둘다 1이면 1이고그외는 모두 0 임으로 결과는 1010이 된다.
XOR 연산
대응되는 비트 중에서 한비트가 1이고 다른 비트가 0이면 1이 되고 두개의 비트가 1이면 0 이 되고 두개다 0 이어도 0이 된다.
ex:) MOV EAX,8
XOR EAX,10
:위를 계산하기 위해 두 오퍼렌드의 값을 2진수로 바꾸어 주면 8은 1000이 되고 10은 1010이 되고 XOR 연산은 한쪽만 1이어야 1임으로 결과는 10이 된다.

NOT 연산
NOT 연산은 오퍼렌드의 값을 반대로 하여 준다.
ex:) MOV EAX,10
NOT EAX
:위를 계산하기 위해 오퍼렌드의 값을 2진수로 바꾸어 주면 10은 1010이 되고 NOT 연산은 1 과 0을 반대로 하여 줌으로 결과는 0101 이 된다.
*Test 연산은 오퍼렌드에 영향을 주지 않으며 플래그만 세트 시키어 준다.

 

 

 

 

2.레지스터
범용 레지스터
(1) Eax 레지스터
누산기인 Eax 레지스터는 입출력과 거의 모든 산술연산에 사용된다. 곱셋과 나눗셈, 변환 명령어등은 반드시 Eax 레지스터를 필요하게 된다.

Eax 레지스터는 32bit의 레지스터이고 16bit 의 레지스터로 ax가 있다.
(ax는 왼쪽의 ah와 오른쪽의 al로 이루어져 있다)
 (2) Ebx 레지스터
Ebx는 주소지정을 확대하기 위한 인덱스로서 사용될수 있는 유일한 범용 레지스터 이며, 다른 일반적인 계산 용도로도 쓰인다.
Ebx는 32bit 레지스터이고 16bit로 eb가 있다.
(eb는 왼쪽의 bh와 오른쪽의 bl로 이루어져 있다)
(3) Ecx 레지스터
Ecx는 루프의 반복 횟수나 좌우방향의 시프트 비트 수를 기억한다. 그외의 계산에도 사용된다.
Ecx는 32bit 레지스터이고 16bit로 cx가 있다.
(cx는 왼쪽의 ch와 오른쪽의 cl로 이루어져 있다.)
(4) Edx 레지스터
Edx는 몇몇 입출력 동작에서 사용 된다.
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
플래그 레지스터
(1) OF [Over Flow]
산술연산후 상위 비트의 오버플로를 나타냄
(2) DF [Direction]
스트링 데이터를 이동하거나 비교할떄 왼쪽 또는 오른쪽으로의 방향을 결정한다.
(4) SF [Sign]
산술결과의 부호를 나타낸다.[0=양수,1=음수]
(5) ZF [zero]
산술연산 또는 비교동작의 결과를 나타낸다.
[0=결과가 0이 아님,1=결과가 0임]

(6) CF [Carry]
산술연산후 상위 비트로부터의 캐리 그리고 시프트 또는 회전동작의 결과 마지막 비트
내용을 저장한다.

(7) TF [trap]
프로세서가 단일 스텝 모드(single-step mode)를 동작할수 있도록 해준다.

 

 

 

 

 

 

 

 

 


5. Assembly 명령어

 

MOV <Destination>, <Source> - Move. 값을 대입하려고 할때 사용한다. 사용 방법에는 <Destination>에는 레지스터, 메모리등이 올 수 있으며 <Source>에는 <Destination>와 같은 것 이외에 직접적인 값 등이 올 수 있다.
Example:
MOV EAX, 14h
MOV EAX, DWORD PTR SS:[EBP-14]
MOV DWORD PTR SS:[EBP-14], EDX

 

MOVS, MOVSB, MOVSW, MOVSD(Move String Byte or Word or DWord) - ESI가 가르키는 곳의 값들을 Byte(1byte), Word(2byte), DWord(4byte)크기만음 EDI가 가르키는 곳으로 이동시킨다.

MOVSX(Move with Sign-Extended) - Byte나 Word크기의 Operand를 Word나 DWord사이즈로 늘려준다. 부호는 유지된다.

 

MOVZX(Move with Zero-Extended) - Byte나 Word크기의 Operand를 Word나 DWord사이즈로 늘려준다. 연산 후 채워지지 않은 공간에는 0으로 매꾼다.

 

INT <Value> - Interrupt. 해당 Value에 따른 Interrupt를 발생시킨다. <Value>에 해당하는 것들이 너무 많으므로 다음에 더욱 자세하게 다루기로 하자.
Example:
INT 21h

 

ADD <Destination>, <Source> - Addition. 간단하다. <Destination>+<Source>한 값을 <Destination>에 저장한다. <Destination>에는 레지스터, 메모리등이 올 수 있으며 <Source>에는 <Destination>와 같은 것 이외에 직접적인 값 등이 올 수 있다.
Example:
MOV EAX, 5h
MOV EBX, 12h
ADD EAX, 5h  ; EAX에는 5h + 5h = Ah(10진수로 10)가 저장된다.
ADD EAX, EBX ; EAX에는 Ah + 12h = 1Ch(10진수로 28)가 저장된다.

 

SUB <Destination>, <Source> - Subtact. ADD명령어와 사용법은 동일하다. 단지 기능은 빼주는 역할이라는거!
Example:
MOV EAX, 4h
SUB EAX, 3h ; EAX에는 4h - 3h = 1h가 저장된다.

 

INC <Target> - Increments. 타겟의 값에서 1을 증가시킨다. <Target>에는 레지스터, 메모리등이 올 수 있으며, 직접적인 값은 불가능하다.
Example:
MOV EAX, 4h
INC EAX     ; EAX에는 4h에서 1증가된 값인 5h가 저장된다.

 

DEC <Target> - Decrements. 타겟의 값에서 1을 감소시킨다. <Target>에는 레지스터, 메모리등이 올 수 있으며, 직접적인 값은 불가능하다.
Example:
MOV EAX, 4h
DEC EAX     ; EAX에는 4h에서 1감수한 값인 3h가 저장된다.

 

JMP <Location> - Jump. 어떠한 장소로 점프한다. 쉽게 생각해서 GOTO문을 생각하면 될것이다. <Location>에는 점프할 곳의 코드주소를 담고있는 레지스터나 메모리등이 올 수 있다.
Example:
JMP 0041D983
JMP DWORD PTR SS:[EBP-14]

 

** Conditional JUMP **

 

JMP명령어와 같다. 단지 조건에 따라서 Jump할지 안할지가 결정되므로 Conditional Jump라고 하겠다. Conditional JUMP는 CMP명령어와 같이 사용된다.

 

CMP <Target1>, <Target2> - 두 타겟을 비교해서 Flag Register를 변경시킨다. <Target1>이 <Target2>보다 작으면 CF가 Set되고, 같으면 ZF가 Set되고 이런것 들이 있긴하지만, 다음에 왠만하면 Conditional Jump가 있기때문에 Jump문 의미로 이해하도록 하고 CMP로 인한 Flag 변화는 그냥 넘어가도록 하겠다.
Example:
CMP EAX, EBX

 

Unsigned
JA(JUMP if ABOVE)                                     CF=0 and ZF=0
JAE(JUMP if ABOVE or EQUAL)                    CF=0
JB(JUMP if BELOW)                                     CF=1
JBE(JUMP if BELOW or EQUAL)                    CF=1 and ZF=1
JNA(JUMP if NOT ABOVE)                            CF=1 or ZF=1
JNAE(JUMP if NOT ABOVE or EQUAL)           CF=1
JNB(JUMP if NOT BELOW)                            CF=0
JNBE(JUMP if NOW BELOW or EQUAL)          CF=0 and ZF=0
JE(JUMP if EQUAL)                                      ZF=1
JNE(JUMP if NOT EQUAL)                             ZF=0

Signed
JG(JUMP if GREATER)                                 ZF=0 and SF=OF
JGE(JUMP if GREATER or EQUAL)                SF=OF
JL(JUMP if LOWER)                                     SF!=OF
JLE(JUMP if LOWER or EQUAL)                    ZF=1 and SF!=OF
JNG(JUMP if NOT GREATER)                        ZF=1 or SF!=OF
JNGE(JUMP if NOT GREATER or EQUAL)       SF!=OF
JNL(JUMP if NOT LOWER)                            SF=OF
JNLE(JUMP if NOT LOWER or EQUAL)           ZF=0 and SF=OF
JE(JUMP if EQUAL)                                     ZF=1
JNE(JUMP if NOT EQUAL)                            ZF=0

Flag
JC(JUMP if CARRY flag set)                        CF=1
JNC(JUMP if NOT CARRY flag set)               CF=0
JO(JUMP if OVERFLOW flag set)                  OF=1
JNO(JUMP if NOT OVERFLOW flag set)         OF=0
JP(JUMP if PARITY flag set)                        PF=1
JNP(JUMP if NOT PARITY flag set)               PF=0
JPE(JUMP if PARITY is EVEN)                     PF=1
JPO(JUMP if PARITY is ODD)                      PF=0
JS(JUMP if SIGNAL flag set)                       SF=1
JNS(JUMP if NOT SIGNAL flag set)              SF=0
JCXZ(JUMP if CX is ZERO)                       CX=0

AND <Destination>, <Source> - Logical AND. 논리회로에 있어서의 AND연산을 수행한다. 그리고 AND연산을 시행할때, OF, CF는 초기화되고, ZF는 Set될 수 있다.
Example:
AND EAX, EBX

CALL <Location> - Call. 말그대로 함수를 부를때 사용한다. Jump와 같다고 느껴질지도 모르지만 Call문을 시행할 경우 스택에 Call문이 시행된것을 Push를 하며 Return이 가능하다.
Example:
CALL 0041D983
CALL DWORD PTR [EBX]

DIV <Target> - Division. EAX를 <Target>으로 나누는 연산이다. 결과로 몫은EAX에 나머지는 ECX에 들어간다.
Example:
MOV EAX, 64h
MOV ECX, 9h
DIV ECX       ; 64h(100) / 9h(9) = 몫 : 0Bh(11) , 나머지 1h이므로
                EAX = 0Bh, ECX = 1h가 저장된다.

 

IDIV <Target> - Integer Division. DIV와 똑같다. 하지만 다른점은 부호있는 정수를 다룬다는 점이다.

 

MUL <Target> - Multiplication. EAX와 <Target>을 곱하여 EAX에 저장한다.
Example:
MOV EAX, 2h
MUL 4h       ; EAX에는 2h * 4h = 8h가 저장된다.

 

IMUL <Value> - Integer Multiplication. EAX와 <Value>를 곱하여 EAX에 저장한다.
IMUL <Destination>, <Value> - <Destination>과 <Value>를 곱하여 <Destination>에 저장한다.
IMUL <Destination>, <Value>, <Value> - 2개의 <Value>를 곱한 후에 <Destination>에 저장한다.

 

LEA <Destination>, <Source> - Load Effective Address. <Source>의 실제 주소를 <Destination>에 저장한다. 하지만 이 용도보다는 빠른 계산을 위해 주로 사용된다. 예를들어 LEA EAX, DWORD PTR [2*EAX+ECX]를 하면, EAX에 2*EAX+ECX계산값이 들어가게 된다.

 

NOP - No Operation. 아무것도 하지 않는다.

 

OR <Destination>, <Source> - Logical OR. 논리회로에 있어서의 OR연산을 수행한다. 그리고 OR연산을 시행할때, OF, CF는 초기화되고, ZF는 Set될 수 있다.
Example:
OR EAX, EBX

 

POP <Destination> - POP. 스택에서 ESP가 가르키는 곳에서 주소값을 불러내어 <Destination>에 저장한다. 그리고 ESP는 다음값을 가르키게 된다.
Example:
POP EAX

 

PUSH <Source> - 스택에 <Source>를 집어넣는다. ESP는 최근에 PUSH한 값을 가르키게 된다.
Example:
PUSH EAX

 

RET - Return. 스택에서 주소를 POP해온 후 그 주소로 돌아간다. PUSH와 RET을 조합해서 JMP처럼 사용 할 수 있다.

 

TEST <Target1>, <Target2> - 이 연산은 대부분이 <Target1>과 <Target2>가 같게 설정된다. 예를들면 TEST EAX, EAX. 이 연산은 논리회로의 AND연산을 수행하지만 결과값을 저장하지 않는다. 단지 EAX=0일경우 ZF=1이 되고 EAX!=0일경우 ZF=0이 된다. 그리고 OF, CF는 0이된다.
Example:
TEST EAX, EAX

 

XOR <Destination>, <Source> - Logical Exclusive OR. 논리회로에 있어서 XOR연산을 수행한다. XOR연산을 시행할때, OF, CF는 초기화되고, ZF는 Set될 수 있다. 이 연산은 XOR EAX, EAX처럼 많이 사용되는데, 이렇게 할 경우 XOR=0이 된다. 이유는 직접 해보면 알것이다.
Example:
XOR EAX, EBX
XOR EAX, EAX     ; EAX=0이 됨.

 

LODS, LODSB, LODSW, LODSD(Load String Byte, Word, DWord) - ESI가 가르키는 곳에서 지정한 크기(Byte, Word, DWord) 만큼 읽어와 EAX에 복사한다. ESI는 복사한만큼 이동한다.

 

STOS, STOSB, STOSW, STOSD(Store String Byte, Word, DWord) - EAX에 들어이있는 데이터를 지정한 크기만큼 EDI가 가르키는 주소에 복사한다. EDI는 복사된 만큼 이동한다.

 

CLD(Clear Direction flag), STD(Set Direction flag) - Direction Flag를 Set하거나 Clear할때 사용한다.

 

CMC(Complement Carry flag), CLC(Clear Carry flag), STC(Set Carry flag) - Carry flag를 순서대로 반전, Clear, Set시킨다.

 

SHL <Destination>, <Value> - Shift Logical Left. <Destination>에 <Value>만큼 Shift연산을 왼쪽으로 수행한다. 만약 <Destination>보다 커질경우 CF=1이 된다.

 

SHR <Destination>, <Value> - Shift Logical Right. SHL과 기능은 동일하며 Shift연산이 오른쪽으로 진행된다.

 

ROL <Destination>, <Value> - Rotate Left. SHL과 기능은 동일하다. 단지 자리수가 늘어날경우 해당 비트가 오른쪽 끝으로 이동한다.

 

ROR <Destination>, <Value> - Rotate Reft. SHR과 기능은 동일하다. 단지 자리수가 없어질경우 해당 비트가 왼쪽 끝으로 이동한다.

 


1. 나눗셈 연산의 피젯수는(32bit의 나눗셈을 가정) 항상 edx:eax 이다.
2. cdq 는 나눗셈을 위해 피젯수의 사이즈를 확장하는 것이다.


나눗셈연산(div, idiv)은 eax와 edx에 의해서만 이루어집니다
- 피젯수(나눔을 당하는 수) 는 eax, edx에만 들어갈 수 있다는 얘기에요
16 / 5 연산을 한다고 가정해 봅시다.

16과 5 둘다 32bit data라고 가정하구요

그럼 일단 eax에 16을 넣습니다. 그 다음 ebx(다른레지스터나 메모리도 상관없음)에

5를 넣습니다. 그 다음 div 연산을 하면.........될것 같지만 안됩니다..

일반적으로 제수(여기서는 5)가 32bit이면 피젯수(여기서는 16) 는 64bit가 되어야

32bit 값을 가지는 몫을 얻을 수 있습니다.

그래서 피젯수의 bit를 확장 시켜주는것이 바로 cdq 연산입니다

32bit 크기의 eax의 값을 64bit의 값인 edx:eax로 만들어줍니다.

여기서 edx는 상위자리가되고 eax는 하위 자리가 되죠

자..그럼 cdq 연산까지 끝났으면 edx:eax에 16이 들어가있고 ebx에 5가 들어있겠네요

그럼 idiv연산을 해봅시다(div는 부호가없는 나눗셈 idiv 부호가 있는 나눗셈)

그럼 몫과 나머지가 나와야 하겠죠? 그 결과는 다시 eax와 edx로 들어가는데

eax에는 몫이, edx에는 나머지 부분이 들어갑니다~

 


LoadLibrary GetProcAddress (로드 라이브러리 겟프락어드레스) 후에 변하지 않는 레지스터는
EBX EBP ESI EDI 이다. EAX, ECX, EDX 가 변한다


출저 : http://zerohz.tistory.com/61

신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

assem 분석 1  (1) 2014.05.05
upx 언패킹 성공  (0) 2013.09.12
펌 리버싱을 위한 어셈정리  (0) 2013.08.13
crackme3-abexcm3  (0) 2013.08.06
crackme2-abexcm2  (0) 2013.07.19
carack_me 문제모음  (1) 2013.07.18

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret


Crack Me 3풀이 -by jen6

스타트는 역시 메시지 창이죠!

시작하자 마자 key file을 찾습니다.

그냥 ok를 눌렀더니

이렇게 되고 꺼지더라구요

올리디버거로 열어봅니다


쭉나열되어 있는데 주요 코드만 확대해서 찍어봤습니다.


이프로그램은 먼저 파일의 유무를 구별한후 파일 크기로 구분하는것 같습니다.


그래서 브레이크 포인트를 비교하는 je와 jnz 명령어의 전인 CMP 명령어에다 걸어놓았습니다.

먼저 이렇게 뜨는 이유를 확인 하기위해


이부분의 코드를 살펴보니

00401034  CMP EAX,-1

00401037  JE SHORT Crackme_ 00401075

je(조건분기문)이 나오는걸 보니 중요한 문장 같은데....

CMP명령어가 뭔지 몰라서 한참동안 고민했습니다.

구글링결과 EAX값과 비교를 하는 것 이었습니다

ex. CMP EAX,1   이경우  EAX -1 을 한 값을 리턴합니다.

같을경우는 0을 반환하고 다를경우 다른값을 반환한다고 하네요.

보통 je jnz 같은거 앞에 자주 온다고 합니다.



요롭게 EAX를 바꿔서 넘어가면 새로운 난관에 봉착하게 됩니다.

(바뀐 EAX)

Key파일은 있는디.. 우리가 원하는 키파일이 아니랍니다



00401041 ~ 00401046 까지가 파일을 또 검사하는 부분임비다

검사방식은 파일 크기를 검사하는 거더라구요

00401046 CMP EAX, 12

00401049 JNZ SHORT Crackme_00402035 (EAX가 12랑 다를경우 파일크기가 다르다는 화면으로 넘어감)



EAX를 12로 바꿔줍니다

FINISH!

신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

upx 언패킹 성공  (0) 2013.09.12
펌 리버싱을 위한 어셈정리  (0) 2013.08.13
crackme3-abexcm3  (0) 2013.08.06
crackme2-abexcm2  (0) 2013.07.19
carack_me 문제모음  (1) 2013.07.18
crackme1-abexcm1  (0) 2013.07.17

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

크랙미 2번 풀이입니다


아주 흔한 크랙하는 형식의 문제입니다

보통 이런 크랙문제들은 name을 어떤 루프에 돌려서 시리얼을 만든다고 합니다.

그런 방식으로 구현해서 풀수도 있겠지만 초보인 저는 좀더 쉬운 방법으로 가보겠습니다.


먼저 프로그램이 시작하는 ep를 찾아줍니다.

ep위에는 함수들이 선언되어있습니다.

먼저 프로그램은 name,serial칸을 모두 채운후 check를 눌러 맞으면 "key is right"가 나오지만

serial이 틀릴경우 "wron serial"과 같은 메세지를 뱉습니다.

R 이라고 멋드러지게 써져있는 아이콘을 눌르면 프로그램 내의 텍스트들이 쭉~ 뽑혀나옵니다.

위 사진처럼 말이지요. visual basic의 특성상 객체를 누를떄 이벤트가 발생하기때문에 메세지 박스 근처에

시리얼과 입력값을 비교하는 부분이 있을거라 생각해서 성공하는 부분의 코드 부터 보았습니다.


예상대로 바로 위에 비교하는 코드가 있더군요.

BP00403321 LEA EDX,DWORD PTR SS:[EBP-44]  함수에서 선언된 객체의 스택 주소입니다

BP00403329 CALL DWORD PTR DS  조건문의 시작

0040332F TEST AX,AX  논리비교 구문(AND연산과 같음)

00403332 JE abexcrac.00403408 조건분기구문

0040338A MOV DWORD PTR SS:[EBP-D4],abexcrac...... 성공문장

브레이크 포인트를 건 부분은 중요하다 생각되어서 걸어놓았습니다.

여기는 실패구문입니다 아까 위에와 비슷한 형태를 띄고있어서 조건문 시작부분에다가만 걸었는데

지금사진을 보니깐 잘못건게 보이네요... 원래는 0040341B에다 걸었지만 이부분은 별로 중요하지 않으니깐 PASS하겠습니다.

ps.이부분에 브포 걸지마세요.. 여기서부터 시작해서 한참 삽질했었습니다.

그냥 순차적이 짱이라는걸 알게되네요

그래서 저는 총 3부분에다가 브레이크포인트를 두었습니다.

프로그램을 실행하다보면 00403321에서 멈추게 됩니다.

그리고 이때 선언한 내용을 보기위해서 디버그 레지스터 창을보면 EDX(파일입출력)부분의 주소가 바뀌어 있는걸 확인할 수 있습니다

주소를 오른쪽 마우스로 클릭하여 Follow in Stack 을 선택하면 스택내에 값을 볼 수있습니다.

사진을 살짝 잘못찍었네요 원래는 정상적인 시리얼과 제가 입력한 시리얼이 나오게 되면서

대략 유추 할수있죠(아.. 이게 시리얼이구나)

013F378 주소값이 정상적인 시리얼입니다

입력하면 Congratulations!

다음번에는 암호화 루틴을 직접 만들어 봐야겠어요

신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

upx 언패킹 성공  (0) 2013.09.12
펌 리버싱을 위한 어셈정리  (0) 2013.08.13
crackme3-abexcm3  (0) 2013.08.06
crackme2-abexcm2  (0) 2013.07.19
carack_me 문제모음  (1) 2013.07.18
crackme1-abexcm1  (0) 2013.07.17

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

크랙미 문제 모음입니다 총 42문제로 구성되어있습니다.

이번 방학때 마스터 할려고 노력해봐야겠습니다

Crack_Me.zip


신고
Creative Commons License
Creative Commons License

'공부 > 리버싱' 카테고리의 다른 글

upx 언패킹 성공  (0) 2013.09.12
펌 리버싱을 위한 어셈정리  (0) 2013.08.13
crackme3-abexcm3  (0) 2013.08.06
crackme2-abexcm2  (0) 2013.07.19
carack_me 문제모음  (1) 2013.07.18
crackme1-abexcm1  (0) 2013.07.17

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글 하나 달렸습니다.
  1. 해커스쿨 눈팅하다가 왔는데 좋은 자료 받아갑니다

    좋은 포스팅 부탁드릴게요 ㅎㅎ
secret