이 문제 역시 입력을 받고 맞으면 correct 틀리면 wrong을 출력해주는 문제이다.

 

검증하는 부분을 살펴보면 

 

참고한 사이트를 보고 정리해보면..

ROL과 ROR은 어셈블리어에서 시프트 연산을 맞는다.

ROR은 오른쪽으로 시프트연산을 하고 ROL은 왼쪽으로 시프트 연산을 한다.

비트회전은 비트를 잃어버리지 않는다. 한쪽 끝에서 회전되어 나온 비트는 다른 한쪽 끝에서 다시 나타난다.

ROL operand1 operand2이면 operand1을 왼쪽으로 operand2만큼 민다. 비트가 넘치면 그 뒤로 받는다.

ROR은 오른쪽으로 민다.

 

MOVZX와 MOVSX명령어

-MOV명령어는 목적지의 피연산자의 길이는 원시 피연산자의 길이와 반드시 일치해야 된다. 바이트는 바이트로 워드는 워드로 전송해야 된다.

MOVZX와 MOVSX명령어는 바이트나 워드의 원시 피연산자를 워드나 더블워드의 목적지 피연산자로 데이터를 전송하는것을 가능하게 해준다.

 

MOVZX

- 부호없는 산술 값에 대해 사용된다.

- 바이트나 워드를 워드나 더블워드 목적지에 전송할수 있다.

- 0비트로 목적지 피연산자의 왼쪽 비트들을 채운다.

 

MOVSX

- 부호있는 산술 값에 대해 사용

- 바이트나 워드를 워드나 더블워드의 목적지에 전송할 수 있다.

- 부호비트(원시 피연산자의 맨 왼쪽비트)로 목적지 피연산자의 왼쪽 비트들을 채운다.

 

movzx

정리하면 하나의 식이 나오는데 (p[i] rol(i&7)^i==e[i]가 나온다...

이것을 계산하기 위해 코드를 짜야 되는데..rol,ror코드를 구현하는 것들이 있다.

FLAG를 찾기 위해 블로그를 참고해서 답을 얻을 수 있었고 코드가 짜여지는것은 더 공부해봐야 될것 같다,,

 

참고

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=hot_tracks&logNo=20157707672

https://sandwichmaker.tistory.com/54

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=sol9501&logNo=70091168321

https://s0ngsari.tistory.com/entry/ROL-ROR

DLL

- 여러 함수들이 모인 라이브러리 파일

- 프로그램에서 라이브러리 함수를 사용하게 되면 해당되는 DLL을 불러와 사용

- 이런 DLL 로딩 방식이 Implict Linking, Explict Linking 두 가지 방식이 존재함

 

IAT

- 프로그램이 어떤 라이브러리에서 어떤 함수를 사용하고 있는지를 기술한 테이블

- 프로그램이 켜지는 순간 프로그램에서 사용하는 DLL들을 불러온 후, 프로그램 종료시 DLL들을 다시 해제시키는 방법에 대한 메카니즘 제공(Implict Linking)

 

IMAGE_IMPORT_DESCRIPTOR(IID)

= 자신이 어떤 라이브러리를 import하고 있는지 명시해주는 구조체

- OriginalFirstThunk = INT(Import Name Table)의 주소 RVA

- Name = Library일므 문자열의 주소 RVA

- FirstThunk = IAT의 주소 RVA

 

IMAGE_THUNK_DATA32

= INT와 IAT를 구성하고 있는 구조체, INT와 IAT의 크기는 동일

 IAT와 INT는 IMAGE_THUNK_DATA32 구조체 배열로 구성된다.

따라서OriginalFirstThunk와 FirstThunk는 IMAGE_THUNK_DATA32 구조체 배열의 주소(RVA)을 가진다.

 

IMAGE_IMPORT_BY_NAME

 

과정

1. IID의 Name멤버를 읽어서 라이브러리의 이름 문자열을 얻는다.

2. 해당 라이브러리를 로딩한다. ex) LoadLibrary("ADVAP132.dll")

3. IID의 OriginalFirstThunk멤버를 읽어서 INT주소를 얻는다.

4. INT에서 배열의 값을 하나씩 읽어 해당 IMAGE_IMPORT_BY_NAME주소(RVA)를 얻는다.

