今天遇到一道APK逆向的题目,难度应该是入门级别的。由于之前见到这类题目直接就放弃了,这样还是不太好,于是试着从头开始,查资料把这道题解决了。
题目给的APK在这里。为了做这道题,我把apktool装好了,还翻墙把android sdk安上了。结果模拟器启动太慢了……以后有钱搞一台实机用好了。话说回来这次也基本没有用到模拟器,主要用了dex2jar和jd-gui。
将APK用unzip解压,再用dex2jar,最后用jd-gui得到了java代码。如下:
importandroid.app.Activity;importandroid.app.AlertDialog.Builder;importandroid.content.res.Resources;importandroid.graphics.BitmapFactory;importandroid.os.Bundle;importandroid.telephony.TelephonyManager;importandroid.widget.ImageView;importandroid.widget.Toast;importjava.io.InputStream;importjava.math.BigInteger;importjava.security.MessageDigest;importjavax.crypto.Cipher;importjavax.crypto.spec.IvParameterSpec;importjavax.crypto.spec.SecretKeySpec;publicclassJewelActivityextendsActivity{publicvoidonCreate(BundleparamBundle){super.onCreate(paramBundle);setContentView(2130903040);Stringstr1=((TelephonyManager)getSystemService("phone")).getDeviceId();try{MessageDigestlocalMessageDigest=MessageDigest.getInstance("SHA-256");localMessageDigest.update(str1.getBytes("ASCII"));Stringstr2=newBigInteger(localMessageDigest.digest()).toString(16);if(!str1.substring(0,8).equals("99999991")){newAlertDialog.Builder(this).setMessage("Your device is not supported").setCancelable(false).setPositiveButton("OK",newb(this)).show();return;}if(!str2.equals("356280a58d3c437a45268a0b226d8cccad7b5dd28f5d1b37abf1873cc426a8a5")){newAlertDialog.Builder(this).setMessage("You are not a valid user").setCancelable(false).setPositiveButton("OK",newa(this)).show();return;}}catch(ExceptionlocalException){Toast.makeText(this,localException.toString(),1).show();return;}InputStreamlocalInputStream=getResources().openRawResource(2130968576);byte[]arrayOfByte1=newbyte[localInputStream.available()];localInputStream.read(arrayOfByte1);SecretKeySpeclocalSecretKeySpec=newSecretKeySpec(("!"+str1).getBytes("ASCII"),"AES");IvParameterSpeclocalIvParameterSpec=newIvParameterSpec("kLwC29iMc4nRMuE5".getBytes());CipherlocalCipher=Cipher.getInstance("AES/CBC/PKCS5Padding");localCipher.init(2,localSecretKeySpec,localIvParameterSpec);byte[]arrayOfByte2=localCipher.doFinal(arrayOfByte1);ImageViewlocalImageView=newImageView(this);localImageView.setImageBitmap(BitmapFactory.decodeByteArray(arrayOfByte2,0,arrayOfByte2.length));setContentView(localImageView);}}
由于没有环境,只能静态去分析代码了,好多不懂的地方现查了。从流程上来说,这段代码取出来了device id,检查其前8位是否是99999991
,而且要求sha256的hash等于某个指定的值。如果符合要求,就用这个device id来构造key,对一个文件进行AES加密,得到一个BMP图片。
具体地,device id查了下是15 bytes,而前8 bytes确定后,还有7 bytes,大概有10^7
种可能,这部分可以通过暴力破解。然后作为AES加密输入的文件,是一个resource,而且这个resource的id是2130968576=0x7f040000
。在apktools解码得到的文件res/values/public.xml
中发现了这个资源文件是raw/jewel_c.png
于是整体的思路就是,先暴力跑出device id,然后AES加密文件,得到BMP图像。之前也没有用过java,于是也第一次练习了……感觉java的文档写的很不错。下面是我的代码,复制了很多原来代码的东西
importjava.io.*;importjava.math.BigInteger;importjava.security.MessageDigest;importjavax.crypto.Cipher;importjavax.crypto.spec.IvParameterSpec;importjavax.crypto.spec.SecretKeySpec;publicclassMain{publicstaticvoidmain(String[]args){try{StringBuilderstr1=newStringBuilder(15);str1.append("99999991");for(inti=0;i<10000000;i++){str1.replace(8,15,String.format("%07d",i));MessageDigestlocalMessageDigest=MessageDigest.getInstance("SHA-256");localMessageDigest.update(str1.toString().getBytes("ASCII"));Stringstr2=newBigInteger(localMessageDigest.digest()).toString(16);if(str2.equals("356280a58d3c437a45268a0b226d8cccad7b5dd28f5d1b37abf1873cc426a8a5")){System.out.println(str1);InputStreamlocalInputStream=newFileInputStream(newFile("jewel_c.png"));byte[]arrayOfByte1=newbyte[localInputStream.available()];localInputStream.read(arrayOfByte1);SecretKeySpeclocalSecretKeySpec=newSecretKeySpec(("!"+str1.toString()).getBytes("ASCII"),"AES");IvParameterSpeclocalIvParameterSpec=newIvParameterSpec("kLwC29iMc4nRMuE5".getBytes());CipherlocalCipher=Cipher.getInstance("AES/CBC/PKCS5Padding");localCipher.init(2,localSecretKeySpec,localIvParameterSpec);byte[]arrayOfByte2=localCipher.doFinal(arrayOfByte1);FileOutputStreamoutfile=newFileOutputStream("1.bmp");outfile.write(arrayOfByte2);break;}}}catch(Exceptione){e.printStackTrace();}}}
编译运行,得到正确的device id是999999913371337
。查看得到的BMP图片,说是flag在comment里面。于是用strings
查看,得到flag
总的来说,第一次做APK逆向的题目,考察的知识还是基本的。没有涉及到网络通信,单纯地静态分析下就可以了,所以其实与android关系并不大,只是旧的逆向题装了个新瓶子。但以后做其他的APK题目可能就不会这么容易了。不过对我来说,比windows下面的逆向题要方便多了,ida在我虚拟机里的xp下总是不能用,非常麻烦,所以到现在APK逆向做了这一道,windows的逆向题还没做过……