K1ngD0m Rush 0r1g1ns
디펜스형 게임.. 시간 순삭하기 좋은 게임이죠. 인앱구매 말고도 앱 자체 구매때 돈좀 들길래 쪼잔하게 mod 포럼을 방문, 크리스탈 무한과 모든 히어로들이 언락된 apk를 받아서 즐기려고 했습니다.
하지만 막상 받고보니 all heroes 언락이 되지않고 자꾸 구매하라고 뜨더군요.
해서 내가 한번 언락해 보자식으로 분석 해보기로 했습니다.
크리스탈 갯수는 mod되어 무한대에 가까운 수치로 조정되어 있습니다.
히어로는 기본 히어로, 특정 갯수의 별을 수집했을때 언락되는 것들 말고는 모두다 구매해서 쓰라고 표시되고 있었습니다.
오리지날 apk와 mod apk 의 차이점은 data.save 라는 파일이 assets 폴더에 생성되 있었으며 smali\com\savegame 클래스파일이 생성되어 있었습니다.
파일이 꾀 크네요 smali 주제에
어엌. 그럼 그렇치 SavesRestoringPortable 파일은 해커가 추가시킨듯한 파일이었으며 아마 해당 smali를 통해 save.dat 파일을 핸들링 할 것 같습니다.
비교적 단순하게 난독화 시킨듯 하여 online java compiler 사이트를 방문하여 즉석으로 간단한 복호화를 진행 하였습니다.
함수를 호출하여 특정 문자들을 리턴받는것을 알 수 있습니다. 문자를 반환하는 함수들을 싹다 복사하여 옮긴 뒤 print 함수를 통해 출력해 보도록 했습니다.
흠? 암호화 알고리즘이 사용되었습니다. data.save 파일을 aes-256 알고리즘을 사용하여 복호화 한 뒤 unzip 함수를 이용하여 압축해제를 진행합니다.
어떤 파일들이 압축되어 있는지 궁금하여 aes 복호화 진행후 까보았습니다.
압축파일 내부에는 킹덤러쉬가 사용하는 데이터를 압축해 놓았습니다. 살펴보니 file/save 폴더에서 사용자가 결제한 리스트, save slot 등이 보관되 있었습니다.
ㅇㅇㅇㅇㅇㅇㅇ
구매 결제 내역. 하지만 이걸 넣어줬다고 해서 실제 게임에서 기능들이 오픈되지 않습니다.ㅜㅜ
슬롯에 크리스탈 갯수가 박혀있습니다. 이건 제대로 작동 하더군요!
킹덤러쉬는 libsdl라이브러리, love 2d 게임엔진을 통하여 게임이 개발되었습니다.(luajit) 따라서 lua와 관련된 파일을 찾아댕긴결과 obb 쪽에서 바이너리화된 lua 파일들을 발견할 수 있었습니다. luajit 을 디컴파일 할 수 있는 툴을 활용하여 대략적으로 구매된 상품을 어떻게 적용시키는지 파악할 수 있었습니다.
디컴파일된 remote_config_defaults.lua 파일에서 공략해야할 상품목록을 파악할 수 있었습니다. 모든 히어로팩!
이때부터 든 생각이 결국엔 smali에서 결제를 처리하겠구나 싶어서 jadx 를통해 classes.dex 파일을 열어 보았습니다.
.. 게임수준.. 패키지 오지게 많구연!
여러가지 정보들을 모으며 삽질한 결과. 갓덤러쉬는 google-inapp service를 사용하여 결제시스템을 구축하였습니다.
우리가 눈여겨 보아야 할곳은
ownedSkus
purchaseDataList
signatureList
3개의 변수입니다. 스트링형 어레이 배열로 관리되고 있으며 어디선가 오브젝트를 얻어와 담아주고 있었습니다.
해당 배열들이 null,배열 사이즈가 0이 아니라면 purchase 객체를 생성하도록 합니다.
purchase 객체의 생성자를 주요깊게 보셔야합니다. 첫번째 파라미터인 purchaseinfo 는 purchase 의 json 객체를 생성할 수 있도록 json 문법을 이용하여 데이터를 가공하셔야 합니다. 2번째 파라미터는 해당 구매상품의 검증값으로 보시면 됩니다.(이 뒤에 시그니쳐값을 비교하여 상품 구매 유효성 검사를 진행합니다.)
ownedSkus
purchaseDataList
signatureList
3개의 변수에 임의로 생성한 문자 오브젝트들을 넘겨줄 수 있도록 바꿨습니다.
ownedSkus , signatureList 변수에는 아무 문자열이든 상관이 없습니다. 하지만 2번째 변수인 purchaseDataList는 json 파싱이 가능하도록 가공시켜주어야 합니다.
저는 모든 히어로를 이용하고 싶으니 com.ironhidegames.kingdomrush.origins.offer.heropackall5 제품명을 전달해 주도록 했습니다.
"{\"orderId\" : \"1\",\"packageName\" : \"com.ironhidegames.android.kingdomrushorigins\",\"productId\" : \"com.ironhidegames.kingdomrush.origins.offer.heropackall5\",\"purchaseTime\" : 15608190,\"token\" : {\"purchaseToken\" : \"YOYO\"},\"autoRenewing\" : true}"
아까 말했던 signature 값으로 상품구매가 유효한지를 체크하는 구간입니다. 쉽게 boolean 형태로 return 하고 있어 그냥 분기점을 바꿔 sb 오브젝트가 무사히 반환될 수 있게 하면 됩니다.
여기까지 하면 될줄 알았으나! 자꾸 purchase 생성자에서 json 예외를 던져 purchase 객체를 생성해내지를 못했습니다.
private final String mOriginalJson; final 키워드가 문제였습니다. ( 이거찾느라 ㅈ빠짐진짜) 해당 final 키워드를 제거하고 다시 테스트를 진행한 결과.
이제 겜 즐기러가야지.