zipalign 과 apksigner 를 활용해서 안드로이드 애플리케이션에 서명하는 방법에 대한 포스팅이다.
리패키징 테스트를 할 때 기존에는 jarsigner 로 서명을 했지만 Android 11 이상부터는 apksigner 로 서명해야 앱이 설치된다.
테스트에 앞서 환경 변수 세팅은 다음과 같다.
# keytool
C:\Program Files\Java\jdk1.8.0_202\bin
# zipalign, apksigner
C:\Users\user\AppData\Local\Android\Sdk\build-tools\32.1.0-rc1
앱 서명을 테스트하기 위해 안드로이드 스튜디오에서 간단한 코드를 작성한다.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, "Sign Test !", Toast.LENGTH_SHORT).show();
}
}
다음으로 Build
> Generate Signed Bundle or APK
메뉴에 접근한다.
Next
> Create new...
> 키 정보 입력 후 OK
버튼을 클릭해서 키를 생성한다.
아까 생성한 키 정보를 입력하고 Next
> Release 체크 후 Finish
버튼을 클릭하면 앱 서명이 완료된다.
그러나 keytool
명령어로 확인해보니 이상하다. 다른 블로그에서는 잘 떴던 것 같은데..
> keytool -printcert -jarfile app-release.apk
서명된 jar 파일이 아닙니다.
그래서 그냥 zipalign
과 apksigner
를 활용해서 직접 서명을 해보자.
먼저 생성한 apk 파일을 zipalign
명령어를 통해 최적화 시킨다. zipalign
을 하지 않아도 앱 설치 및 실행이 가능했지만 일단 Android Developer 에서 시키니까 따라하자. 나는 apksigner
를 사용할 것이기 때문에 zipalign
명령어를 서명하기 전에 실행해야 한다.
아래 명령어를 통해 zipalign
명령어를 실행시켜 준다.
> zipalign -p -f -v 4 app-release.apk zipaligned_release.apk
Verifying alignment of zipaligned_release.apk (4)...
87 META-INF/com/android/build/gradle/app-metadata.properties (OK - compressed)
180 classes.dex (OK - compressed)
1988200 META-INF/androidx.activity_activity.version (OK)
1988296 META-INF/androidx.annotation_annotation-experimental.version (OK)
1988388 META-INF/androidx.appcompat_appcompat-resources.version (OK)
1988472 META-INF/androidx.appcompat_appcompat.version (OK)
1988556 META-INF/androidx.arch.core_core-runtime.version (OK)
1988636 META-INF/androidx.cardview_cardview.version (OK)
1988736 META-INF/androidx.coordinatorlayout_coordinatorlayout.version (OK)
1988808 META-INF/androidx.core_core.version (OK)
...
2295853 res/yP.xml (OK - compressed)
2296444 res/yf.xml (OK - compressed)
2296778 res/yx.xml (OK - compressed)
2297278 res/z1.xml (OK - compressed)
2297516 res/z3.xml (OK - compressed)
2297784 res/zH.xml (OK - compressed)
2298348 res/zq.xml (OK - compressed)
2298820 resources.arsc (OK)
Verification succesful
>
실행 결과 zipaligned_release.apk
파일이 떨어지는데, apksigner
명령어로 해당 파일에 대해 서명을 진행한다.
이때 jks 파일은 아까 안드로이드 스튜디오에서 만든 koooo.jks
파일을 사용한다.
> apksigner sign --ks koooo.jks zipaligned_release.apk
Keystore password for signer #1:
>
서명이 완료되면 keytool
명령어로 서명 정보를 확인할 수 있다.
> keytool -printcert -jarfile zipaligned_release.apk
서명자 #1:
서명:
소유자: CN=Koo, OU=Test, O=Test, L=Seoul, ST=Seoul, C=KR
발행자: CN=Koo, OU=Test, O=Test, L=Seoul, ST=Seoul, C=KR
일련 번호: 7e375792
적합한 시작 날짜: Mon May 23 12:42:33 KST 2022 종료 날짜: Fri May 17 12:42:33 KST 2047
인증서 지문:
MD5: 1A:50:08:90:B8:96:43:0E:BC:81:6C:52:D6:F5:56:C2
SHA1: 24:EC:E4:6D:9E:81:82:E8:F0:F3:09:0E:E1:4F:16:CD:7F:A3:68:92
SHA256: 7A:CC:48:A3:6D:71:E9:5E:F4:BB:6F:9A:1D:E5:AD:B8:12:FA:5F:2D:28:F0:F0:B6:B4:2B:2E:F6:62:FC:B6:71
서명 알고리즘 이름: SHA256withRSA
주체 공용 키 알고리즘: 2048비트 RSA 키
버전: 3
확장:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 94 BC 6E 6A D1 77 BD 0E 99 08 07 2B 5B 07 26 A2 ..nj.w.....+[.&.
0010: 9E 9D 07 94 ....
]
]
>
keystore
파일은 keytool
명령어로도 생성할 수 있다.
> keytool -genkey -alias koooo -keyalg RSA -validity 20000 -keystore koooo.keystore
키 저장소 비밀번호 입력:
새 비밀번호 다시 입력:
이름과 성을 입력하십시오.
[Unknown]: Koo
조직 단위 이름을 입력하십시오.
[Unknown]: Test
조직 이름을 입력하십시오.
[Unknown]: Test
구/군/시 이름을 입력하십시오?
[Unknown]: Seoul
시/도 이름을 입력하십시오.
[Unknown]: Seoul
이 조직의 두 자리 국가 코드를 입력하십시오.
[Unknown]: KR
CN=Koo, OU=Test, O=Test, L=Seoul, ST=Seoul, C=KR이(가) 맞습니까?
[아니오]: Y
<koooo>에 대한 키 비밀번호를 입력하십시오.
(키 저장소 비밀번호와 동일한 경우 Enter 키를 누름):
Warning:
JKS 키 저장소는 고유 형식을 사용합니다. "keytool -importkeystore -srckeystore koooo.keystore -destkeystore
koooo.keystore -deststoretype pkcs12"를 사용하는 산업 표준 형식인 PKCS12로 이전하는 것이 좋습니다.
>
keytool
로 생성한 koooo.keystore
파일로 동일하게 서명을 진행한다.
> zipalign -p -f -v 4 app-release.apk zipaligned_release2.apk
Verifying alignment of zipaligned_release2.apk (4)...
87 META-INF/com/android/build/gradle/app-metadata.properties (OK - compressed)
180 classes.dex (OK - compressed)
1988200 META-INF/androidx.activity_activity.version (OK)
1988296 META-INF/androidx.annotation_annotation-experimental.version (OK)
1988388 META-INF/androidx.appcompat_appcompat-resources.version (OK)
1988472 META-INF/androidx.appcompat_appcompat.version (OK)
1988556 META-INF/androidx.arch.core_core-runtime.version (OK)
1988636 META-INF/androidx.cardview_cardview.version (OK)
1988736 META-INF/androidx.coordinatorlayout_coordinatorlayout.version (OK)
1988808 META-INF/androidx.core_core.version (OK)
...
2295853 res/yP.xml (OK - compressed)
2296444 res/yf.xml (OK - compressed)
2296778 res/yx.xml (OK - compressed)
2297278 res/z1.xml (OK - compressed)
2297516 res/z3.xml (OK - compressed)
2297784 res/zH.xml (OK - compressed)
2298348 res/zq.xml (OK - compressed)
2298820 resources.arsc (OK)
Verification succesful
>
> apksigner sign --ks koooo.keystore zipaligned_release2.apk
Keystore password for signer #1:
>
> keytool -printcert -jarfile zipaligned_release2.apk
서명자 #1:
서명:
소유자: CN=Koo, OU=Test, O=Test, L=Seoul, ST=Seoul, C=KR
발행자: CN=Koo, OU=Test, O=Test, L=Seoul, ST=Seoul, C=KR
일련 번호: 16d698e6
적합한 시작 날짜: Mon May 23 15:20:29 KST 2022 종료 날짜: Tue Feb 23 15:20:29 KST 2077
인증서 지문:
MD5: D9:59:AB:94:99:13:81:8F:17:F1:0E:79:5A:B7:24:A2
SHA1: 87:1B:14:60:B8:F9:21:27:DA:2A:28:86:27:FA:7F:BD:94:23:4C:42
SHA256: 67:59:22:44:7B:2B:6E:C1:AF:62:6C:8D:41:8E:80:7A:BE:84:97:FD:F3:70:64:65:89:E3:56:28:AC:41:95:7A
서명 알고리즘 이름: SHA256withRSA
주체 공용 키 알고리즘: 2048비트 RSA 키
버전: 3
확장:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: CB 35 E5 C9 36 2D AA D2 93 C0 DA BD 86 A1 CA 0D .5..6-..........
0010: BE 9E 87 7F ....
]
]
>
그리고 certutil
명령어를 통해 apk 파일의 해시 값을 확인할 수 있다.
> certutil -hashfile zipaligned_release.apk MD5
MD5의 zipaligned_release.apk 해시:
d2a4de87a9cb4eaf571e8aa072153fdf
CertUtil: -hashfile 명령이 성공적으로 완료되었습니다.
>
> certutil -hashfile zipaligned_release2.apk SHA1
SHA1의 zipaligned_release2.apk 해시:
4320ebab17236b3de03620681780c32fd8a79458
CertUtil: -hashfile 명령이 성공적으로 완료되었습니다.
>
매번 리패키징할 때마다 apktool
> zipalign
> apksigner
명령어를 반복적으로 실행해야 하기 때문에 자동화시킬 필요가 있다.
@ECHO off
TITLE Let's Repackaging !
@ECHO ---------------------------------------------------------------
@ECHO ! !
@ECHO ! Let's Koo00 ! !
@ECHO ! !
@ECHO ---------------------------------------------------------------
@ECHO.
REM 실행 전 Java 및 Build Tool 환경 변수 세팅 필요
REM keystore 생성 방법 : keytool -genkey -alias koooo -keyalg RSA -validity 20000 -keystore koooo.keystore
REM 리사이닝 툴 세팅
SET APKTOOL=apktool.jar
SET KEYSTORE=keystore's name
SET KEYPASS=keystore's password
:START
IF EXIST crack.apk (
SET /p ANSWER="[-] Do you want to remove crack.apk first ? (Y/N) : "
)
IF "%ANSWER%" == "Y" (
start /wait /b powershell -ExecutionPolicy -Command "rm crack.apk"
@ECHO [!] Remove Done.
@ECHO.
) ELSE (
@ECHO [!] Pass !
@ECHO.
)
SET /p APK="[*] Input APK's Name : "
@ECHO.
IF NOT EXIST %APK% (
goto ERROR
)
IF EXIST %APK% (
start /wait /b java -jar %APKTOOL% d -rf %APK% -o tmp
@ECHO.
@ECHO [!] Decomplie Done.
@ECHO.
start /wait /b java -jar %APKTOOL% b tmp -o tmp.apk
@ECHO.
@ECHO [!] Repackaging Done.
start /wait zipalign -p -f -v 4 tmp.apk crack.apk
@ECHO [!] Zipalign Done.
cmd /c apksigner sign --ks %KEYSTORE% --ks-pass pass:%KEYPASS% crack.apk
@ECHO [!] Resigning Done.
@ECHO.
@ECHO [!] All Done !
@ECHO.
start /b powershell -ExecutionPolicy -Command "rm -r tmp*"
@ECHO [+] 인증서 소유자 :
start /wait /b powershell -ExecutionPolicy -Command "(keytool -printcert -jarfile crack.apk | select-object -index 4).toString().Split(':')[1].Trim()"
@ECHO.
@ECHO [+] 인증서 지문^(SHA1^) :
start /wait /b powershell -ExecutionPolicy -Command "(keytool -printcert -jarfile crack.apk | select-object -index 10).toString().Trim().ToLower() -split 'SHA1: ' -split ':' -join ''"
@ECHO.
@ECHO [+] %APK% MD5 :
start /wait /b powershell -ExecutionPolicy -Command "certutil -hashfile %APK% MD5 | select-object -index 1"
@ECHO.
@ECHO [+] %APK% SHA1 :
start /wait /b powershell -ExecutionPolicy -Command "certutil -hashfile %APK% SHA1 | select-object -index 1"
@ECHO.
@ECHO [+] crack.apk MD5 :
start /wait /b powershell -ExecutionPolicy -Command "certutil -hashfile crack.apk MD5 | select-object -index 1"
@ECHO.
@ECHO [+] crack.apk SHA1 :
start /wait /b powershell -ExecutionPolicy -Command "certutil -hashfile crack.apk SHA1 | select-object -index 1"
@ECHO.
start /wait /b powershell -ExecutionPolicy -Command "rm crack.apk.idsig"
exit
)
:ERROR
@ECHO [!] This file doesn't exist... Please retry...
@ECHO.
배치 파일에는 APK 파일의 해시 값과 인증서 정보를 확인할 수 있는 스크립트를 추가했다.
스크립트를 실행시키면 리사이닝부터 APK 파일 정보까지 한 번에 해결할 수 있다!
나중에 앱 디컴파일 이후 MainActivity 에 Smali 코드를 삽입해서 Toast 를 띄우는 과정을 추가해서 파이썬으로 다시 짜봐야겠다!
Using apksigner is a straightforward process that involves signing your APK with a keystore and verifying the signature. Make sure to keep your geometry dash lite and key secure, as they are essential for updates to your app in the future.