5. IMAGE_IMPORT_BY_NAME의 hint of name의 이용하여 해당 함수의 시작 주소를 얻는다. GetProcAddress("OpenProcessToken")

6. IID의 FirstThunk 멤버를 읽어서 iat의 주소를 얻는다.

7. 해당 IAT배열 값에 위에서 구한 함수 주소를 입력한다.

8. INT가 끝날 떄까지 (NULL을 만날때 까지) 4-7의 과정을 반복한다.

 

IAT실습

RVA = 7604

해당 주소에 들어가면 IMPORT Table의 RVA뒤쪽이 Size이다.

RVA를 알기 때문에 offset(RAW)를 구한다.

7604 - 1000 + 0400 = 6A04이므로 파일에서 6A04를 보면 밑과 같다.

RAW값을 보면 다음과 같다.

Description RAQ
INT 00006D90
Time Date Stamp -
Forwarder Chain -
Name 00006EAC
IAT 000006C4

1. Name 00006EAC

2. INT 00006D90

INT는 임포트 하는 함수의 정보가 담긴 구조체 포인터 배열이다. 프로세스 메모리에 로딩된 라이브러리에서 해당 함수의 시작주소를 알아낼 수 있다. 주속값 하나하나가 각각의 IMAGE_IMPORT_BY_NAME구조체를 가리키고 있다.

 

3. IMAGE_IMPORT_BY_NAME

RVA: 7A7A를 RAW로 변환한다.

7A7A + 1000 - 0400 = 6E7A

제일 앞에 ...(000F)는 라이브러리에서 함수의 고유번호라고 한다. 이 Oridinal뒤에 함수 이름 문자열을 보면 INT는 IMAGE_IMPORT_BY_NAME구조체의 포인터 배열임을 알수 있다.

 

4. IAT 000006C4

comdlg32.dll라이브러리에 해당하는 IAT배열 영역이다. IAT의 첫번째 원소값인 76324906은 의미 없는 값이고 메모리에 로딩될때 정확한 주소값으로 대체된다.


EAT

프로그램에서 어떤 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 사용할 수 있도록 해주는 핵심 메커니즘이다. 즉 EAT를 통해서만 해당 라이브러리에서 익스포트하는 함수의 시작 주소를 정확히 구할 수 있다.

 

- IAT와 마찬가지로 PE 파일 내의 특정 구조체 IMAGE_EXPORT_DIRECTORY에 익스포트 정보를 저장하고 있으며 라이브러리의 EAT를 설명하는 이 구조체는 PE파일에 하나만 존재한다.

- PE 파일에서 IMAGE_EXPORT_DIRECTORY구조체의 위치는 PE헤더에서 찾을 수 있으며IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress값이 실제  IMAGE_EXPORT_DIRECTORY구조체 배열의 시작주소이다.

 

항목 의미
NumberOfFunctions 실제 Export 함수 개수
NumberOfNames Export함수 중에서 이름을 가지는 함수 개수
AddressOfFunctions Export함수 주소 배열
AddressOfNames 함수 이름 주소 배열
AddressOfNameOrdinals Ordinal배열

 

EAT로딩 과정

1. AddressOfNames멤버를 이용해 함수이름 배열로 이동

2. 함수이름배열은 문자열 주소가 있으므로 문자열 비교를 통하여 원하는 함수 이름을 찾는다.

3. AddressOfNameOrdinals멤버를 이용하여 'ordinal'배열로 이동

4. 'ordinal배열'에서 name_index를 이용하여 해당 ordinal값을 찾는다.

5. AddressOfFunctions멤버를 이용하여 함수 주소 배열로 이동한다.

6. EAT에서 ordinal을 배열 인덱스로 하여 원하는 함수의 시작주소를 얻는다.

 

해당 주소로 이동한 모습니다.

IAT와 같이 앞쪽 4바이트가 RVA 뒤쪽 4바이트가 Size의 멤버임을 볼 수 있다.

 

RVA값이 262C이므로 RAW를 께산해보면 262C - 100 + 0400 = 1A2C이다.

