summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2013-09-24 22:05:30 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2013-09-24 22:08:55 +0200
commita2c4be45d43425fdfb34ae91e6695f61cf1df549 (patch)
tree88b2196df0958e634a6defda1b3cf77feb53393b /tools
parent0dfa942319cf742e65f3dc4b7e6761e841a6f147 (diff)
tools: Add _rmk_'s deobfuscation scripts for kernel drivers
The kernel drivers in kernel_drivers can be run through these to make them more readable.
Diffstat (limited to 'tools')
-rw-r--r--tools/deobfuscate-complex-vivante.pl195
-rw-r--r--tools/deobfuscate-simple-vivante.pl17
2 files changed, 212 insertions, 0 deletions
diff --git a/tools/deobfuscate-complex-vivante.pl b/tools/deobfuscate-complex-vivante.pl
new file mode 100644
index 0000000..21414e6
--- /dev/null
+++ b/tools/deobfuscate-complex-vivante.pl
@@ -0,0 +1,195 @@
+$bitfield = '\d+:\d+|[A-Z_a-z]+';
+$id = '[^()]+|[^()]*(?:(\((?:[^()]++|(?-1))*+\))[^()]*)*';
+$hex = '0x[0-9a-fA-F]+';
+
+$sub = "";
+$name = "";
+undef $prev;
+
+while (<>) {
+ if (/^#define/) {
+ if (/^#define\s+(\w+)\s+($hex|\d+)/) {
+ my ($w, $v) = ($1, $2);
+ $v = hex($v) if ($v =~ /^0x/);
+
+ if ($w =~ /(gcCMD)_(\w+)_([^ ]+)/) {
+ $values{$1}{$2}{$v} = $3;
+ $name = $3;
+ } elsif ($w =~ /(GC_PROFILE_SEL[01])_(\w+)_([^ ]+)/) {
+ $values{$1}{$2}{$v} = $3;
+ }
+ }
+ if (/\s+(\w+)_(\w+)\s+(\d+:\d+)/) {
+ $field{$1}{$name}{$3} = $2;
+#print ">>> '$1' '$name' '$3' = '$2'\n";
+ }
+ print;
+ next;
+ }
+
+ $o = $_;
+ $m = 0;
+
+ s/\(0 ?\? ?($bitfield)\)/__gcmSTART(\1)/g;
+ s/\(1 ?\? ?($bitfield)\)/__gcmEND(\1)/g;
+ s/\(__gcmEND\(($bitfield)\) ?- ?__gcmSTART\(\1\) ?\+ ?1\)/__gcmGETSIZE(\1)/g;
+ s/\(\(gctUINT32\) ?\(\(__gcmGETSIZE\(($bitfield)\) ?== ?32\) ?\? ?~0 ?: ?\(~\(~0 ?<< ?__gcmGETSIZE\((?-1)\)\)\)\)\)/__gcmMASK(\1)/g;
+
+ $m |= s/\(\(\(gctUINT32\) ?\(($id)\)\) ?\<\< ?__gcmSTART\((?<field>$bitfield)\)\)/__gcmALIGN(\1, $+{field})/g;
+ $m |= s/\(\(\(\(gctUINT32\) \(($id)\)\) >> __gcmSTART\((?<field>$bitfield)\) & __gcmMASK\(\k<field>\)\) == \((?<value>[0-9a-fx]+) & __gcmMASK\(\k<field>\)\)\)/gcmVERIFYFIELDVALUE(\1, ####, $+{field}, $+{value})/g;
+ $m |= s/\( ?\(\(\(\(gctUINT32\) \(($id)\)\) >> __gcmSTART\((?<field>$bitfield)\)\) & __gcmMASK\(\k<field>\)\) ?\)/gcmGETFIELD(\1, ####, $+{field})/g;
+ $m |= s/\(\(\(\(gctUINT32\) \(($id)\)\) & ~__gcmALIGN\(__gcmMASK\((?<field>$bitfield)\), \k<field>\)\) \| __gcmALIGN\(\(gctUINT32\) \((?<value>$id)\) & __gcmMASK\(\k<field>\), \k<field>\)\)/gcmSETFIELD(\1, ####, $+{field}, $+{value})/g;
+ $m |= s/\(\(\(\(gctUINT32\) \(($id)\)\) & ~__gcmALIGN\(__gcmMASK\((?<field>$bitfield)\), \k<field>\)\) \| __gcmALIGN\((?<value>$id) ?& ?__gcmMASK\(\k<field>\), \k<field>\)\)/gcmSETFIELDVALUE(\1, ####, $+{field}, $+{value})/g;
+
+ if ($m and /####/) {
+ # Now fix things up a bit. First, the spec field definition
+ s/(gcmGETFIELD\(specs, )####, GC_CHIP_SPECS_field\)/\1GC_CHIP_SPECS, field)/g;
+# s/(= gcmGETFIELD\(specs, )####, /\1GC_CHIP_SPECS, /;
+
+ # Now, replace command opcode fields
+ if (/gcmSETFIELDVALUE\(0, ####, 31:27,/) {
+ $reg = "gcCMD";
+ $sub = "";
+ }
+ if (/\(State, ####, 31:27,/) {
+ $reg = "gcCMD";
+ $sub = "";
+ }
+ if (/\(specs, ####, /) {
+ $reg = "GC_CHIP_SPECS";
+ $sub = "";
+ }
+ if (/\(chipIdentity, ####, /) {
+ $reg = "GC_CHIP_IDENTITY";
+ $sub = "";
+ }
+ if (/\((?:features|\*ChipFeatures|.*->chipFeatures), ####, /) {
+ $reg = "GC_CHIP_FEATURES";
+ $sub = "";
+ }
+ if (/[Cc]hipMinorFeatures0, ####, /) {
+ $reg = "GC_CHIP_MINOR_FEATURES0";
+ $sub = "";
+ }
+ if (/[Cc]hipMinorFeatures1, ####, /) {
+ $reg = "GC_CHIP_MINOR_FEATURES1";
+ $sub = "";
+ }
+ if (/\(idle, ####, /) {
+ $reg = "GC_IDLE";
+ $sub = "";
+ }
+ if (/debug, ####, /) {
+ $reg = "AQMemoryDebug";
+ $sub = "";
+ }
+ if (/destination/) {
+ $reg = "AQEvent";
+ $sub = "";
+ }
+ if (/Address/) {
+ $reg = "ADDRESS";
+ $sub = "";
+ }
+ if (/gckOS_WriteRegister.*0x0+470/) {
+ $reg = "GC_DEBUG_CONTROL0";
+ $sub = "";
+ }
+ if (/gckOS_WriteRegister.*0x0+474/) {
+ $reg = "GC_DEBUG_CONTROL1";
+ $sub = "";
+ }
+ if (/gckOS_WriteRegister.*0x0+478/) {
+ $reg = "GC_DEBUG_CONTROL2";
+ $sub = "";
+ }
+ if (/if \(\(gcmGETFIELD\(control/) {
+ $reg = "GC_CLOCK_CONTROL";
+ $sub = "";
+ }
+ if (/stall =/) {
+ $reg = "STALL";
+ $sub = "";
+ }
+
+ # Replace register names
+ s/####/$reg/ if defined $reg;
+
+ # Replace bitfields with their definitions
+ if (/(\w+), (\d+:\d+)/) {
+ my $r = $1;
+ my $f = $2;
+ if (defined($field{$r}{$sub}{$f})) {
+ s/$r, $f/$r, $field{$r}{$sub}{$f}/;
+ }
+ }
+
+ # Replace command opcodes with their decimal equivalents
+ s/($reg, \w+, )($hex) */$1.hex($2)/eg;
+ if (/(\w+), (\w+), (\d+) */ and defined($values{$1}{$2}{$3})) {
+#print ">>> $1 $2 $3\n";
+ $sub = $values{$1}{$2}{$3} if $sub eq "";
+ s/((\w+), (\w+), )(\d+) */$1.$values{$2}{$3}{$4}/e;
+ }
+
+ s/= gcmGETFIELD\(specs, GC_CHIP_SPECS, /= gcmSPEC_FIELD(/g;
+ } else {
+ if (/gcvFLUSH_/ or /flush = \(Pipe == 0x1\)/) {
+ $reg = "AQFlush";
+ $sub = "";
+ }
+ if (/Flush the memory/) {
+ $reg = "MMUFlush";
+ $sub = "";
+ }
+ if (/isolat(?:e|ion)|soft reset|frequency scaler/i or /gcvPOWER_ON/) {
+ $reg = "GC_CLOCK_CONTROL";
+ $sub = "";
+ }
+ if (/Build control register/ or /Set big endian/) {
+ $reg = "GC_CONTROL";
+ $sub = "";
+ }
+ if (/clock gating/) {
+ $reg = "GC_PWR_R0";
+ $sub = "";
+ }
+ if (/Disable PE clock/) {
+ $reg = "GC_PWR_R1";
+ $sub = "";
+ }
+ }
+
+ s/\( *(gcmSETFIELD\([^)]+\)) *\)/\1/;
+
+ undef $reg if /;/;
+
+ if (defined ($prev)) {
+ if (/gcmkONERROR\(gckOS_ReadRegister\(Hardware->os, $hex, &profiler->(\w+)\)\);/) {
+ $dbg_elem = $1;
+ s/(\s*).*/\1gcmkREAD_DEBUG_REGISTER($dbg_regoff, $dbg_block, $dbg_index, $dbg_elem);/;
+ undef $prev;
+ } elsif (/gcmkONERROR\(gckOS_WriteRegister\(Hardware->os, $hex, \( *gcmSETFIELD\(0, GC_DEBUG_CONTROL$dbg_regoff, $dbg_block, 0\)/) {
+ s/(\s*).*/\1gcmkRESET_DEBUG_REGISTER($dbg_regoff, $dbg_block);/;
+ $prev = $_;
+ next;
+ } elsif (/^\)\)\);$/) {
+ $_ = $prev;
+ undef $prev;
+ }
+ } else {
+ if (/gcmkONERROR\(gckOS_WriteRegister\(Hardware->os, $hex, gcmSETFIELD\(0, GC_DEBUG_CONTROL(\d), (\w+), (\w+)/) {
+ $prev = $_;
+ $dbg_regoff = $1;
+ $dbg_block = $2;
+ $dbg_index = $3;
+ next;
+ }
+ }
+
+ print $prev if defined $prev;
+ undef $prev;
+ print;
+
+ print STDERR if /(\d+:\d+|####)/;
+}
diff --git a/tools/deobfuscate-simple-vivante.pl b/tools/deobfuscate-simple-vivante.pl
new file mode 100644
index 0000000..cf07ea7
--- /dev/null
+++ b/tools/deobfuscate-simple-vivante.pl
@@ -0,0 +1,17 @@
+$bitfield = '\d+:\d+|[A-Z_a-z]+';
+$id = '[^()]+|[^()]*(?:(\((?:[^()]++|(?-1))*+\))[^()]*)*';
+$hex = '0x[0-9a-fA-F]+';
+
+$sub = "";
+$name = "";
+undef $prev;
+
+while (<>) {
+ s/\(0 ?\? ?($bitfield)\)/__gcmSTART(\1)/g;
+ s/\(1 ?\? ?($bitfield)\)/__gcmEND(\1)/g;
+ s/\(__gcmEND\(($bitfield)\) ?- ?__gcmSTART\(\1\) ?\+ ?1\)/__gcmGETSIZE(\1)/g;
+ s/\(\(gctUINT32\) ?\(\(__gcmGETSIZE\(($bitfield)\) ?== ?32\) ?\? ?~0 ?: ?\(~\(~0 ?<< ?__gcmGETSIZE\((?-1)\)\)\)\)\)/__gcmMASK(\1)/g;
+ s/\(\(\(gctUINT32\) ?\(($id)\)\) ?\<\< ?__gcmSTART\((?<field>$bitfield)\)\)/__gcmALIGN(\1, $+{field})/g;
+
+ print;
+}