Smali插桩(一)
使用Smali插桩需要先了解Smali的基础语法,见 Smali语法基础 - Tzy0425 - 博客园 (cnblogs.com)
插桩的含义:程序插桩,它是在保证被测程序原有逻辑完整性的基础上在程序中插入一些探针(又称为“探测仪”),通过探针的执行并抛出程序运行的特征数据,通过对这些数据的分析,可以获得程序的控制流和数据流信息,进而得到逻辑覆盖等动态信息,从而实现测试目的的方法。
通过开发一个简单的注册用户程序。程序中要求注册码必须为16位。
关键代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle(R.string.unregister);
EditText editText1 = (EditText) findViewById(R.id.edit_username);
EditText editText2 = (EditText) findViewById(R.id.edit_sn);
Button button = (Button) findViewById(R.id.button_register);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (!checkSN(editText1.getText().toString().trim(),
editText2.getText().toString().trim())) {
Toast.makeText(MainActivity.this, R.string.unsuccessed, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, R.string.successed, Toast.LENGTH_SHORT).show();
setTitle(R.string.registered);
}
}
});
}
private boolean checkSN(String userName,String sn) {
try {
if((userName == null) || (userName.length() ==0))
return false;
if((sn == null) || (sn.length() != 16))
return false;
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.reset();
digest.update(userName.getBytes());
byte[] bytes = digest.digest();
String hexstr = toHexSting(bytes,"");
StringBuilder sb = new StringBuilder();
for(int i = 0;i < hexstr.length();i += 2) {
sb.append(hexstr.charAt(i));
}
String userSN = sb.toString();
if(userSN.equalsIgnoreCase(sn))
return false;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return false;
}
return true;
}
private String toHexSting(byte[] bytes, String s) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if(hex.length() == 1){
hexString.append('0');
}
hexString.append(hex).append(separator);
}
return hexString.toString();
}
}
输入非16位的注册码会发现弹出错误的提示,比如注册失败,这时候我们需要在反编译的文件string.xml中搜索“注册失败”相关字样,看到其对应的属性值为unsuccessed,接下来就在文件punlic.xml中找unsuccessed对应的ID值,然后在MainActivity$1.smali文件中找到该ID值所在的位置,分析上下文smali代码。(分析逻辑见顶部网址)
修改if-nez为if-eqz,保存,签名,重编译,然后就会发现输入任意位数的注册码都会显示注册成功。
举个别的例子,此处不展示具体细节,前几步是一样的,在MainActivity$1.smali文件中定位到关键代码,然后通过插桩log可以输出源代码中定义的正确值。