항목 의미
NumberOfFunctions 실제 Export함수 개수
NumberOfNames Export함수 중에서 이름을 가지는 함수 개수
AddressOfFuncions Export 함수 주소 배열
AddressOfNames 함수 이름 주소 배열
AddressOfNmaeOrdinals Ordinal배열

라이브러리에서 함수 주소를 얻는 API는 GetProcAddress()이다.  API가 EAT를 참조해서 원하는 API주소를 휙득한다.

 

1. 함수 이름배열

AddOfNames멤버의 RVA = 3538RAW = 3538 - 1000 _ 0400 = 2938
2. AddAtom은 AddOfNames의 RVA들 중에 3번째에 속해있고 배열 인덱스로는 2가 된다.

 

3. Oridnal배열AddAtom함수의 Oridnal값을 알아낸다 멤버값은 441c RAW : 381C이다.

4. ordinal

AddressOfNameOrdinal[index] = ordinal ( index = 2, ordinal = 2)

 

5. 함수 주소 배열

RAW : 1A54이다.

 

참고

https://kyumoonhan.tistory.com/119

https://su0-0su.tistory.com/56

이번 문제 역시 입력을 받고 맞으면 correct 틀리면 wrong을 출력해주는 문제이다.

 

je부분을 통해 correct일지 wrong일지가 나뉘는것을 볼 수 있다.

함수를 살펴보면

rax = [rsb]

rcx = [rsp+20]

eax = [rcx + rax]

rcx에 src1의 주소 대입

eax = [rcx+rax] : src1[str[cnt]]

rcx = [rsp]

rdx에 src2의 주소 대입

ecx = [rdx + rcx] : src2[cnt]

cmp(eax,ecx)

 

src1의 인덱스 역할을 하는 str[cnt]의 값은 char자료형이기 때문에 src1의 메모리를 0x7f까지 참조한다.

파이썬으로 계산을 해주면 

일단 정답이 나오기는 했는데 블로그를 참고하면서 풀어서 다시 풀어봐야 될것같다. 

'보안 > 리버싱' 카테고리의 다른 글

[리버싱] 드림핵 rev-basic-7 풀이  (0) 2021.11.13
IAT, EAT 로딩 과정  (0) 2021.10.02
[리버싱] 드림핵 rev-basic-5 풀이  (0) 2021.10.02
[리버싱] 드림핵 rev-basic-4 풀이  (0) 2021.10.02
[리버싱]pe 헤더 정리  (0) 2021.09.25

이번 문제 역시 값을 입력받고 맞으면 correct 틀리면 wrong을 출력하는 문제이다.

이번 역시 값을 결정해주는 부분같은 call부분을 들어가 보았다.

inc eax부분을 통해 eax에 입력된 값 중 가장 첫번째 값을 넣는것을 알수 있따.

ecx에 +1을 수행해준다

add eax,ecx를 통해 eax+ecx값을 eax에 넣는다는 것을 알 수 있다.

 

lea rdx,qword ptr ds:[7FF655AC3000]부분을 통해 주소에 있는 값을 ecx에 넣고 eax와 비교하는 것을 알 수 있다.

주소에 해당하는 덤프를 따라갔다.

 

이문제의 계산되는 방식을 정리하면 밑에 식처럼 반복하는 것을 볼 수있다.

str[0] + str[1] = src[0]

str[1] + str[2] = src[1]

... 

str[0x16] + str[0x18] = src[0x16]

str[0x17] + str[0x18] = src[0x17]

 

str[0x17] + str[0x18] = 0이고 str[0x17] = str[0x18]=0인 결론이 나온다.

str[0x16] + 0 = 4C니까 str[0x16] = 4c라는 것을 알 수 있다.

 

계산방법으로 코드를 짜면 밑과 같다.(코드부분은 블로그를 참고하여 해결하였다.)

'보안 > 리버싱' 카테고리의 다른 글

IAT, EAT 로딩 과정  (0) 2021.10.02
[리버싱] 드림핵 rev-basic-6 풀이  (0) 2021.10.02
[리버싱] 드림핵 rev-basic-4 풀이  (0) 2021.10.02
[리버싱]pe 헤더 정리  (0) 2021.09.25
[리버싱]패킷 & UPX 문서화  (0) 2021.09.25

+ Recent posts