windbg의 메모리창에서 포인터 내용을 바로 보고 싶을때~
최신목록
2017년 9월 14일 목요일
2017년 7월 20일 목요일
[windbg]IAT 테이블 이용해서 system function 찾기
windows 2012 r2에서 system process에서 LoadLibrary break 걸때는 bp kernel32!LoadLibraryW 하고 사용을 잘하고 있었는데.... windows 2016에서 계속 couldn't resolve error 가 떴다.
아래와 같이 심볼도 잘 올라왔고 kernel32에 있는 api가 아닌가??? msdn을 확인해봐도 kernel32에 있단다....뭐죠..?
windows 2016으로 오면서 kernel32가 변했나? dependency walker로 확인을 해보았다.
api가 정상적으로 export되있다. 근데 왜!!! 무엇때문에 windbg는 인식을 못하는걸까?
그럼 이번엔 process의 IAT 테이블을 이용해서 실제 process가 LoadLibrary를 어떤 모듈에서 가져오는지 확인해보기로하자.
IAT table은 process 의 IMAGE_NT_HEADERS>IMAGE_OPTIONAL_HEADER 의 DllCharacteristics에 존재한다. windbg는 해당 정보를 dh 명령어를 통해 자세히 보여준다.
하단에 Import Address Table Directory 옵셋(62D0)과 해당 테이블의 사이즈(450) 정보가 보인다. 이 옵셋을 해당 프로세스의 ImagebaseAddr과 결합하여 심볼정보를 보면 import된 API 심볼이 보일것이다. ImagebaseAddr은 'lm m <Module>'을 통해 볼 수 있다.
LoadLibrary로 검색해보면 API가 없고 kernelbase!LoadLibraryExW 가 존재한다. LoadLibrary기능중 호출될거 같은 놈이다 ㅎ break 걸고 LoadLibrary 호출상황을 만들어본다.
앗 여기...kernelbase!LoadLibraryA 가 .... kernel32를 안쓰고 kernelbase를 쓰네...
음 왠진 모르겠다. 여튼 bp kernelbase!LoadLibraryA 를 이용하는걸로....아시는분?
아래와 같이 심볼도 잘 올라왔고 kernel32에 있는 api가 아닌가??? msdn을 확인해봐도 kernel32에 있단다....뭐죠..?
windows 2016으로 오면서 kernel32가 변했나? dependency walker로 확인을 해보았다.
api가 정상적으로 export되있다. 근데 왜!!! 무엇때문에 windbg는 인식을 못하는걸까?
그럼 이번엔 process의 IAT 테이블을 이용해서 실제 process가 LoadLibrary를 어떤 모듈에서 가져오는지 확인해보기로하자.
IAT table은 process 의 IMAGE_NT_HEADERS>IMAGE_OPTIONAL_HEADER 의 DllCharacteristics에 존재한다. windbg는 해당 정보를 dh 명령어를 통해 자세히 보여준다.
하단에 Import Address Table Directory 옵셋(62D0)과 해당 테이블의 사이즈(450) 정보가 보인다. 이 옵셋을 해당 프로세스의 ImagebaseAddr과 결합하여 심볼정보를 보면 import된 API 심볼이 보일것이다. ImagebaseAddr은 'lm m <Module>'을 통해 볼 수 있다.
LoadLibrary로 검색해보면 API가 없고 kernelbase!LoadLibraryExW 가 존재한다. LoadLibrary기능중 호출될거 같은 놈이다 ㅎ break 걸고 LoadLibrary 호출상황을 만들어본다.
앗 여기...kernelbase!LoadLibraryA 가 .... kernel32를 안쓰고 kernelbase를 쓰네...
음 왠진 모르겠다. 여튼 bp kernelbase!LoadLibraryA 를 이용하는걸로....아시는분?
2016년 4월 8일 금요일
[WinDbg]PROCESS와 HANDLE과 OBJECT
testc.exe에서 open 함수로 파일을 열었다. 윈도우 개발자인 나는 c코딩에 익숙하지 않다 win32 api에 익숙하다. fd를 리턴해준다. file descriptor...음...security descriptor는 많이 사용하나..fd는 왠지 아는거 같으면서도 핸들도 아니고 뭐지?? 의문이 꼬리를 물어 찾아봤더니 윈도우의 핸들과 비슷한 거라하여 테스트 해보니 핸들값과는 또 달랐다...음..뭔가 명확하지 않다. 일단 핸들부터는 내가 익숙하고 잘 안다 생각했는데...잘 생각해보니...핸들은...
핸들 테이블을 커널이 관리하니...또 난 잘 모른다. 일단 잘 아는거 부터 정리하고 FD를 풀어봐야겠다 ㅋㅋ 결국 이글은 FD 관련 글은 아니란 얘기...낚이지 마세요~아래와 같은 궁금증을 해소하기로 하였다.
1. 핸들은 커널이 관리하나 프로세스 마다 독립적으로 존재하는가?
=> 그렇다.
2. 그럼 프로세스 어디에 핸들테이블에 대한 정보가 존재한다는 것인데...어디에 있는가?
=> ??
3. 핸들테이블에 가면 실제 object 정보를 가져올 수 있는가?
=> ??
일단 제일 접근하기 쉬운 파일을 하나 열어서 확인해보았다.
int fd = open("c:\\test_hook\\1.txt, O_RDONLY); // fd = 3
HANDLE hFile = (void*)_get_osfhandle(fd); // hFile = 7e4
fd와 hFile 값은 다르다!!
windbg를 이용하여 user mode에서 hFile의 정보를 찾아보자
!handle commnad를 이용하여 정보를 보았으나...음 포인터가 있어보이진 않는다.
kernel mode로 가보자. 커널이 궁금하다 ㅎ
.attach -k로 커널로 change!!
!process 0 0 커멘드로 프로세스 리스트에서 testc.exe를 찾았다.
EPROCESS 주소가 89C42188임을 알수 있다. EPROCESS를 뒤져보자
^^어라 핸들테이블 역시 eprocess 프로세스의 모든것이 들어있다 ㅋ
내가 생각한 핸들테이블이 맞는지 고고
_HANDLE_TABLE은 이렇게 생겼군요... 실제 포인터는 어디에 있는걸까요?
TableCode가 실제 핸들테이블 주소라고 하네요
실제 핸들테이블 메모리와 !handle을 이용한 값을 비교해볼까요~?
핸들값이 순차적으로 올라가는게 비슷해보이네요 근데 왜 다 free handle이고 앞에 값들이 다 0네요..이렇게 아까 열었던 1.txt파일 핸들 7e4를 찾아서 비교해보면
핸들이 4씩 커지고 있으므로 계산해보니 !handle에서 가리키는 Entry 값과 같은 위치에 정보가 존재하네요. GrantedAccess 값이 뒤 8바이트로 나타내지고 있는걸 볼수 있구요
앞에 있는 정보는 그럼 실제 object pointer인지 비교해보면 그건 약간의 차이가 있네요...음...왜죠?? 실제 해더와 메모리에 있는 값과는 3?? 차이가 나네요...앗 fd값? ㅋㅋ 낚이면 안되요 아니겠죠 ㅎㅎ 여튼 핸들테이블에서는 관련정보가 잇다는걸 확인하고 실제 _FILE_OBJECT는 !handle 에 있는 Object값으로 확인해보겠습니다.
FileName이 제대로 들어가 있는거 보니 확실하네요.
2015년 11월 19일 목요일
[windbg]함수의 파라미터와 클래스 인스턴스 전달방식
클래스 멤버함수에서 멤버함수 호출시 필요한 데이타는 클래스 instance와 전달되는 파라미터이다.
1. 32bit 프로그램
32bit 프로그램에서는 파라미터를 전달할때 스택을 사용한다. 아래의 그림은 B함수가 A함수를 호출하고 prologue 마치고 난후의 스택의 모습과 prologue 전 함수에 바로 진입했을때의 스택의 모습을 보여주고 있다.
prologue 작업은 해당함수에 맞게 EBP와 ESP를 스택에 다시 셋팅하는 작업으로 보통은 windbg에서 breakpoint를 찍어서 걸리면 prologue 작업전이기때문에 스택을 쳐다보면 return address가 있고 그 아래에 파라미터들을 볼 수 있다. assembly 코드를 보고 있으면 ebp+8, ebp+c, ebp+10 에 있는 데이터를 이용하는것을 볼수 있는데 이것은 전달된 파라미터를 이용하고 있는 모습니다. 32bit 에서는 ebp가 중요한 기준이 되고 있음을 볼 수 있다.
클래스에서는 이와 같으나 추가로 클래스 instance를 전달해주어야 하는데 이는 스택을 통하지 않고 ECX 레지스터를 통해 전달된다. 그러나 가끔 Windows 시스템 내부 함수를 추적하다보면 32bit OS에서는 ECX에 instance값이 없고 스택으로 전달할 때도 있다. 그러면 parameter1이 있을 자리에 instance값이 존재한다. 32bit OS에서는 __thiscall 이라는 호출규약 지정시 ecx를 통해 클래스 포인터(인스턴스)를 전달한다.
2. 64bit 프로그램
64bit 프로그램에서는 파라미터를 전달할때 레지스터를 사용한다.
사용되는 레지스터는 아래와 같다.
RCX : CLASS instance
RDX : parameter1
R8 : parameter2
R9 : parameter3
그래서 64bit 프로그램에서는 prologue 작업에 파라미터로 전달된 데이터를 스택에 저장하는 작업이 추가된다.
rdx는 전달된 iValue이고 rcx는 이클래스의 instance 값이고 각각 rsp+8과 rsp+10에 저장되고 있음을 볼 수 있다. 그래서 64bit에서는 rbp보다 rsp가 더 중요한 기준이 되고 있음을 볼 수 있다.
1. 32bit 프로그램
32bit 프로그램에서는 파라미터를 전달할때 스택을 사용한다. 아래의 그림은 B함수가 A함수를 호출하고 prologue 마치고 난후의 스택의 모습과 prologue 전 함수에 바로 진입했을때의 스택의 모습을 보여주고 있다.
prologue 작업은 해당함수에 맞게 EBP와 ESP를 스택에 다시 셋팅하는 작업으로 보통은 windbg에서 breakpoint를 찍어서 걸리면 prologue 작업전이기때문에 스택을 쳐다보면 return address가 있고 그 아래에 파라미터들을 볼 수 있다. assembly 코드를 보고 있으면 ebp+8, ebp+c, ebp+10 에 있는 데이터를 이용하는것을 볼수 있는데 이것은 전달된 파라미터를 이용하고 있는 모습니다. 32bit 에서는 ebp가 중요한 기준이 되고 있음을 볼 수 있다.
클래스에서는 이와 같으나 추가로 클래스 instance를 전달해주어야 하는데 이는 스택을 통하지 않고 ECX 레지스터를 통해 전달된다. 그러나 가끔 Windows 시스템 내부 함수를 추적하다보면 32bit OS에서는 ECX에 instance값이 없고 스택으로 전달할 때도 있다. 그러면 parameter1이 있을 자리에 instance값이 존재한다. 32bit OS에서는 __thiscall 이라는 호출규약 지정시 ecx를 통해 클래스 포인터(인스턴스)를 전달한다.
2. 64bit 프로그램
64bit 프로그램에서는 파라미터를 전달할때 레지스터를 사용한다.
사용되는 레지스터는 아래와 같다.
RCX : CLASS instance
RDX : parameter1
R8 : parameter2
R9 : parameter3
그래서 64bit 프로그램에서는 prologue 작업에 파라미터로 전달된 데이터를 스택에 저장하는 작업이 추가된다.
2015년 10월 2일 금요일
하드웨어 브레이크포인트
패킹된 바이너리의 OEP(Original Entry Point)를 찾던중 하드웨어 브레이크 포인트라는 유용한 방법을 알게되어서 정리해보았습니다.
이전에 Windbg로 리버싱하던중 메모리를 뒤져서 원하는 정보를 얻었는데 메모리에 언제 누가 그 정보를 입력하는지가 궁금해서 엄청 노가다를 해서 알아냈던 기억이 있습니다. 이때 하드웨어 브레이크포인트를 알았더라면..ㅠㅠ
일단 Windbg와 OllyDbg 두가지 경우를 정리하겠습니다.
먼저 OllyDbg로 OEP를 찾는 방법입니다.
1. OllyDbg
약간의 패킹에 대한 기본지식이 필요하지만 일단 정리하는 차원이라 간단히 설명드리겠습니다. UPX를 이용하여 패킹을 한 실행파일을 실행을 하면 PUSHAD 명령어로 시작을 하게 됩니다. UPX 패커의 특징입니다.
PUSHAD : 8개의 범용 레지스터(EAX~EDI)의 값을 스택에 저장
POPAD : 8개의 범용 레지스터(EAX~EDI)의 값을 스택에서 빼서 레지스터에 적용
UPX를 가지고 패킹을 하면 패킹된 실행파일은 처음 실행될때 바로 패킹하기전 EP(OEP)로 시작하지 않기 때문에 해당 레지스터의 값들을 그대로 스택에 저장했다가 EP에 왔을때 POPAD를 통해 레지스터 복원을 해주고 있습니다. 하여 PUSHAD를 통하여 스택에 저장된 데이타를 언제 ACCESS하는지 잡으면 쉽게 EP로 가는 곳을 잡을 수 있습니다.
그림에서와 같이 PUSHAD 실행후 레지스터값이 그대로 스택에 저장이 된것을 볼 수 있습니다. 그리고 DUMP 창에서 팝업메뉴에 있는 Breakpoint > Hardware, on access > Byte를 선택하면 해당 스택의 데이타가 access 되는 시점에 브레이크가 잡히게 됩니다.
OllyDbg를 보다가 WinDbg에도 있나 하고 찾아봤더니 같은 기능이 있더군요..
아래와 같이 간단히 사용법만 정리해보았습니다.
2. WinDbg
WinDbg는 ba(break on access) 라는 명령어를 이용하여 메모리 access 시점을 잡을 수 있습니다.
<사용법>
ba [r/w/e][Size] Addr
-r(Read), w(Write), e(Execute)
-Size : 해당 주소로 부터 엑세스를 감지할 메모리 사이즈(1/2/4 bytes)
-Addr : 해당 주소
이전에 Windbg로 리버싱하던중 메모리를 뒤져서 원하는 정보를 얻었는데 메모리에 언제 누가 그 정보를 입력하는지가 궁금해서 엄청 노가다를 해서 알아냈던 기억이 있습니다. 이때 하드웨어 브레이크포인트를 알았더라면..ㅠㅠ
일단 Windbg와 OllyDbg 두가지 경우를 정리하겠습니다.
먼저 OllyDbg로 OEP를 찾는 방법입니다.
1. OllyDbg
약간의 패킹에 대한 기본지식이 필요하지만 일단 정리하는 차원이라 간단히 설명드리겠습니다. UPX를 이용하여 패킹을 한 실행파일을 실행을 하면 PUSHAD 명령어로 시작을 하게 됩니다. UPX 패커의 특징입니다.
PUSHAD : 8개의 범용 레지스터(EAX~EDI)의 값을 스택에 저장
POPAD : 8개의 범용 레지스터(EAX~EDI)의 값을 스택에서 빼서 레지스터에 적용
UPX를 가지고 패킹을 하면 패킹된 실행파일은 처음 실행될때 바로 패킹하기전 EP(OEP)로 시작하지 않기 때문에 해당 레지스터의 값들을 그대로 스택에 저장했다가 EP에 왔을때 POPAD를 통해 레지스터 복원을 해주고 있습니다. 하여 PUSHAD를 통하여 스택에 저장된 데이타를 언제 ACCESS하는지 잡으면 쉽게 EP로 가는 곳을 잡을 수 있습니다.
그림에서와 같이 PUSHAD 실행후 레지스터값이 그대로 스택에 저장이 된것을 볼 수 있습니다. 그리고 DUMP 창에서 팝업메뉴에 있는 Breakpoint > Hardware, on access > Byte를 선택하면 해당 스택의 데이타가 access 되는 시점에 브레이크가 잡히게 됩니다.
아래와 같이 간단히 사용법만 정리해보았습니다.
2. WinDbg
WinDbg는 ba(break on access) 라는 명령어를 이용하여 메모리 access 시점을 잡을 수 있습니다.
<사용법>
ba [r/w/e][Size] Addr
-r(Read), w(Write), e(Execute)
-Size : 해당 주소로 부터 엑세스를 감지할 메모리 사이즈(1/2/4 bytes)
-Addr : 해당 주소
2015년 9월 18일 금요일
[리버싱]PE 헤더와 RVA&RAW 차이
이번에는 PE 헤더와 RVA(Relative Virtual Address)와 RAW의 차이에 대해서 정리하겠습니다.
PE 헤더 PE헤더에는 DOS 헤더, NT 헤더, Section 헤더 크게 세가지로 구분이 되어 있습니다.
<DOS 헤더>
DOS signature("MZ") 와 NT Header의 옵셋이 들어있습니다. DOS 헤더 아래에는 DOS Stub을 통해서 도스에서 실행될때 처리를 넣을 수 있습니다. (컴파일러가 기본으로 "This program cannot be run is DOS mode" 라고 콘솔에 뿌려주는 처리루틴을 DOS Stub에 넣게 됩니다.)
<NT 헤더>
PE signature("PE")와 File Header, Optional Header 를 포함하고 있습니다. File Header에는 이 PE 파일이 지원하는 CPU와 section 수, Optional Header 사이즈 등을 포함하고 있습니다. Optional Header에는 실제 메모리로 올라갔을때 필요한 정보들이 포함이 되어 있습니다.
- ImageBase : 메모리에서 PE파일이 로딩되는 시작주소
- SectionAlignment, FileAlignment : 섹션의 최소단위를 나타내면 메모리에서의 섹션과 파일에서의 섹션의 최소단위의 사이즈가 다르다. 각 섹션의 크기는 반드시 Alignment의 배수여야함.
- SizeOfImage : 메모리에서 PE Image가 차지하는 사이즈
- SizeOfHeader : 메모리에서 PE Header가 차지하는 사이즈
- subsystem : 드라이버(1), GUI(2), 콘솔기반(3) 인지 구분
<Section Header>
각 세셕의 메모리에서의 시작주소와 사이즈, 파일에서의 시작주소와 사이즈 정보가 포함되어 있다.
-VirtualAddress : 메모리에서의 section의 시작주소의 RVA
-PointerToRawData : 파일에서의 section의 시작주소의 RAW
-RVA : 메모리에서의 주소 옵셋으로 ImageBase를 기준으로 계산된다.
-RAW : 파일에서의 주소 옵셋
따라서 RVA와 RAW의 관계는 아래와 같다.
RVA - VA(section의 시작주소) = RAW - PointToRawData
다음에 IAT , EAT등 좀 더 깊게 들어가보겠습니다.
PE 헤더 PE헤더에는 DOS 헤더, NT 헤더, Section 헤더 크게 세가지로 구분이 되어 있습니다.
<DOS 헤더>
DOS signature("MZ") 와 NT Header의 옵셋이 들어있습니다. DOS 헤더 아래에는 DOS Stub을 통해서 도스에서 실행될때 처리를 넣을 수 있습니다. (컴파일러가 기본으로 "This program cannot be run is DOS mode" 라고 콘솔에 뿌려주는 처리루틴을 DOS Stub에 넣게 됩니다.)
<NT 헤더>
PE signature("PE")와 File Header, Optional Header 를 포함하고 있습니다. File Header에는 이 PE 파일이 지원하는 CPU와 section 수, Optional Header 사이즈 등을 포함하고 있습니다. Optional Header에는 실제 메모리로 올라갔을때 필요한 정보들이 포함이 되어 있습니다.
- ImageBase : 메모리에서 PE파일이 로딩되는 시작주소
- SectionAlignment, FileAlignment : 섹션의 최소단위를 나타내면 메모리에서의 섹션과 파일에서의 섹션의 최소단위의 사이즈가 다르다. 각 섹션의 크기는 반드시 Alignment의 배수여야함.
- SizeOfImage : 메모리에서 PE Image가 차지하는 사이즈
- SizeOfHeader : 메모리에서 PE Header가 차지하는 사이즈
- subsystem : 드라이버(1), GUI(2), 콘솔기반(3) 인지 구분
<Section Header>
각 세셕의 메모리에서의 시작주소와 사이즈, 파일에서의 시작주소와 사이즈 정보가 포함되어 있다.
-VirtualAddress : 메모리에서의 section의 시작주소의 RVA
-PointerToRawData : 파일에서의 section의 시작주소의 RAW
-RVA : 메모리에서의 주소 옵셋으로 ImageBase를 기준으로 계산된다.
-RAW : 파일에서의 주소 옵셋
따라서 RVA와 RAW의 관계는 아래와 같다.
RVA - VA(section의 시작주소) = RAW - PointToRawData
다음에 IAT , EAT등 좀 더 깊게 들어가보겠습니다.
2015년 9월 3일 목요일
[리버싱]콜링 컨벤션
함수 호출시 caller(호출자:main)와 callee(피호출자:sum)간의 파라미터 전달 방법및 스택 정리 담당자에 대한 규약을 콜링 컨벤션(함수 호출 규약)이라고 한다.
주로 사용되는 규약에는 세가지 정도가 있다. __cdecl, __stdcall, __fastcall에 대해 정리한다.
예제는 Visual Studio와 OllyDbg를 사용하여 분석하였다.
간단히 정리하면 아래와 같다.
4. __thiscall
클래스의 멤버함수에서만 사용되는 호출규약으로 클래스 포인터를 스택이 아닌 ecx를 통해 넘기겠다는 규약이다. __stdcall과 유사하나 클래스 포인터가 스택이 아닌 ecx를 통해 전달된다.
호출규약이 서로 맞게 되있는지 확인하기 위해선 VS 옵션인 C/C++>코드생성>기본 런타임 검사 를 실시한다. 만약 호출규약이 서로 맞지 않으면 RTC_CheckEsp에서 에러를 리턴하여 확인할 수 있다.
이번에는 32bit 프로세스를 분석하였는데 64bit에서는 어떤지 궁금하네요
64비트에서는 여전히 __stdcall과 __cdecl을 사용한다고 하나 실제 파라미터 전달방식을 보면 __fastcall과 같은데...뭔가 다른게 있는지는 확인되면 업데이트 해야겠네요. 또한 호출규약이 서로 맞지 않아도 RTC_CheckEsp에서 잡지 못하더군요...64비트에서는 RTC_CheckRsp일라나...또한 확인후...^^;
예제는 Visual Studio와 OllyDbg를 사용하여 분석하였다.
간단히 정리하면 아래와 같다.
__cdecl
|
__stdcall
|
__fastcall
|
|
파라미터 전달 방법
|
스택
|
스택
|
스택, 레지스터
|
스택 정리 담당
|
caller
|
callee
|
Callee(래지스터만사용시불필요)
|
1. __cdecl(C declaration)
C 및 C++ 프로그램의 기본 호출 규칙으로 Visual Studio 프로젝트 생성하면 디폴트로 __cdecl로 되어있다. main에서 sum 함수를 호출할때 push로 파라미터를 stack에 저장하고 call 한 후 다시 Add ESP, 8을 하여 사용했던 stack을 반환하는것을 볼 수 있다. operator new, delete등 C, C++ 함수는 함수 포인터 얻을때 typedef 시 호출규약을 __cdecl로 정의해주어야 한다.
2. __stdcall
Win32 API 함수를 호출하는데 사용된다. WINAPI로 재정의 되있다. 그러므로 callback 함수등 정의시 함수 앞에 WINAPI라고 호출규약을 명시해주어야 한다. sum함수 앞에 명시적으로 __stdcall을 써서 호출규약을 정해주었다. OllyDbg로 해당 바이너리를 열어서 보면 __cdecl과 다르게 main에서 스택을 이용해서 파라미터를 전달하고 있으나 sum함수 콜 한 후 esp를 정리하는 부분이 없다. 대신 sum 함수에 보면 마지막에 retn 8을 하는데 이는 pop 8하여 stack을 정리하고 return 하는 역할을 한다.
3. __fastcall
64bit 시스템에서는 기본으로 레지스터를 이용해서 파라미터를 전달하는데 32bit 시스템에서는 __fastcall이라는 호출규약을 통해서 레지스터를 이용하게 강제할 수 있다. 레지스터를 이용함으로써 좀 더 빠른 함수 호출이 가능하다. 스택을 사용하지 않았기때문에 스택을 정리할 필요도 없겠지요. 만약 파라미터가 많아서 레지스터가 모자라다고 하면 그때 스택을 이용하게 되고 그 후 정리는 __stdcall과 같이 callee쪽에서 하게 됩니다.
4. __thiscall
클래스의 멤버함수에서만 사용되는 호출규약으로 클래스 포인터를 스택이 아닌 ecx를 통해 넘기겠다는 규약이다. __stdcall과 유사하나 클래스 포인터가 스택이 아닌 ecx를 통해 전달된다.
호출규약이 서로 맞게 되있는지 확인하기 위해선 VS 옵션인 C/C++>코드생성>기본 런타임 검사 를 실시한다. 만약 호출규약이 서로 맞지 않으면 RTC_CheckEsp에서 에러를 리턴하여 확인할 수 있다.
이번에는 32bit 프로세스를 분석하였는데 64bit에서는 어떤지 궁금하네요
64비트에서는 여전히 __stdcall과 __cdecl을 사용한다고 하나 실제 파라미터 전달방식을 보면 __fastcall과 같은데...뭔가 다른게 있는지는 확인되면 업데이트 해야겠네요. 또한 호출규약이 서로 맞지 않아도 RTC_CheckEsp에서 잡지 못하더군요...64비트에서는 RTC_CheckRsp일라나...또한 확인후...^^;
다음에~ to be continume
2015년 8월 28일 금요일
[OllyDbg]main함수 찾는 방법(API 검색)
OllyDbg에서 내가 원하는 코드를 찾는 방법(OllyDbg110)
간단한 프로그램 실행중 Win32 API가 추측이 되면 검색하여 코드를 찾는 방법입니다.
여러가지가 있지만 일단 제가 사용하는 방법을 공유합니다.
먼저 lv.exe 바이너리를 open하면 바로 lv.exe의 entry point로 이동하는것이 아니라 시스템 영역(ntdll)에서 시작합니다.
여기서 일단 lv 코드 영역으로 이동을 해야합니다.
F7을 눌러서 코드영역에 lv 모듈로 넘어갈때까지 진행하셔도 되고 Memory Map을 이용하셔서 바로 이동해도 됩니다.
코드 영역에서 Alt+M을 클릭하면 Memory Map이 나오고 lv의 text 영역의 시작주소를 확인하여 코드영역을 선택한 후 Ctrl+G를 이용하여 해당 주소로 이동하면 됩니다.
module lv 영역으로 진입후
코드 영역의 마우스 우클릭 메뉴에서 Search for > All intermodular calls 를 선택합니다.
아래와 같이 사용하고 있는 API 목록이 오른쪽에 보여집니다.
위는 printf 함수를 보여주고 있습니다.
이를 더블클릭하면 원하는 곳으로 이동합니다.
간단한 프로그램 실행중 Win32 API가 추측이 되면 검색하여 코드를 찾는 방법입니다.
여러가지가 있지만 일단 제가 사용하는 방법을 공유합니다.
먼저 lv.exe 바이너리를 open하면 바로 lv.exe의 entry point로 이동하는것이 아니라 시스템 영역(ntdll)에서 시작합니다.
F7을 눌러서 코드영역에 lv 모듈로 넘어갈때까지 진행하셔도 되고 Memory Map을 이용하셔서 바로 이동해도 됩니다.
코드 영역에서 Alt+M을 클릭하면 Memory Map이 나오고 lv의 text 영역의 시작주소를 확인하여 코드영역을 선택한 후 Ctrl+G를 이용하여 해당 주소로 이동하면 됩니다.
module lv 영역으로 진입후
코드 영역의 마우스 우클릭 메뉴에서 Search for > All intermodular calls 를 선택합니다.
아래와 같이 사용하고 있는 API 목록이 오른쪽에 보여집니다.
위는 printf 함수를 보여주고 있습니다.
이를 더블클릭하면 원하는 곳으로 이동합니다.
2015년 8월 7일 금요일
[WinDbg] 조건부 브레이크포인트 (breakpoints with commands)
windbg로 rdp 리버싱중 rdpwsx!WsxIcaStackIoControl의 38009b 파라미터를 넣었을때만 리버싱을 진행하고 싶었다.
하지만 StackIoControl은 입력 파라미터에 따른 output 데이타가 다른 함수로 많은 정보를 이 함수로 얻어내고 있는 듯 보였다. 하지만 나는 38009b 일때의 정보만이 관심이 있을뿐...
조건을 걸어 브레이크를 걸수 있으면 좋을거 같단 생각이 들었다.
아래 사이트는 common windbg commands 이다.
http://windbg.info/doc/1-common-cmds.html
windbg에는 breakpoints를 걸때 사용할 수 있는 options 및 commands를 지원하여 확장성 및 편의성을 높이고 있었다.
bp [Addr][Options]
bp [Addr]["CmdString"]
단순히 hitting 수로 거는 옵션을 제공하고 조건문을 넣을수 있는 cmdstring을 지원했다.
나는 bp rdpwsx!WsxIcaStackIoControl ".if(r9==0x38009b){} .else{gc}" 로 원하는 조건에 맞는 순간을 잡을 수 있었다.
시스템 리버싱할때는 레지스터값을 주로 보겠지만 드라이버에서 변수값을 조건에 넣고 싶을때는 아래와 같이 사용한다.
bp Function ".if@@(변수==값){} .else{gc}"
좀 더 자세한 조건부 사용법은 아래 사이트를 참고하자.
https://msdn.microsoft.com/en-us/library/windows/hardware/ff556853(v=vs.85).aspx
좀 더 많은 조건부를 사용해보고 다시 정리하도록 해야겠다.
하지만 StackIoControl은 입력 파라미터에 따른 output 데이타가 다른 함수로 많은 정보를 이 함수로 얻어내고 있는 듯 보였다. 하지만 나는 38009b 일때의 정보만이 관심이 있을뿐...
조건을 걸어 브레이크를 걸수 있으면 좋을거 같단 생각이 들었다.
아래 사이트는 common windbg commands 이다.
http://windbg.info/doc/1-common-cmds.html
windbg에는 breakpoints를 걸때 사용할 수 있는 options 및 commands를 지원하여 확장성 및 편의성을 높이고 있었다.
bp [Addr][Options]
bp [Addr]["CmdString"]
단순히 hitting 수로 거는 옵션을 제공하고 조건문을 넣을수 있는 cmdstring을 지원했다.
나는 bp rdpwsx!WsxIcaStackIoControl ".if(r9==0x38009b){} .else{gc}" 로 원하는 조건에 맞는 순간을 잡을 수 있었다.
시스템 리버싱할때는 레지스터값을 주로 보겠지만 드라이버에서 변수값을 조건에 넣고 싶을때는 아래와 같이 사용한다.
bp Function ".if@@(변수==값){} .else{gc}"
좀 더 자세한 조건부 사용법은 아래 사이트를 참고하자.
https://msdn.microsoft.com/en-us/library/windows/hardware/ff556853(v=vs.85).aspx
좀 더 많은 조건부를 사용해보고 다시 정리하도록 해야겠다.
피드 구독하기:
글 (Atom)