[AOS] How to use apksigner

koo00·2022년 5월 25일
1

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 파일이 아닙니다.


그래서 그냥 zipalignapksigner 를 활용해서 직접 서명을 해보자.


먼저 생성한 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 를 띄우는 과정을 추가해서 파이썬으로 다시 짜봐야겠다!

profile
JFDI !

0개의 댓글