一般情况下,我们采用apktool(xml资源)+dex2jar+JDGui(jar to java)反编译android apk之后的代码中,涉及到资源索引的信息全部替换成了十进制的数字。
如何将这些数字还原成为原始的资源索引形式呢?
public g(Context paramContext)
{
super(paramContext);
b(2130903088);
this.b = ((FirModule)this.k.N().a("fir_module"));
int[] arrayOfInt = new int[2];
arrayOfInt[0] = 2131427902;
arrayOfInt[1] = 2131427901;
a(arrayOfInt);
f(1);
f(2);
}
我们希望得到如下形式的代码:
public g(Context paramContext)
{
super(paramContext);
b(R.layout.fir_info_page);
this.b = ((FirModule)this.k.N().a("fir_module"));
int[] arrayOfInt = new int[2];
arrayOfInt[0] = R.string.commended_apps;
arrayOfInt[1] = R.string.person_info;
a(arrayOfInt);
f(1);
f(2);
}
可读性就非常高了。
下面讲述如何做到这个功能:
b(2130903088);中的数字转换为16进制以后,是0x7f030030,通过手工在R.java中搜索我们可以找到:
public static final int fir_info_page=0x7f030030;
因此在相应的地方替换为对应的资源索引就可以了,处于layout class之下,因此是 R.layout.fir_info_page 。
注意:如果代码中不是10进制的ID,而是十六进制,即与R.java相同的数值,则将$RESERVED_HEX设为0.
好了,原理很简单,接下来我们编写一个perl脚本来批量做这个事情,具体代码如下:
同时支持自定义匹配模式,在该脚本所在目录下,新建一个文本文件 wordspattern.txt,
内容格式如下:
intent\.setFlags\(0x10000000\)=intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent\.setFlags\(0x20000000\)=intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
intent\.setFlags\(0x40000000\)=intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent\.setFlags\(0x80000000\)=intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
intent\.setFlags\(0x30000000\)=intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_FORWARD_RESULT)
perl源代码:
#!/usr/bin/perl
#注意事项:
#复制一份 R.java在该文件所在目录
#第一个参数为:需要处理的源代码目录路径
use strict;
use File::Find;
#是否按十六进制进行替换
#即源代码中的资源ID是否与R.java中一样采用十六进制
#如果是,设置为1,否则设置为0
my $RESERVED_HEX = 1;
my $from_str;
my $to_str;
my $resource;
my $init_folder = $ARGV[0];
if (not -d $init_folder)
{
print "目录:$init_folder不存在.\n";
print "$0 \n";
exit;
}
#读取R.java中的所有文本
my $k_file = "R.java";
open my $k ,"< $k_file" or die "couldn't open $k_file\n";
my @keywords = ;
close $k;
#遍历每行数据
for my $line (@keywords)
{
#print "$line";
#先解析内部class类型:id/style/xml/arrays等
#public static final class style {
if ($line =~ /public\sstatic\sfinal\sclass\s(\w+)\s\{/)
{
$resource = $1;
print "class:$resource\n";
}
else
{
#如果格式如下,则解析出来
#public static final int MarketPanelTheme=0x7f0c0076;
if ($line =~ /public\sstatic\sfinal\sint\s(\w+)=(\w+)\;/)
{
#print "keywords:$1 $to_str\n\n";
find(\&CallBackMe, $init_folder );
}
}
}
#读取用户自定义的匹配模式
#如:intent.setFlags(0x10000000)=intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
my $wordpatternfile = "wordspattern.txt";
my @userkeywords;
my $userword;
open $userword ,"< $wordpatternfile" if -e $wordpatternfile;
@userkeywords = ;
close $userword;
for my $line (@userkeywords)
{
if($line =~ /(.*)=(.*)$/)
{
$from_str=$1;
$to_str=$2;
find(\&CallBackMe, $init_folder );
}
}
print "Well Done.\n";
sub CallBackMe
{
my $fullpath = $File::Find::name;
if(-d $fullpath)
{
print "[Dir] $fullpath\n";
}
else
{
#print "[File] $fullpath\n";
if($fullpath =~ /\.java$/i)
{
if($fullpath =~ /\\$k_file/i)
{
#ignore it
print "Ignored $k_file\n";
}
else
{
#replace text
print "Replacing $from_str with $to_str in $fullpath\n";
ReplaceString($fullpath, $from_str,$to_str);
}
}
}
}
#Replacing $from with $to in $file
sub ReplaceString
{
my $file = shift @_;
my $from = shift @_;
my $to = shift @_;
open my $fh ,"< $file" or die "couldn't open $file\n";
my @lines=;
close $fh;
my $outlines = join '',@lines;
#replace all
$outlines =~ s/$from/$to/g;
#write back
open my $out , "> $file" or die "couldn't write $file";
print $out $outlines;
close $out;
}