인코딩


쉘코드 인코더를 직접 구현해 보던 중 현재 실행 코드 주소를 알아내는 테크닉이 필요해서 정리해 둔다. 


인코더를 구현하기 위해서는 현재 실행중인 코드 주소를 알아내야 한다. 아래처럼 디코더가 인코딩된 쉘코드의 주소값을 알아야


하기 때문이다.



| 디코더 | 인코딩된 쉘코드 | 

    |        ^

     -----l






여기서 실행코드 주소란 바로 위에 표시된 주소를 구하는 방법인데, 이미 잘 알려진 몇가지 방법이 있다. 또한 이 


방법들은 메타스플로잇 msfencode 의 여러 인코더들이 사용중인 방법들이다. 



1) call + 5


 e8 00 00 00 00      call 0x5

 58                        pop eax


call 명령이 실행되면 스택에 돌아올 주소를 push 한 뒤 해당 주소로 점프하게 되는데, 0x5로 점프하게 되면 바로 


다음줄 명령으로 점프하게 되고, 스택에 저장된 코드주소를 pop 으로 꺼내는 원리이다. 아래 그림을 보면 실행 후 


eax 에 코드 주소가 저장되어 있는 것을 볼 수 있다.





2) call + 4


 e8 ff ff ff ff          call 0x4

 c2                      ret

 59                      pop ecx


이전과 비슷하지만, call + 4를 하기 때문에 자기 자신( ff 의 끝) 으로 점프하게 된다.(아래 그림) 점프 한 뒤에는 ff c2 가 RET가 


아닌 INC EDX 로 해석되고, 바로 뒤의 pop 을 통해 스택에 저장되어 있는 코드 주소를 가져와서 ecx 레지스터에 저장해 준다.



                                                                              call 명령 전


                                                                      call 명령 후 재 해석 된 명령어




3) FPU 명령어 이용(fstenv)


 d9 ee                    fldz

 d9 74 24 f4           fnstenv [esp-0xc]

 58                        pop eax


위의 기본적인  fldz, fnstenv 등의 fpu 관련 명령어를 이용할 수도 있다. 부동소수점 관련 연산 명령어들인데, 위의 두 방법보다 더


깔끔하고 안정적인 방법인 듯 하다. 가장 많이 쓰이는 msfencode 인코더 중 하나인 shikata_ga_nai 도 이 방법으로 구현되어 있다. 


fnstenv 명령이 실행되면 스택에 fldz 명령 주소값이 들어간다. 그림을 보면 fldz 명령 주소인 0x401000 이 들어가 있음을 알 수 있다.




4) backword call


 eb 03                jmp short 0x5    (1)

 5e                    pop esi     (3)

 ff e6                 jmp esi     (4)

 e8 f8 ff ff ff       call -7      (2)

 shellcode(아래 그림 nop 부분)

    ...


마찬가지로 call 을 하면 다음 명령어 주소가 스택에 저장되는 것을 이용한 것으로, 이 또한 많이 사용되는 방법 중 하나이다. 다만 


역방향 call 을 한다는 것만 다르다. 




이 외에도 몇가지 방법이 더 있으나..이정도면 충분한 듯 하다. 이 getpc 코드들은 일반적으로 인코더의 첫 부분에 들어가는데,


동일한 코드를 사용하면 단순 패턴 탐지만으로도 백신, IDS 등에 탐지될 수 있으므로 레지스터, 명령어 순서 변경, 쓰레기 명령


삽입 등으로 다형성을 추가할 수 있다. 이 부분은 다음 블로깅에서 이어 가도록 하겠다.







+ Recent posts