/*
* Copyright (C) 2012 Sony Mobile Communications AB
*
* This file is part of ApkAnalyser.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package andreflect.gui.action.injection;
import java.awt.event.ActionEvent;
import java.util.Iterator;
import javax.swing.Icon;
import jerl.bcm.inj.Injection;
import mereflect.MEMethod;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib.FieldIdItem;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.InstructionWithReference;
import analyser.gui.MainFrame;
import analyser.gui.Selection;
import analyser.gui.TextBuilder;
import analyser.gui.actions.bytecodemod.AbstractTreeBytecodeModAction;
import analyser.logic.BytecodeModificationMediator;
import analyser.logic.RefContext;
import analyser.logic.RefField;
import analyser.logic.RefFieldAccess;
import analyser.logic.RefMethod;
import analyser.logic.Reference;
import andreflect.ApkClassContext;
import andreflect.DexField;
import andreflect.DexMethod;
import andreflect.Util;
import andreflect.injection.impl.DalvikMethodField;
public class DalvikMethodFieldWriteAction extends AbstractTreeBytecodeModAction {
private static final long serialVersionUID = -1273863284481378500L;
protected static DalvikMethodFieldWriteAction m_inst = null;
protected static DalvikMethodFieldWriteAction m_inst_onefield = null;
int traverseCount, traverseIndex = 0;
FieldIdItem fieldIdItem;
public static DalvikMethodFieldWriteAction getInstance(MainFrame mainFrame)
{
if (m_inst == null)
{
m_inst = new DalvikMethodFieldWriteAction("Print writing all fields", null);
m_inst.setMainFrame(mainFrame);
}
return m_inst;
}
public static DalvikMethodFieldWriteAction getInstanceOneField(MainFrame mainFrame)
{
if (m_inst_onefield == null)
{
m_inst_onefield = new DalvikMethodFieldWriteAction("Print writing this field", null);
m_inst_onefield.setMainFrame(mainFrame);
}
return m_inst_onefield;
}
protected DalvikMethodFieldWriteAction(String arg0, Icon arg1)
{
super(arg0, arg1);
}
@Override
public void run(ActionEvent e) throws Throwable {
if (Selection.getSelectedView() instanceof TextBuilder) {
} else {
Object ref = Selection.getSelectedObject();
if (ref != null && ref instanceof RefField) {
RefField rf = (RefField) ref;
Iterator<Reference> i = rf.getChildren().iterator();
while (i.hasNext()) {
RefFieldAccess access = (RefFieldAccess) i.next();
fieldIdItem = access.getAccess().fieldIdItem;
if (access.getAccess().isRead == false) {
createInjection(access.getAccess().method);
}
}
return;
}
}
super.run(e);
}
@Override
protected void modify(MEMethod method) throws Throwable {
fieldIdItem = Util.getFieldIdItem();
if (fieldIdItem == null) {
if (method.isAbstract()) {
return;
}
DexMethod dexMethod = (DexMethod) method;
if (hasWriteField(dexMethod, fieldIdItem)) {
createInjection(dexMethod);
}
} else {
Object ref = Selection.getSelectedView();
TextBuilder tb = (TextBuilder) ref;
Object lineRef = tb.getLineBuilder().getReference(tb.getCurrentLine());
ApkClassContext apkContext = (ApkClassContext) (((DexField) lineRef).getDexClass().getResource().getContext());
Iterator<Reference> i = MainFrame.getInstance().getResolver().getMidletResources().iterator();
RefContext refContext = null;
while (i.hasNext()) {
Object obj = i.next();
if (obj instanceof RefContext
&& ((RefContext) obj).getContext() == apkContext) {
refContext = (RefContext) obj;
break;
}
}
if (refContext != null) {
traverseCount = 0;
traverseIndex = 0;
getTraverseCount(refContext);
if (traverseCount != 0) {
traverseInside(refContext);
}
}
}
}
private void createInjection(DexMethod method) {
DalvikMethodField fieldInjection = new DalvikMethodField(getMethodSignature(method),
method.getMEClass().getName() + ":" + getMethodSignature(method),
fieldIdItem,
false);
BytecodeModificationMediator.getInstance().registerModification(
method.getMEClass().getResource().getContext(),
method.getMEClass(),
fieldInjection,
method);
((MainFrame) getMainFrame()).getMidletTree().findAndMarkNode(method, Reference.MODIFIED);
}
protected void getTraverseCount(Reference ref) throws Throwable {
if (ref instanceof RefMethod) {
traverseCount++;
} else {
Iterator<Reference> i = ref.getChildren().iterator();
while (i.hasNext()) {
getTraverseCount(i.next());
}
}
}
protected void traverseInside(Reference ref) throws Throwable {
if (ref instanceof RefMethod) {
if (hasWriteField((DexMethod) ((RefMethod) ref).getMethod(), fieldIdItem)) {
createInjection((DexMethod) ((RefMethod) ref).getMethod());
}
getMainFrame().actionReportWork(this, 100 * traverseIndex++ / traverseCount);
} else {
Iterator<Reference> i = ref.getChildren().iterator();
while (i.hasNext()) {
traverseInside(i.next());
}
}
}
@Override
protected Injection getInjection(String className, String methodSignature) {
//not used
return null;
}
public boolean hasWriteField(DexMethod method, FieldIdItem fieldIdItem) {
boolean ret = false;
CodeItem codeItem = method.getEncodedMethod().codeItem;
if (codeItem != null) {
Instruction[] instructions = method.getEncodedMethod().codeItem.getInstructions();
for (Instruction instruction : instructions) {
switch (instruction.deodexedInstruction.opcode) {
case IPUT:
case IPUT_WIDE:
case IPUT_OBJECT:
case IPUT_BOOLEAN:
case IPUT_BYTE:
case IPUT_CHAR:
case IPUT_SHORT:
case SPUT:
case SPUT_WIDE:
case SPUT_OBJECT:
case SPUT_BOOLEAN:
case SPUT_BYTE:
case SPUT_CHAR:
case SPUT_SHORT:
if (fieldIdItem == null
|| ((InstructionWithReference) instruction).getReferencedItem() == fieldIdItem) {
ret = true;
}
break;
/*
case IPUT_QUICK:
case IPUT_WIDE_QUICK:
case IPUT_OBJECT_QUICK:
//for gingerbread
case IPUT_VOLATILE:
case IPUT_WIDE_VOLATILE:
case IPUT_OBJECT_VOLATILE:
case SPUT_VOLATILE:
case SPUT_WIDE_VOLATILE:
case SPUT_OBJECT_VOLATILE:
Instruction deodexedIns = method.getDeodexedInstruction(instruction);
if (fieldIdItem == null
||((InstructionWithReference)deodexedIns).getReferencedItem() == fieldIdItem){
ret = true;
}
break;
*/
}
if (ret == true) {
break;
}
}
}
return ret;
}
}