일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 3단계 지역 DB
- reversing.kr
- EER
- 동읍면 DB
- react
- 방명록 만들기
- 소프트웨어 개발보안 경진대회
- spring
- 인턴 지원
- Forensic 절차
- jsp
- Layered Architecture
- SessionAttribute
- riceteacatpanda
- Django
- PyAmdecoder
- frontend
- 메모리 포랜식
- 인턴 후기
- 행정지역 DB
- 소개딩
- DBMS
- webhacking 처음
- 네이버 인턴
- restapi
- Database
- ㅁㅇㅂ??ㅇㅈㄷ ㅎㅇㅌ...
- 정보보호병 후기
- mysql
- JSTL
- Today
- Total
웹찢남
Decoding Algorithm of AndroidManifest.XML 본문
1) 간단한 android app 구현
2) apk속 AndroidManifest.xml 추출
그 후 기존의 AndroidManifest.xml과 비교를 하며 encoding된 AndroidManifest.xml의 구조 분석
3) encoding된 AndroidManifest.xml 구조 분석
00000000 03 00 // Type (XML)
00000002 08 00 // Header Size
00000004 BC 08 00 00 // Chunk Size
------------------------------------------
00000008 01 00 // Type (String_Pool)
0000000a 1C 00 // Header Size
0000000c FC 04 00 00 // Chunk Size
------------------------------------------
00000010 21 00 00 00 // stringCount – 33개
00000014 00 00 00 00 // styleCount
00000018 00 00 00 00 // flags
0000001c A0 00 00 00 // StringsStart (address 000000a8)
00000020 00 00 00 00 // StylesStart
-----------------------------------------
00000024 00 00 00 00 // String[0] 00000028 0E 00 00 00 // String[1]
0000002c 1C 00 00 00// String[2] 00000030 28 00 00 00 // String[3]
00000034 34 00 00 00// String[4] 00000038 52 00 00 00// String[5]
0000003c 6C 00 00 00// String[6] 00000040 86 00 00 00 // String[7]
------ string[8] ~ string [25] -------
0000008c 42 03 00 00// String[26] 00000090 9A 03 00 00// String[27]
00000094 B8 03 00 00// String[28] 00000098 CC 03 00 00// String[29]
0000009c DE 03 00 00// String[30] 000000a0 12 04 00 00// String[31]
000000a4 46 04 00 00// String[32]
000000a8 05 00 74 00 68 00 65 00 6D 00 65 00 00 // [0] : theme
000000b6 05 00 6C 00 61 00 62 00 65 00 6C 00 00 00 // [1] : label
000000c4 04 00 69 00 63 00 6F 00 6E 00 00 00 // [2] : icon
000000d0 04 00 6E 00 61 00 6D 00 65 00 00 00 // [3] : name
000000dc 0D 00 6D 00 69 00 6E 00 53 00 64 00 6B 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 00 00 // [4] : minSdkVersion
000000fa 0B 00 76 00 65 00 72 00 73 00 69 00 6F 00 6E 00 43 00 6F 00 64 00 65 00 00 00 // [5] : versionCode
00000115 0B 00 76 00 65 00 72 00 73 00 69 00 6F 00 6E 00 4E 00 61 00 6D 00 65 00 00 // [6] : versionName
0000012d 00 10 00 74 00 61 00 72 00 67 00 65 00 74 00 53 00 64 00 6B 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 // [7] : targetSdkVersion
00000152 0B 00 61 00 6C 00 6C 00 6F 00 77 00 42 00 61 00 63 00 6B 00 75 00 70 00 00 00 // [8]: allowBackup
0000016c 0B 00 73 00 75 00 70 00 70 00 6F 00 72 00 74 00 73 00 52 00 74 00 6C 00 00 00 // [9]: supportsRtl
00000186 09 00 72 00 6F 00 75 00 6E 00 64 00 49 00 63 00 6F 00 6E 00 00 00 // [10]: roundIcon
0000019c 11 00 63 00 6F 00 6D 00 70 00 69 00 6C 00 65 00 53 00 64 00 6B 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 00 00 // [11]: compilesdkversion
000001c2 19 00 63 00 6F 00 6D 00 70 00 69 00 6C 00 65 00 53 00 64 00 6B 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 43 00 6F 00 64 00 65 00 6E 00 61 00 6D 00 65 00 00 00 // [12]: compilesdkversioncodename
000001f8 13 00 61 00 70 00 70 00 43 00 6F 00 6D 00 70 00 6F 00 6E 00 65 00 6E 00 74 00 46 00 61 00 63 00 74 00 6F 00 72 00 79 00 00 00 // [13]: appcomponentFactory
00000222 03 00 31 00 2E 00 30 00 00 00 // [14]: 1.0
0000022c 02 00 31 00 31 00 00 00 // [15]:11
00000235 06 00 61 00 63 00 74 00 69 00 6F 00 6E 00 00 00 // [16]: action
00000245 08 00 61 00 63 00 74 00 69 00 76 00 69 00 74 00 79 00 00 00 // [17]: activity
00000258 07 00 61 00 6E 00 64 00 72 00 6F 00 69 00 64 00 00 00 // [18]: android
0000026a 1A 00 61 00 6E 00 64 00 72 00 6F 00 69 00 64 00 2E 00 69 00 6E 00 74 00 65 00 6E 00 74 00 2E 00 61 00 63 00 74 00 69 00 6F 00 6E 00 2E 00 4D 00 41 00 49 00 4E 00 00 00 // [19]: android.intent.action.MAIN
000002a2 20 00 61 00 6E 00 64 00 72 00 6F 00 69 00 64 00 2E 00 69 00 6E 00 74 00 65 00 6E 00 74 00 2E 00 63 00 61 00 74 00 65 00 67 00 6F 00 72 00 79 00 2E 00 4C 00 41 00 55 00 4E 00 43 00 48 00 45 00 52 00 00 00 // [20]: android.intent.category.LAUNCHER
000002e6 26 00 61 00 6E 00 64 00 72 00 6F 00 69 00 64 00 78 00 2E 00 63 00 6F 00 72 00 65 00 2E 00 61 00 70 00 70 00 2E 00 43 00 6F 00 72 00 65 00 43 00 6F 00 6D 00 70 00 6F 00 6E 00 65 00 6E 00 74 00 46 00 61 00 63 00 74 00 6F 00 72 00 79 00 00 00 // [21]: androidx.core.app.CoreComponentFactory
00000336 0B 00 61 00 70 00 70 00 6C 00 69 00 63 00 61 00 74 00 69 00 6F 00 6E 00 00 00 // [22]: application
00000350 08 00 63 00 61 00 74 00 65 00 67 00 6F 00 72 00 79 00 00 00 // [23]: category
00000364 19 00 63 00 6F 00 6D 00 2E 00 65 00 78 00 61 00 6D 00 70 00 6C 00 65 00 2E 00 6D 00 79 00 61 00 70 00 70 00 6C 00 69 00 63 00 61 00 74 00 69 00 6F 00 6E 00 00 00 // [24]: com.example.myapplication
0000039a 26 00 63 00 6F 00 6D 00 2E 00 65 00 78 00 61 00 6D 00 70 00 6C 00 65 00 2E 00 6D 00 79 00 61 00 70 00 70 00 6C 00 69 00 63 00 61 00 74 00 69 00 6F 00 6E 00 2E 00 4D 00 61 00 69 00 6E 00 41 00 63 00 74 00 69 00 76 00 69 00 74 00 79 00 00 00 // [25]: com.example.myapplication.MainActivity
000003ea 2A 00 68 00 74 00 74 00 70 00 3A 00 2F 00 2F 00 73 00 63 00 68 00 65 00 6D 00 61 00 73 00 2E 00 61 00 6E 00 64 00 72 00 6F 00 69 00 64 00 2E 00 63 00 6F 00 6D 00 2F 00 61 00 70 00 6B 00 2F 00 72 00 65 00 73 00 2F 00 61 00 6E 00 64 00 72 00 6F 00 69 00 64 00 00 00 // [26]: http://schemas.android.com/apk/res/android
00000442 0D 00 69 00 6E 00 74 00 65 00 6E 00 74 00 2D 00 66 00 69 00 6C 00 74 00 65 00 72 00 00 00 // [27]: intent-filter
00000460 08 00 6D 00 61 00 6E 00 69 00 66 00 65 00 73 00 74 00 00 00 // [28]: manifest
00000474 07 00 70 00 61 00 63 00 6B 00 61 00 67 00 65 00 00 00 // [29]: package
00000486 18 00 70 00 6C 00 61 00 74 00 66 00 6F 00 72 00 6D 00 42 00 75 00 69 00 6C 00 64 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 43 00 6F 00 64 00 65 00 00 00 // [30]: platformBuildVersionCode
000004ba 18 00 70 00 6C 00 61 00 74 00 66 00 6F 00 72 00 6D 00 42 00 75 00 69 00 6C 00 64 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 4E 00 61 00 6D 00 65 00 00 00 // [31] : platformBuildVersionName
000004ee 08 00 75 00 73 00 65 00 73 00 2D 00 73 00 64 00 6B 00 00 00 // [32] : uses-sdk
String_Pool 정리 |
|||
0 |
Theme |
11 |
Activity |
1 |
Label |
12 |
android |
2 |
Icon |
13 |
android.intent.action.MAIN |
3 |
name |
14 |
android.intent.category.LAUNCHER |
4 |
minSdkVersion |
15 |
androidx.core.app.CoreComponentFactory |
5 |
versionCode |
16 |
application |
6 |
versionName |
17 |
category |
7 |
targetSdkVersion |
18 |
com.example.myapplication |
8 |
allowBackup |
19 |
com.example.myapplication.MainActivity |
9 |
supportsRtl |
1a |
|
A |
roundIcon |
1b |
intent-filter |
B |
compilesdkversion |
1c |
manifest |
C |
compilesdkversioncodename |
1d |
package |
D |
appcomponentFactory |
1e |
platformBuildVersionCode |
E |
1,0 |
1f |
platformBuildVersionName |
F |
11 |
20 |
uses-sdk |
10 |
action |
X |
X |
---------------End of String Pool------------
00000504 80 01 // type [XML_RESOURCE_MAP]
00000506 08 00 // header size
00000508 40 00 00 00 // chunk size
------------------------------------------------
0000050c 00 00 01 01 // [0]
[1]~[8]
00000540 7A 05 01 01 // [9]
------------End of XML_RESOURCE_MAP--------
00000544 00 01 // type [XML_START_NAMESPACE]
00000546 10 00 // Header Size
00000548 18 00 00 00 // Chunk Size
0000054c 02 00 00 00 // LineNumber
00000550 FF FF FF FF // Comment
00000554 12 00 00 00 // prefix
00000558 1A 00 00 00 // uri
----------End of XML_START_NAMESPACE-------
0000055c 02 01 // type [XML_START_ELEMENT]
0000055e 10 00 // header size
00000560 B0 00 00 00 // chunk size (60c까지 chunk)
-------------------------------------------------
00000564 02 00 00 00 // lineNumber
00000568 FF FF FF FF // comment
--------------------------------------------------
0000056c FF FF FF FF // ns
00000570 1C 00 00 00 // name [manifest]
00000574 14 00 // attribute Start
00000576 14 00 // attribute Size
00000578 07 00 // attribute Count
0000057a 00 00 // id Index
0000057c 00 00 // class Index
0000057e 00 00 // styleIndex
00000580 1A 00 00 00 // attribute[0] ns
00000584 05 00 00 00 // attribute[0] name [versioncode]
00000588 FF FF FF FF // attribute[0] rawValue
0000058c 08 00 // size
0000058e 00 // 0
0000058f 10 // datatype = INT
00000590 01 00 00 00 // data = 1
00000594 1A 00 00 00 // attribute[1] ns
00000598 06 00 00 00 //attribute[1] name [versionname]
0000059c 0E 00 00 00 //attribute[1] raw Value
000005a0 08 00 // size
000005a2 00 // 0
000005a3 03 // datatype =StringPool
000005a4 0E 00 00 00 // data = 1.0
000005a8 ~ 00000874 (ELEMENTS)
0000088C 03 01 // type [XML_END_ELEMENT]
0000088E 10 00 // header size
00000890 18 00 00 00 // chunk Size
00000894 0B 00 00 00 // linenumber
00000898 FF FF FF FF // comment
0000089C FF FF FF FF // ns
000008A0 1C 00 00 00 // name
--------------End of xml_end_element--------------
000008A4 01 01 // type [XML_END_NAMESPACE]
000008A6 10 00 // header size
000008A8 18 00 00 00 // chunk size
000008AC 02 00 00 00 // line number
000008B0 FF FF FF FF // comment
000008B4 12 00 00 00 // prefix
000008B8 1A 00 00 00 // uri
-------------End of XML_END_NAMESPACE--------------
-------------End of XML-----------------------------------
4) Android_manifest.xml 오픈소스 decoder 사용
기존의 Android_manifest를 encoding 하고 decoding할 때 값이 바뀔 것이라 생각을 하여 decoding이 완료된 모습을 보기 위해 AXMLPrinter2를 사용해봤습니다. 아래의 결과를 목표로 decoder을 개발하기로 했습니다.
5) Manifest_decoder 개발
개발 환경은 python 3.7.9를 사용하였으며 3번의 제가 만든 encoding된 xml파일의 분석을 기준으로, 4번의 decoding 결과를 목표로 개발을 진행하였습니다.
개발 routine은 XML_header -> stringPool -> resource_map -> RECURSIVE(Start_namespace, start element , End_namespace, End element)로 계획을 세웠습니다.
코드를 3분할하여 코드를 설명하겠습니다.
lb는 byte를 int로 바꾸는 함수로 data를 처리할 때 값을 비교하거나 사용하기 위해 사용합니다.
check_routin”은 위에서 설명한 RECURSIVE( Start_namespace, start element , End_namespace, End element) 부분인데. Xml 파일을 분석해본 결과 resource_map 다음에 이 4개의 함수가 반복되어 한 함수에서 Chunk가 끝나면 check_routine으로 돌아와 앞 두 바이트를 통해 type을 확인하고 다른 함수로 넘어갑니다.
XML_END_ELEMENT는 START_ELEMENT와 대비되며 열린 태그를 닫습니다.
XML_ENDNAMESPACE는 end_prefix,uri를 반환하고 해당 함수의 data를 처리합니다.
XML_START_ELEMENT는 출력을 담당하는 함수입니다. 우선 ELEMENT의 Header 정보를 인자에 넘겨준 후 태그를 열고 값을 출력합니다. 보통의 manifest.xml에서는 다음과 같이 uri와 prefix를 설명하는 xmlns:android=http://schemas.android.com/apk/res/android line이 한 줄 나와 변수를 통해 한번만 나오도록 설정하였습니다. URI와 PREFIX는 namespace에서 인자로 넘기도록 하였습니다. 그 후 header에 있던 element_count만큼의 반복문을 돌립니다. 그 후 태그 내의 값들을 attribute_name=attribute_data 방식으로 출력합니다. 이때 element_type을 통해 type을 설정하는데 0x03일 경우 string_pool 속의 index가 data에 주어지고 0x01은 resource값으로@+hex값으로 표현합니다. 0x12는 Boolean값, 0x11은 hex값 0x10은 int로 int는 else처리를 했습니다. 그 후 for문이 끝난 후 다시 check_routine으로 돌아갑니다.
XML_START_NAMESPACE는 저장한 값인 prefix와 uri를 Start_ELEMENT 전달하는 역할을 합니다.
Resource_map의 역할에 대해 자료를 찾지 못해 해당 Chunk size만 처리하도록 하였는데 아마 start element속의 datatype인 0x01의 resourcetype내의 데이터를 처리하지 않나 생각합니다.
String_Pool함수는 Make_String_List에 count와 data를 넘겨줍니다. MakeStringList에서는 StringPool함수에서 받은 String_Count만큼의 for문을 돌리는데 이때 따로 전역 List를 만들어 해당 List에 string들을 append하여 추후에 사용할 수 있도록 저장합니다.
Main 함수에서는 HeaderSize가 끝난 후의 데이터를 String_Pool로 넘겨주는 역할을 합니다. 또한 맨 첫 라인이 sys.setrecursionlimit(10000) 인데, 카카오톡의 android_manifest.xml을 돌려본 결과 recursive로 코드를 짜 놓은 탓에 recursive func의 depth가 3000이 넘어가 오류가 발생하여 3000이 넘어도 돌아갈 수 있도록 10000으로 limit을 설정해 놨습니다.
6) 결과
아래와 같이 manifest.xml 오픈소스 decoder과 똑같은 결과를 이끌어 냈습니다. Indentation 또한 tab 인자를 따로 만들어 처리를 하는 등 보기에 불편함이 없도록 개발을 하였습니다. 오류의 해결에 관한 부분도 실제 상용 앱의 manifest.xml파일을 집어넣어 처리하며 여러 처리과정을 거쳤습니다.
위의 캡처는 추가로 카카오톡의 apk 속 androidmanifest.xml을 decoding한 것인데 문제없이 디코딩에 성공하였습니다.
7) pypi 배포
배포도 해봤습니다. 솔직히 pip 배포 경험을 위해 한거긴한데 급박하게 개발을 진행한 모듈이고 저의 apk에 맞춰 개발을 진행하여 다른 몇몇 apk에는 디코딩이 잘 이루어지지 않은 것 같긴한데, pypi 링크에 github 주소도 있으니 손봐서 사용하셔도 괜찮습니다!