2018騰訊遊戲安全技術競賽Android 組資格賽 Round1

“工欲善其事,必先利其器”

——《論語·魏靈公》

        最近參加了騰訊遊戲安全技術競賽,話說這個比賽我已經參加了3年了,第一年,什麼都沒看懂;第二年,題目做出來一半;第三年,我花了5天做完了最簡單的題目。自己雖然自信滿滿,覺得可以做到高級賽題,可是比賽的時候並不順利,遇到了層層阻隔。最終可能是由於提交時間過晚,沒有晉級決賽吧。我想把這些寫下來和大家分享,或者說,提醒自己更合適。

一、賽題解析

        那麼,我們首先來說說這次的題目吧。剛拿到賽題的時候,我覺得似曾相識,仔細看下去,發現和去年的題目大同小異。

拿到Apk之後,首先拖到jadx,如我所料,java代碼裏面沒有什麼有價值的內容,主要還是native代碼。將libnative-lib.so拖入IDA,定位到檢查key和code的函數:Java_com_qq_gslab_regme_MainActivity_checkReg,代碼將接受到的key和code傳入sub_51B0進行檢查,主要的檢查邏輯也在此處。

0x01 key的合法性?

首先遇到的是sub_4864,跟進去讀IDA生成的僞代碼發現是檢查字符串長度,key的長度應該爲39。

之後又對字符串進行了一系列操作。


         因此我們得到了完整的key格式約束:長度應該爲39,每四個字符以“#”分隔,字符範圍應該在“0123456789ABCDEF”,不區分大小寫,但是計算code時使用大寫字母進行計算。爲了方便敘述,將key以#分隔,分爲8個段,以segment0~segment7來表示。即XXXX#XXXX#XXXX#XXXX#XXXX#XXXX#XXXX#XXXX。

0x02 key的5個校驗值

在key的合法性驗證通過之後,繼續使用key生成5個校驗數,這個校驗數在之後會用到。這5個校驗數計算方式如下:


I1 = 0L;
I1 += (segment0[0] * segment1[0]) <<16;
I1 += segment0[1] ^ segment2[1];
I1 += (segment0[2] % (segment3[2] + 1)) +1;
I1 += segment0[3] / (segment4[3] +1);

I2 = 0L;
I2 += (segment1[0] ^ segment5[0])<<16;
I2 += (segment1[1] % (segment6[1] + 3));
I2 += (segment1[2] / (segment7[2] + 1)) +5;
I2 += segment1[3] + segment0[3];

I3 = 0L;
I3 += (segment2[0] / (segment1[0] +3)) <<16;
I3 = (segment2[1] % segment3[1]) ^ I3;
I3 += segment2[2] + segment5[2] + 12;
I3 += segment2[3] + segment7[3];

I4 = 0L;
I4 += segment0[1] ^ segment2[3];
I4 *= segment1[3] + segment3[1];
I4 = (segment4[2] & segment5[2]) & (I4 & 0xFFFFFFFF);
I4 *= segment7[3];
I4 += I2;
I4 *= segment6[0] * I1;
I4 -= (I4 - I2 )% (I1 *2);

I5 = 0L;
I5 += (segment3[0] ^ segment4[0]) <<16;
I5 *= segment3[1] % (segment4[1] +2);
I5 += (segment3[2] % (segment4[2] +5 )) + 7;
I5 += segment3[3] * segment4[3];

0x03 code解碼

到此爲止,我們的key就沒有使用價值了,接下來都是對code 的檢查。首先是sub_7114對code進行一個base64解碼。但是這個base64解碼和常規的有些不同,字符表被替換爲

ZO6Kq79L&CPWvNopzQfghDRSG@di*kAB8rsFewxlm+/u5a^2YtTJUVEn0$HI34y#

對於生成的每個十進制碼x,要做一個x^(x>>3)的變換,並以此爲索引,替換在字符集中的相應字符。

0x04 分水嶺!

接下來的就是進階和標準的分界點了。由於我此次做出的標準等級。所以接下來的流程比較簡單。

首先是code解碼後長度檢查,題目中要求解碼後的code 長度應該爲32字節。每8個字節爲一組,記爲Group1,Group2,Group3,Group4。將Group1,Group2,Group3和之前計算出的五個校驗值,視爲64bit長的數字,並應滿足如下方程:

令Group1 = x, Group2 = y, Group3 = z;
I1* x^2 + I2* y + I3 – y = 0
I4* x + I3 - y = (I2-I4)^2/ (4*I1)

