Skip to content

Commit

Permalink
Fixed bug where relatives offsets would overflow in branching instruc…
Browse files Browse the repository at this point in the history
…tions in large methods. Fixed the usage message. Thanks to Alexandre Bartel for reporting.
  • Loading branch information
docteau committed Nov 19, 2013
1 parent c4e3799 commit 6be95ae
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 16 deletions.
2 changes: 2 additions & 0 deletions dare/decompiler/include/dare.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class Dare {
ignore_bad_checksum_(false) {}

static bool split_exception_tables() { return split_exception_tables_; }
static int offset_limit() { return offset_limit_; }
// static void AddConflictedClass(std::string c) {
// conflicted_classes_.insert(c);
// }
Expand Down Expand Up @@ -86,6 +87,7 @@ class Dare {
const char* stubs_dir_;

static bool split_exception_tables_;
static int offset_limit_;

bool ignore_bad_checksum_;
// static std::set<std::string> conflicted_classes_;
Expand Down
4 changes: 4 additions & 0 deletions dare/decompiler/include/tyde/body.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class Body {
}
void pop_front() { instructions_.erase(instructions_.begin()); }
void pop_back() { instructions_.pop_back(); }
void insert(int index, const std::vector<T>& contents) {
instructions_.insert(instructions_.begin() + index, contents.begin(),
contents.end());
}
size_t size() const { return instructions_.size(); }

private:
Expand Down
19 changes: 19 additions & 0 deletions dare/decompiler/include/tyde/cfg_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,25 @@ class CFGBuilder {
* @param dcode A Tyde body.
*/
static void ComputeReachability(const TydeBody& dcode);
/**
* Check offsets in branching instructions and patch potentially overflowing
* two-byte offsets.
*
* @param dcode A Tyde body.
*/
static void CheckAndPatchOffsets(TydeBody& dcode);
/**
* Check offset in a branching instruction and patch potentially overflowing
* two-byte offset if necessary.
*
* It is necessary that all instruction indices are up-to-date before calling
* this function (call dcode.RefreshIndicesAfter() if necessary).
*
* @param dcode A Tyde body.
* @param index The index of an instruction to be checked.
* @return True if the code was modified.
*/
static bool CheckOffsetAtInstruction(TydeBody& dcode, int index);

static int label_;
};
Expand Down
4 changes: 3 additions & 1 deletion dare/decompiler/include/tyde/translator.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ class Translator {
* Translate unambiguous branching instruction.
*
* @param ins A Tyde instruction.
* @param large_method True if the method is large and therefore requires the
* use of goto_w instead of goto.
*/
void TranslateFmtTub(const TydeInstruction* ins);
void TranslateFmtTub(const TydeInstruction* ins, bool large_method);

/**
* Translate ambiguous branching instruction.
Expand Down
5 changes: 5 additions & 0 deletions dare/decompiler/include/tyde/tyde_body.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ class TydeBody : public Body<TydeInstruction*> {
const std::vector<TryItem>& tries() const { return tries_; }
void set_tries(const std::vector<TryItem>& tries) { tries_ = tries; }

void RefreshIndicesAfter(int index) const {
for (int i = 0; i < (int) size(); ++i)
operator[](i)->set_index(i);
}

void Dump(std::ostream& out) const {
for (int i = 0; i < (int) size(); ++i)
out << operator[](i)->ToString();
Expand Down
5 changes: 5 additions & 0 deletions dare/decompiler/include/tyde/tyde_instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class TydeInstruction {
const std::vector<TydeInstruction*>& successors() const {
return successors_;
}
void set_successors(const std::vector<TydeInstruction*>& successors) {
successors_ = successors;
}
const std::vector<TydeInstruction*>& exception_successors() const {
return exception_successors_;
}
Expand Down Expand Up @@ -125,6 +128,8 @@ class TydeInstruction {
void AddPredecessor(TydeInstruction* ins) {
predecessors_.push_back(ins);
}
void ReplacePredecessor(TydeInstruction* original,
TydeInstruction* replacement);
void AddExceptionPredecessor(TydeInstruction* ins) {
exception_predecessors_.push_back(ins);
}
Expand Down
10 changes: 8 additions & 2 deletions dare/decompiler/src/dare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#include "dare.h"

#include <stdlib.h>

#include <fstream>

#include "libdex/SysUtil.h"
Expand All @@ -42,6 +44,7 @@ using std::string;

/*static*/ const char* Dare::kVersion = "1.1.0";
/*static*/ bool Dare::split_exception_tables_ = true;
/*static*/ int Dare::offset_limit_ = 5000;
///*static*/ std::set<std::string> Dare::conflicted_classes_;


Expand All @@ -59,7 +62,7 @@ int Dare::Start(int argc, char* const argv[]) {
const char* verif = NULL;

while (true) {
ic = getopt(argc, argv, "id:t:c:es:p:v");
ic = getopt(argc, argv, "id:t:c:es:p:vl:");
if (ic < 0)
break;

Expand Down Expand Up @@ -88,6 +91,9 @@ int Dare::Start(int argc, char* const argv[]) {
case 'v':
printf("dare version %s\n", Dare::version());
return 0;
case 'l':
offset_limit_ = atoi(optarg);
break;
default:
wantUsage = true;
break;
Expand Down Expand Up @@ -219,7 +225,7 @@ int Dare::Process(const char* file) {
* Display usage information.
*/
void Dare::Usage() const {
fprintf(stderr, "Copyright (C) 2012 The Pennsylvania State University\n"
fprintf(stderr, "Copyright (C) 2012-2013 The Pennsylvania State University\n"
"Systems and Internet Infrastructure Security Laboratory\n\n");
fprintf(stderr,
"Usage: dare-%s [-d <output dir>] [-i] [-t <tempfile>] [-c <class-list>]"
Expand Down
78 changes: 78 additions & 0 deletions dare/decompiler/src/tyde/cfg_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
AddSuccessors(code_attribute->tyde_body());
AddExceptionSuccessors(code_attribute, cp);
RemoveDeadTries(code_attribute->tyde_body());
CheckAndPatchOffsets(code_attribute->tyde_body());
}


Expand Down Expand Up @@ -345,3 +346,80 @@
s.push(instruction->exception_successors()[i]);
}
}

/**
* Check offsets in branching instructions and patch potentially overflowing
* two-byte offsets.
*
* @param dcode A Tyde body.
*/
/*static*/ void CFGBuilder::CheckAndPatchOffsets(TydeBody& dcode) {
if ((int) dcode.size() < Dare::offset_limit() || Dare::offset_limit() <= 0) {
return;
}

for (int i = dcode.size() - 1; i >= 0; --i)
if (dcode[i]->op() >= OP_IF_EQ && dcode[i]->op() <= OP_IF_LEZ)
if (CheckOffsetAtInstruction(dcode, i))
dcode.RefreshIndicesAfter(i);
}

/**
* Check offset in a branching instruction and patch potentially overflowing
* two-byte offset if necessary.
*
* It is necessary that all instruction indices are up-to-date before calling
* this function (call dcode.RefreshIndicesAfter() if necessary).
*
* @param dcode A Tyde body.
* @param index The index of an instruction to be checked.
* @return True if the code was modified.
*/
/*static*/ bool CFGBuilder::CheckOffsetAtInstruction(TydeBody& dcode,
int index) {
TydeInstruction* branching_instruction = dcode[index];
TydeInstruction* original_target = branching_instruction->successors()[1];
s4 relative_offset = (s4) branching_instruction->constant();
int original_target_index = original_target->index();
int gap;

if (relative_offset > 0)
gap = original_target_index - index;
else
gap = index - original_target_index;

if (gap <= Dare::offset_limit())
return false;

// Make the next instruction.
DecodedInstruction decoded_instruction;
decoded_instruction.opcode = OP_GOTO;
TydeInstruction* next = new TydeInstruction(&decoded_instruction,
branching_instruction->original_offset());
TydeInstruction* normal_successor = branching_instruction->successors()[0];
normal_successor->ReplacePredecessor(branching_instruction, next);
normal_successor->set_label(label_++);
next->AddSuccessor(normal_successor);
next->AddPredecessor(branching_instruction);

// Make the new target instruction.
TydeInstruction* new_target = new TydeInstruction(&decoded_instruction,
branching_instruction->original_offset());
TydeInstruction* target_successor = branching_instruction->successors()[1];
target_successor->ReplacePredecessor(branching_instruction, new_target);
new_target->AddSuccessor(target_successor);
new_target->AddPredecessor(branching_instruction);
new_target->set_label(label_++);

// Patch successors and insert new instructions.
std::vector<TydeInstruction*> slice(2);
slice[0] = next;
slice[1] = new_target;

branching_instruction->set_successors(slice);

dcode.insert(index + 1, slice);

return true;
}

21 changes: 16 additions & 5 deletions dare/decompiler/src/tyde/translator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "class_file/integer_info.h"
#include "class_file/interface_method_ref_info.h"
#include "class_file/method_ref_info.h"
#include "dare.h"
#include "timer.h"
#include "tyde/java_opcode_jasmin.h"
#include "tyde/tyde_instruction.h"
Expand Down Expand Up @@ -101,6 +102,8 @@ void Translator::Convert() {
out_ << "Label" << code_attribute_->tyde_body()[i]->label() << ":" << "\n";

TydeInstruction* instruction = code_attribute_->tyde_body()[i];
bool large_method = Dare::offset_limit() > 0
&& (int) code_attribute_->tyde_body().size() > Dare::offset_limit();
// std::cout << instruction->ToString();
switch (TydeInstrUtils::TydeGetFormatFromOpcode(instruction->op())) {
case kFmtTuo:
Expand All @@ -110,7 +113,7 @@ void Translator::Convert() {
TranslateFmtTao(instruction);
break;
case kFmtTub:
TranslateFmtTub(instruction);
TranslateFmtTub(instruction, large_method);
break;
case kFmtTab:
TranslateFmtTab(instruction);
Expand Down Expand Up @@ -180,16 +183,24 @@ void Translator::TranslateFmtTao(const TydeInstruction* ins) {
* Translate unambiguous branching instruction.
*
* @param ins A Tyde instruction.
* @param large_method True if the method is large and therefore requires the
* use of goto_w instead of goto.
*/
void Translator::TranslateFmtTub(const TydeInstruction* ins) {
void Translator::TranslateFmtTub(const TydeInstruction* ins,
bool large_method) {
TranslateSources(ins);
AddOpcode(ins->op());
Opcode opcode = ins->op();
int label = -1;
if (opcode == OP_GOTO || opcode == OP_GOTO_16 || opcode == OP_GOTO_32)
if (opcode == OP_GOTO || opcode == OP_GOTO_16 || opcode == OP_GOTO_32) {
if (large_method)
out_ << GOTO_W;
else
AddOpcode(opcode);
label = ins->successors()[0]->label();
else
} else {
AddOpcode(ins->op());
label = ins->successors()[1]->label();
}
if (label == -1) {
LOGE("Error: label does not exist\n");
exit(1);
Expand Down
7 changes: 7 additions & 0 deletions dare/decompiler/src/tyde/tyde_instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ void TydeInstruction::AddExceptionSuccessor(TydeInstruction* ins) {
ins->AddExceptionPredecessor(this);
}

void TydeInstruction::ReplacePredecessor(TydeInstruction* original,
TydeInstruction* replacement) {
for (int i = 0; i < (int) predecessors_.size(); ++i)
if (predecessors_[i] == original)
predecessors_[i] = replacement;
}

/**
* Source source register type.
*
Expand Down
2 changes: 1 addition & 1 deletion dare/launcher/dare
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ ANDROID_LIBS="$DED_DIR/../../../../dalvik/dare/libs/class"
PREVERIFY_SCRIPT="$DED_DIR/../../../../dalvik/tools/dex-preopt"
PREVERIFY=""

while getopts "ed:ocpbx:k" p
while getopts "ed:ocpbx:kl:" p
do
case "$p" in
p) PREVERIFY=" -p $PREVERIFY_SCRIPT";;
Expand Down
15 changes: 9 additions & 6 deletions dare/launcher/dare_launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void DedLauncher::Process(int argc, char** argv) {
char* class_list = NULL;

while (1) {
ic = getopt(argc, argv, "d:s:a:ocj:m:p:evr:bx:k");
ic = getopt(argc, argv, "d:s:a:ocj:m:p:evr:bx:kl:");
if (ic < 0)
break;

Expand Down Expand Up @@ -115,6 +115,9 @@ void DedLauncher::Process(int argc, char** argv) {
case 'k':
keep_jasmin_files_ = true;
break;
case 'l':
offset_limit_ = optarg;
break;
default:
want_usage = true;
break;
Expand All @@ -140,12 +143,12 @@ void DedLauncher::Process(int argc, char** argv) {
* Display usage information.
*/
void DedLauncher::Usage() const {
fprintf(stderr, "Copyright (C) 2012 The Pennsylvania State University\n"
fprintf(stderr, "Copyright (C) 2012-2013 The Pennsylvania State University\n"
"Systems and Internet Infrastructure Security Laboratory\n\n");
fprintf(stderr,
"Usage: dare-launcher-%s [-d <output dir>] [-s <Soot classes>] "
"[-a <library classes>] [-o] [-c] [-j <jasmin jar>] [-m <maxine script>] "
"[-p] [-e] <dex or apk file>\n", DedLauncher::version());
"[-p <Dalvik verifier>] [-e] <dex or apk file>\n", DedLauncher::version());
fprintf(stderr, " -d <output dir>: set output directory\n");
fprintf(stderr, " -s <Soot classes> : define Soot/Polyglot/Jasmin class "
" locations (separated by a : character)\n");
Expand All @@ -156,8 +159,8 @@ void DedLauncher::Usage() const {
fprintf(stderr, " -j <jasmin jar> : set the path to the Jasmin jar\n");
fprintf(stderr, " -m <maxine script> : set the path to the Maxine max or mx "
"script\n");
fprintf(stderr, " -p : use Dalvik verifier annotations to make the code "
"verifiable\n");
fprintf(stderr, " -p <Dalvik verifier>: set the path to the Dalvik verifier, "
"if pre-verification is desired\n");
fprintf(stderr, " -e : prevent exception table splitting\n");
fprintf(stderr, " -v : version number\n");
fprintf(stderr, " -b : generate stubs\n");
Expand Down Expand Up @@ -279,7 +282,7 @@ int DedLauncher::ExecuteDare(const string& options, int* dare_status) const {
struct timeval time1;
struct timeval time2;
string cmd = dare_;
cmd += " -d " + dclass_ + "/ " + options +
cmd += " -d " + dclass_ + "/ -l " + offset_limit_ + options +
(no_split_tables_ ? " -e " : " ") + i_file_name_;

return StartProcess(cmd, 3000, NULL, dare_status);
Expand Down
4 changes: 3 additions & 1 deletion dare/launcher/dare_launcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class DedLauncher {
bad_input_classes_(0),
dare_(std::string("./dare-") + kVersion),
generate_stubs_(false),
keep_jasmin_files_(false) {}
keep_jasmin_files_(false),
offset_limit_("5000") {}

/**
* Process a dex or apk file.
Expand Down Expand Up @@ -257,6 +258,7 @@ class DedLauncher {
bool generate_stubs_;
std::vector<std::string> vm_options_;
bool keep_jasmin_files_;
const char* offset_limit_;
};

#endif /* DARE_LAUNCHER_H_ */

0 comments on commit 6be95ae

Please sign in to comment.