본문 바로가기

0x00 /0x01 Reversing

- RVA to RAW (PE File 관련)

이번에는 "RVA to RAW"에 대해서 포스팅하도록 하겠습니다. "RVA to RAW"를 간단하게 설명하자면, RVA to RAW

   는 PE 파일이 메모리에 로딩되었을 때 각 섹션에서 메모리의 주소(RVA)와 File Offset(RAW)을 매핑하는 것을 말합니다.

   이전 PE File Format 포스팅에서 언급했던 VA와 RVA에 대해서 간단하게 다시 얘기하고 시작하도록 하겠습니다.

   RVA ↔ RAW(File Offset) 변환 작업은 PE 헤더를 공부할 때 가장 기본이 되는 개념이므로 잘 숙지하도록 합시다.





# RVA to RAW


- RVA는 PE 파일이 메모리에 로딩되었을 때의 메모리 주소를 의미하고, RAW는 PE 파일이 로딩되기 전에 File Offset 의미합니다.

- RVA to RAW는 PE 파일의 각 섹션이 메모리에 로딩되기 전의 File Offset과 메모리에 로딩된 후에 로딩된 위치의 주소를 매칭하는 것입니다.




# RVA to RAW 방법 (매핑하는 방법)


  ① RVA가 속해 있는 섹션을 찾는다.

  ② RAW 구하는 비례식을 이용하여 RAW(File Offset)을 구한다.







# RVA to RAW 매핑하는 방법은 위의 설명 처럼 간단합니다. 익숙해질 수 있도록 연습을 해보도록 하겠습니다.




- 바로 위에 보이시는 그림이 Windows7 운영체제의 Calc,exe 파일이 메모리에 로딩되는 모습을 그려놓은 것입니다. 이그림을 가지고 매핑

  하는 연습을 해보도록 하겠습니다.


- 우선 왼쪽편이 File (Offset) 입니다. 오른쪽편이 Memory 구요. 이전 PE File Format 포스팅에서 언급했었는데, PE File 일 때의 섹션 크기와

  위는 Memory에 로딩되면 각 섹션의 크기와 위치가 달라진다고 했었습니다. ( 크게 변하진 않지만, 동일하진 않다고 했었습니다 )


- 위에 그림에서 보이시는 File의 Offset과 Memory에서의 VA(Virtual Address)는 제가 PE View 툴을 이용하여 다 구한 값들입니다. File에서의

  섹션 크기와 Memory에서의 섹션 크기가 조금씩 다르신게 보이시죠? 앞에서 말했듯이 크게 변하진 않았습니다. 우선 이런점들을 미리 알고 계

  셔야 "RVA to RAW"를 이해하시기 편하실것 같습니다.


- 예제 문제를 풀기전에 VA(Virtual Address)와 RVA(Relative Virtual Address)에 대해서 다시 한번 정리하고 예제 문제를 풀어보도록 하겠습

  니다.





- RVA to RAW 비례식을 이용하여 RAW 주소를 구할 수 있는데요. 이 비례식에 존재하는 VirtualAddress는 우리가 지금껏 말하고 있던 VA

  (Virtual Address)가 아닙니다. VA는 프로세스의 메모리에서의 절대주소라고 설명했습니다. 위에서 RAW(Offset)를 구하기 위한 식에서의

  VA(VirtualAddress)는 Section Header의 멤버인 VirtualAddress를 의미합니다. Section Header 구조체의 멤버인 VirtualAddress 멤버는

  메모리에서 섹션의 시작 주소(RVA)를 의미합니다. 결론적으로 RAW 비례식에서의 VirtualAddress는 우리가 앞에서 계속 얘기하던 RVA

  (프로세스 메모리에서의 상대주소)를 말하는 것입니다. 이 부분만 주의하신다면 쉽게 매핑할 수 있으리라 생각합니다.

  ( 저는 RAW를 구하는 비례식의 VirtualAddress가 프로세스 가상 메모리의 절대주소를 의미하는 것인줄 알고 한참 삽질을 했습니다. )








# 1. RVA = 3000일 때 File Offset (RAW) 은 얼마인가 ?


  - RVA 값이 3000입니다. RVA는 프로세스 가상 메모리에서의 상대주소입니다. 위에 Memory 쪽의 VA를 보시면 제일 처음 "01000000"으로 시작

     하는 것을 볼 수 있는데요. 바로 저 값이 기준 위치가 되는 ImageBase 값입니다. [ ImageBase = 01000000 ]

   

  - 지금부터 RVA to RAW 매핑 방법대로 순서대로 해보도록 하죠. 첫 번째가 주어진 RVA가 속해있는 섹션이 어떤 섹션인지 찾는 것입니다. 

    위 그림을 보시면 메모리상에서 .text 섹션의 시작 RVA가 1000이고, 크기가 52CA1이니까 53CA1까지 .text 섹션이 되겠네요. RVA 3000은 

    .text 섹션에 포함되는 군요. [ RVA = 3000 해당 섹션 → .text 섹션 ]


 - 이제 두 번째 해야할 것이 RAW 비례식을 이용하여 RAW (Offset)을 구하는 것입니다. 비레식을 이용해서 구해보도록 하죠.

   식 : 3000 (RVA) - 1000 (VirtualAddress) + 400 (PointerToRawData) = 2400 (RAW)


 * RAW 비례식에서의 VirtualAddress와 PointerToRawData는 Section Header 구조체의 멤버들로, VirtualAddress는 메모리에서 섹션의 시작

   주소(RVA)를 의미하고, PointerToRawData는 파일에서 섹션의 시작 위치를 의미합니다.



 * RVA to RAW 가 어떤것인지 이제 어느정도 감이 오시죠? 리버싱 관련 작업들을 할 땐 이렇게 RVA에서 RAW로 RAW에서 RVA로 바꾸는 작업이

   가장 기본이 된다고 하네요. 꼭 숙지하도록 해야겠습니다. 예제 하나만 더 풀어보고 이번 포스팅을 마치도록 하겠습니다.




# 2. RVA = BC123일 때 File Offset (RAW) 은 얼마인가 ?


  - RVA = BC123 입니다. 해당 RVA가 속해 있는 섹션을 찾아보니, .reloc 섹션에 포함되어있네요.  [ RVA = BC123 해당 섹션 → .reloc 섹션 ]


  - 식 : BC123 (RVA) - BC000 (VirtualAddress) + B9C00 (PointerToRawData) = B9D23 (RAW)


  - 위에서 처럼 RAW (Offset)을 구한 후에는 실제로 그 Offset에 해당 섹션이 있는지 확인하셔야합니다. 혹시 메모리상에서 포함되었던

    섹션이 아니거나, 벗어난다면 " 해당 RVA에 대한 RAW를 정의할 수 없다" 라고 해야 합니다. 이렇게 딱 떨어지지 않는 경우가 Virtual

    Size와 SizeOfRawData 값이 서로 달라서 벌어지는 일들이라고 하는데요. 이러한 부분은 좀 더 공부를 한 후에 알 수 있다고 하네요.




# "RVA to RAW"에 대해서 알아 봤는데요. 생각보다 쉬운 내용이었던 것 같습니다. 




# 참고 도서 : 리버싱 핵심원리