求解這個方程組得到:

x = (I2-I4)/(2*I1)
y = (I1*x + I2)*x+I3

z的方程比較簡單:

z = ( I1*I5 + I2)*I5 +I3

最後使用java寫的註冊機,做成了一個apk。提供一組成功的值。代碼自下

Key:1111#1111#1111#1111#1111#1111#1111#1111

Code:ZZZpxEZZZZ6tNCl4ZZk0Fs0x4DG0$zDZNQeUNKq#EZZ= 

二、我踩到的坑


1.工欲善其事,必先利其器。這次的比賽,並沒有做好充足的準備,首先是自己覺得之前參加過比賽,有了比賽經驗之後,沒有去參考其他比賽的內容,導致最開始上手的時候,折騰了好久彙編。其次呢,就是沒有找好調試機器,自己想當然的覺得肯定沒問題,可是等到真的開始調試的的時候,又遇到了超級多的bug,比如64位的機器能不能動態調試so庫,什麼樣的手機才能調試,自己如何尋找到能夠調試的方法。這些都是問題。如果能夠早點進行準備的話, 就不會在調試機器上面耽誤1天時間,能夠節省下來看其他的代碼。第三,就是自己明知道是有加密算法的,但是卻沒有準備相關的逆向知識,導致高級算法根本就看不出來是什麼。雖然這些加密算法都有一個獨特的特徵,但是如何能夠識別卻還是需要經驗的。最後就是不要太相信自己的能力,雖然直接看彙編進行逆向固然好,可是有現成的工具又爲什麼不用呢?最後兩個方程,自己看了幾個小時,還不及IDA7.0 F5一下。一句“無他,唯手熟爾”包含着多少默默付出。

2.根據自己的需求,選擇好最合適的語言再進行開發。這次比賽我首先使用的是python語言。爲什麼?自己最熟悉而且可以省略很多底層的操作(由於知道算法中有大數運算),就是這一點讓自己吃了大虧。後面底層的操作,本來取低64位的操作可以進行&0xFFFFFFFFFFFFFFFF或者進行mod 2**64,但是無論如何都得不到想要的結果,而且Python使用bin的時候正數很正常,但是負數的話是正數的bin前面加上負號,也就是-5表示成 -101。但是如果換做Java就沒有這些問題,而且還有大數庫可以很好地操作64位乘法。所以啊,有些事情不是看看就會的,還是要動手調試。“絕知此事要躬行”眼高手低要不得。

3.缺少“擼起袖子加油幹”的精神。嗯。。。這也是自己一直以來的一個通病吧,就是幹活的時候喜歡聽音樂、聽相聲、聽視頻,應該說是因爲自己比較偷懶,想一直看視頻、看相聲,自己從骨子裏就是有股惰性,而雖然我表面上在幹活,可是內心裏卻已經放飛。這種隱藏摸魚的手法,雖然自己覺着可能工作中比較輕鬆,但是卻大大增加了開發的週期,影響了效率。正好藉着耳機壞了的機會,把自己的這個毛病好好扳一扳。“空談誤國,實幹興邦”,自己不知何時變得浮躁,還是要踏踏實實的幹下去。

4.無論何時,編程能力都是重中之重。編程可謂是安全人員的工作基石,可是自己的編程能力不過關。別的姑且不論,就拿大端小端來說,弄了那麼久都沒有弄對,究其本質,還是自己的基礎知識不過關。自己經常說記性不好,可是記性不好並不是失敗的藉口,接下來,努力強化記憶吧。

5."I always do what I can not do ,so that I can know how to do."說起來比較有意思,這句話是從基友衣服上面看到的,有點意思,謹記吧。

那麼我自己的優點呢我覺得還是有一些的。
1.耐心好,能夠耐着性子看完彙編
2.聯想能力比較好,快速的聯想到了去年的比賽,從而加速了開發的進程。

3.已經掌握了較多的技巧,知道如何去動態,如何去尋找工具。

這並不是一件壞事,在這個找工作和做畢設的緊要關頭,這一個比賽暴露了自己的缺點,改正就行了。希望來年,不要再寫出這幾點缺點,爭取做完全部內容。同時,表達能力啊喂,自己多看一看文章,多寫一些內容,幹得多也要說得多。我這個人記打不記喫,而且比較喜歡和別人比較找出自己的弱點,並且一定要改正。已經嘗試戒掉聽音樂3天,工作效率有所提高,想漸漸改掉摸魚的習慣。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章