/* * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. * Original author: Edmund Wagner * Creation date: 31.05.2007 * * Source: $HeadURL$ * Last changed: $LastChangedDate$ * * the unrar licence applies to all junrar source and binary distributions * you are not allowed to use this source to re-create the RAR compression algorithm * * Here some html entities which can be used for escaping javadoc tags: * "&": "&" or "&" * "<": "<" or "<" * ">": ">" or ">" * "@": "@" */ package com.github.junrar.unpack.vm; import java.util.List; import java.util.Vector; import com.github.junrar.crc.RarCRC; import com.github.junrar.io.Raw; /** * DOCUMENT ME * * @author $LastChangedBy$ * @version $LastChangedRevision$ */ public class RarVM extends BitInput { public static final int VM_MEMSIZE = 0x40000; public static final int VM_MEMMASK = (VM_MEMSIZE - 1); public static final int VM_GLOBALMEMADDR = 0x3C000; public static final int VM_GLOBALMEMSIZE = 0x2000; public static final int VM_FIXEDGLOBALSIZE = 64; private static final int regCount = 8; private static final long UINT_MASK = 0xffffFFFF;//((long)2*(long)Integer.MAX_VALUE); private byte[] mem; private int[] R = new int[regCount]; private int flags; private int maxOpCount = 25000000; private int codeSize; private int IP; public RarVM() { mem = null; } public void init() { if (mem == null) { mem = new byte[VM_MEMSIZE + 4]; } } private boolean isVMMem(byte[] mem) { return this.mem == mem; } private int getValue(boolean byteMode, byte[] mem, int offset) { if (byteMode) { if (isVMMem(mem)) { return (mem[offset]); } else { return (mem[offset] & 0xff); } } else { if (isVMMem(mem)) { //little return Raw.readIntLittleEndian(mem, offset); } else //big endian return Raw.readIntBigEndian(mem, offset); } } private void setValue(boolean byteMode, byte[] mem, int offset, int value) { if (byteMode) { if (isVMMem(mem)) { mem[offset] = (byte) value; } else { mem[offset] = (byte) ((mem[offset] & 0x00) | (byte) (value & 0xff)); } } else { if (isVMMem(mem)) { Raw.writeIntLittleEndian(mem, offset, value); // mem[offset + 0] = (byte) value; // mem[offset + 1] = (byte) (value >>> 8); // mem[offset + 2] = (byte) (value >>> 16); // mem[offset + 3] = (byte) (value >>> 24); } else { Raw.writeIntBigEndian(mem, offset, value); // mem[offset + 3] = (byte) value; // mem[offset + 2] = (byte) (value >>> 8); // mem[offset + 1] = (byte) (value >>> 16); // mem[offset + 0] = (byte) (value >>> 24); } } // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint // *)Addr,Value) } public void setLowEndianValue(byte[] mem, int offset, int value) { Raw.writeIntLittleEndian(mem, offset, value); // mem[offset + 0] = (byte) (value&0xff); // mem[offset + 1] = (byte) ((value >>> 8)&0xff); // mem[offset + 2] = (byte) ((value >>> 16)&0xff); // mem[offset + 3] = (byte) ((value >>> 24)&0xff); } public void setLowEndianValue(Vector<Byte> mem, int offset, int value) { mem.set(offset + 0, Byte.valueOf((byte) (value&0xff))) ; mem.set(offset + 1, Byte.valueOf((byte) ((value >>> 8)&0xff))); mem.set(offset + 2, Byte.valueOf((byte) ((value >>> 16)&0xff) )); mem.set(offset + 3, Byte.valueOf((byte) ((value >>> 24)&0xff))) ; } private int getOperand(VMPreparedOperand cmdOp) { int ret = 0; if (cmdOp.getType() == VMOpType.VM_OPREGMEM) { int pos = (cmdOp.getOffset() + cmdOp.getBase()) & VM_MEMMASK; ret = Raw.readIntLittleEndian(mem, pos); } else { int pos = cmdOp.getOffset(); ret = Raw.readIntLittleEndian(mem, pos); } return ret; } public void execute(VMPreparedProgram prg) { for (int i = 0; i < prg.getInitR().length; i++) // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); { R[i] = prg.getInitR()[i]; } long globalSize = Math .min(prg.getGlobalData().size(), VM_GLOBALMEMSIZE) & 0xffFFffFF; if (globalSize != 0) { for (int i = 0; i < globalSize; i++) // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); { mem[VM_GLOBALMEMADDR + i] = prg.getGlobalData().get(i); } } long staticSize = Math.min(prg.getStaticData().size(), VM_GLOBALMEMSIZE - globalSize) & 0xffFFffFF; if (staticSize != 0) { for (int i = 0; i < staticSize; i++) // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); { mem[VM_GLOBALMEMADDR + (int) globalSize + i] = prg .getStaticData().get(i); } } R[7] = VM_MEMSIZE; flags = 0; List<VMPreparedCommand> preparedCode = prg.getAltCmd().size() != 0 ? prg .getAltCmd() : prg.getCmd(); if (!ExecuteCode(preparedCode, prg.getCmdCount())) { preparedCode.get(0).setOpCode(VMCommands.VM_RET); } int newBlockPos = getValue(false, mem, VM_GLOBALMEMADDR + 0x20) & VM_MEMMASK; int newBlockSize = getValue(false, mem, VM_GLOBALMEMADDR + 0x1c) & VM_MEMMASK; if ((newBlockPos + newBlockSize) >= VM_MEMSIZE) { newBlockPos = 0; newBlockSize = 0; } prg.setFilteredDataOffset(newBlockPos); prg.setFilteredDataSize(newBlockSize); prg.getGlobalData().clear(); int dataSize = Math.min(getValue(false, mem, VM_GLOBALMEMADDR + 0x30), VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE); if (dataSize != 0) { prg.getGlobalData().setSize(dataSize + VM_FIXEDGLOBALSIZE); // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); for (int i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); { prg.getGlobalData().set(i, mem[VM_GLOBALMEMADDR + i]); } } } public byte[] getMem() { return mem; } private boolean setIP(int ip) { if ((ip) >= codeSize) { return (true); } if (--maxOpCount <= 0) { return (false); } IP = ip; return true; } private boolean ExecuteCode(List<VMPreparedCommand> preparedCode, int cmdCount) { maxOpCount = 25000000; this.codeSize = cmdCount; this.IP = 0; while (true) { VMPreparedCommand cmd = preparedCode.get(IP); int op1 = getOperand(cmd.getOp1()); int op2 = getOperand(cmd.getOp2()); switch (cmd.getOpCode()) { case VM_MOV: setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(), mem, op2)); // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); break; case VM_MOVB: setValue(true, mem, op1, getValue(true, mem, op2)); break; case VM_MOVD: setValue(false, mem, op1, getValue(false, mem, op2)); break; case VM_CMP: { int value1 = getValue(cmd.isByteMode(), mem, op1); int result = value1 - getValue(cmd.isByteMode(), mem, op2); if (result == 0) { flags = VMFlags.VM_FZ.getFlag(); } else { flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS .getFlag()); } } break; case VM_CMPB: { int value1 = getValue(true, mem, op1); int result = value1 - getValue(true, mem, op2); if (result == 0) { flags = VMFlags.VM_FZ.getFlag(); } else { flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS .getFlag()); } } break; case VM_CMPD: { int value1 = getValue(false, mem, op1); int result = value1 - getValue(false, mem, op2); if (result == 0) { flags = VMFlags.VM_FZ.getFlag(); } else { flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS .getFlag()); } } break; case VM_ADD: { int value1 = getValue(cmd.isByteMode(), mem, op1); int result = (int) ((((long) value1 + (long) getValue(cmd .isByteMode(), mem, op2))) & 0xffffffff); if (cmd.isByteMode()) { result &= 0xff; flags = (result < value1) ? 1 : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() : ((result & 0x80) != 0) ? VMFlags.VM_FS .getFlag() : 0); // Flags=(Result<Value1)|(Result==0 ? VM_FZ:((Result&0x80) ? // VM_FS:0)); } else flags = (result < value1) ? 1 : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() : (result & VMFlags.VM_FS.getFlag())); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_ADDB: setValue(true, mem, op1, (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + (long) getValue(true, mem, op2) & 0xFFffFFff)); break; case VM_ADDD: setValue( false, mem, op1, (int) ((long) getValue(false, mem, op1) & 0xFFffFFff + (long) getValue(false, mem, op2) & 0xFFffFFff)); break; case VM_SUB: { int value1 = getValue(cmd.isByteMode(), mem, op1); int result = (int) ((long) value1 & 0xffFFffFF - (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff); flags = (result == 0) ? VMFlags.VM_FZ.getFlag() : (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS .getFlag()); setValue(cmd.isByteMode(), mem, op1, result);// (Cmd->ByteMode,Op1,Result); } break; case VM_SUBB: setValue(true, mem, op1, (int) ((long) getValue(true, mem, op1) & 0xFFffFFff - (long) getValue(true, mem, op2) & 0xFFffFFff)); break; case VM_SUBD: setValue( false, mem, op1, (int) ((long) getValue(false, mem, op1) & 0xFFffFFff - (long) getValue(false, mem, op2) & 0xFFffFFff)); break; case VM_JZ: if ((flags & VMFlags.VM_FZ.getFlag()) != 0) { setIP(getValue(false, mem, op1)); continue; } break; case VM_JNZ: if ((flags & VMFlags.VM_FZ.getFlag()) == 0) { setIP(getValue(false, mem, op1)); continue; } break; case VM_INC: { int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff + 1); if (cmd.isByteMode()) { result &= 0xff; } setValue(cmd.isByteMode(), mem, op1, result); flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result & VMFlags.VM_FS.getFlag(); } break; case VM_INCB: setValue( true, mem, op1, (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + 1)); break; case VM_INCD: setValue(false, mem, op1, (int) ((long) getValue(false, mem, op1) & 0xFFffFFff + 1)); break; case VM_DEC: { int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff - 1); setValue(cmd.isByteMode(), mem, op1, result); flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result & VMFlags.VM_FS.getFlag(); } break; case VM_DECB: setValue( true, mem, op1, (int) ((long) getValue(true, mem, op1) & 0xFFffFFff - 1)); break; case VM_DECD: setValue(false, mem, op1, (int) ((long) getValue(false, mem, op1) & 0xFFffFFff - 1)); break; case VM_JMP: setIP(getValue(false, mem, op1)); continue; case VM_XOR: { int result = getValue(cmd.isByteMode(), mem, op1) ^ getValue(cmd.isByteMode(), mem, op2); flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result & VMFlags.VM_FS.getFlag(); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_AND: { int result = getValue(cmd.isByteMode(), mem, op1) & getValue(cmd.isByteMode(), mem, op2); flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result & VMFlags.VM_FS.getFlag(); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_OR: { int result = getValue(cmd.isByteMode(), mem, op1) | getValue(cmd.isByteMode(), mem, op2); flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result & VMFlags.VM_FS.getFlag(); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_TEST: { int result = getValue(cmd.isByteMode(), mem, op1) & getValue(cmd.isByteMode(), mem, op2); flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result & VMFlags.VM_FS.getFlag(); } break; case VM_JS: if ((flags & VMFlags.VM_FS.getFlag()) != 0) { setIP(getValue(false, mem, op1)); continue; } break; case VM_JNS: if ((flags & VMFlags.VM_FS.getFlag()) == 0) { setIP(getValue(false, mem, op1)); continue; } break; case VM_JB: if ((flags & VMFlags.VM_FC.getFlag()) != 0) { setIP(getValue(false, mem, op1)); continue; } break; case VM_JBE: if ((flags & (VMFlags.VM_FC.getFlag() | VMFlags.VM_FZ.getFlag())) != 0) { setIP(getValue(false, mem, op1)); continue; } break; case VM_JA: if ((flags & (VMFlags.VM_FC.getFlag() | VMFlags.VM_FZ.getFlag())) == 0) { setIP(getValue(false, mem, op1)); continue; } break; case VM_JAE: if ((flags & VMFlags.VM_FC.getFlag()) == 0) { setIP(getValue(false, mem, op1)); continue; } break; case VM_PUSH: R[7] -= 4; setValue(false, mem, R[7] & VM_MEMMASK, getValue(false, mem, op1)); break; case VM_POP: setValue(false, mem, op1, getValue(false, mem, R[7] & VM_MEMMASK)); R[7] += 4; break; case VM_CALL: R[7] -= 4; setValue(false, mem, R[7] & VM_MEMMASK, IP + 1); setIP(getValue(false, mem, op1)); continue; case VM_NOT: setValue(cmd.isByteMode(), mem, op1, ~getValue( cmd.isByteMode(), mem, op1)); break; case VM_SHL: { int value1 = getValue(cmd.isByteMode(), mem, op1); int value2 = getValue(cmd.isByteMode(), mem, op2); int result = value1 << value2; flags = (result == 0 ? VMFlags.VM_FZ.getFlag() : (result & VMFlags.VM_FS.getFlag())) | (((value1 << (value2 - 1)) & 0x80000000) != 0 ? VMFlags.VM_FC .getFlag() : 0); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_SHR: { int value1 = getValue(cmd.isByteMode(), mem, op1); int value2 = getValue(cmd.isByteMode(), mem, op2); int result = value1 >>> value2; flags = (result == 0 ? VMFlags.VM_FZ.getFlag() : (result & VMFlags.VM_FS.getFlag())) | ((value1 >>> (value2 - 1)) & VMFlags.VM_FC.getFlag()); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_SAR: { int value1 = getValue(cmd.isByteMode(), mem, op1); int value2 = getValue(cmd.isByteMode(), mem, op2); int result = ((int) value1) >> value2; flags = (result == 0 ? VMFlags.VM_FZ.getFlag() : (result & VMFlags.VM_FS.getFlag())) | ((value1 >> (value2 - 1)) & VMFlags.VM_FC.getFlag()); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_NEG: { int result = -getValue(cmd.isByteMode(), mem, op1); flags = result == 0 ? VMFlags.VM_FZ.getFlag() : VMFlags.VM_FC .getFlag() | (result & VMFlags.VM_FS.getFlag()); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_NEGB: setValue(true, mem, op1, -getValue(true, mem, op1)); break; case VM_NEGD: setValue(false, mem, op1, -getValue(false, mem, op1)); break; case VM_PUSHA: { for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) { setValue(false, mem, SP & VM_MEMMASK, R[i]); } R[7] -= regCount * 4; } break; case VM_POPA: { for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) R[7 - i] = getValue(false, mem, SP & VM_MEMMASK); } break; case VM_PUSHF: R[7] -= 4; setValue(false, mem, R[7] & VM_MEMMASK, flags); break; case VM_POPF: flags = getValue(false, mem, R[7] & VM_MEMMASK); R[7] += 4; break; case VM_MOVZX: setValue(false, mem, op1, getValue(true, mem, op2)); break; case VM_MOVSX: setValue(false, mem, op1, (byte) getValue(true, mem, op2)); break; case VM_XCHG: { int value1 = getValue(cmd.isByteMode(), mem, op1); setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(), mem, op2)); setValue(cmd.isByteMode(), mem, op2, value1); } break; case VM_MUL: { int result = (int) (((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff * (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff) & 0xFFffFFff); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_DIV: { int divider = getValue(cmd.isByteMode(), mem, op2); if (divider != 0) { int result = getValue(cmd.isByteMode(), mem, op1) / divider; setValue(cmd.isByteMode(), mem, op1, result); } } break; case VM_ADC: { int value1 = getValue(cmd.isByteMode(), mem, op1); int FC = (flags & VMFlags.VM_FC.getFlag()); int result = (int) ((long) value1 & 0xFFffFFff + (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff + (long) FC & 0xFFffFFff); if (cmd.isByteMode()) { result &= 0xff; } flags = (result < value1 || result == value1 && FC != 0) ? 1 : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() : (result & VMFlags.VM_FS.getFlag())); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_SBB: { int value1 = getValue(cmd.isByteMode(), mem, op1); int FC = (flags & VMFlags.VM_FC.getFlag()); int result = (int) ((long) value1 & 0xFFffFFff - (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff - (long) FC & 0xFFffFFff); if (cmd.isByteMode()) { result &= 0xff; } flags = (result > value1 || result == value1 && FC != 0) ? 1 : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() : (result & VMFlags.VM_FS.getFlag())); setValue(cmd.isByteMode(), mem, op1, result); } break; case VM_RET: if (R[7] >= VM_MEMSIZE) { return (true); } setIP(getValue(false, mem, R[7] & VM_MEMMASK)); R[7] += 4; continue; case VM_STANDARD: ExecuteStandardFilter(VMStandardFilters.findFilter(cmd.getOp1() .getData())); break; case VM_PRINT: break; } IP++; --maxOpCount; } } public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) { InitBitInput(); int cpLength = Math.min(MAX_SIZE, codeSize); for (int i = 0; i < cpLength; i++) // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); { inBuf[i] |= code[i]; } byte xorSum = 0; for (int i = 1; i < codeSize; i++) { xorSum ^= code[i]; } faddbits(8); prg.setCmdCount(0); if (xorSum == code[0]) { VMStandardFilters filterType = IsStandardFilter(code, codeSize); if (filterType != VMStandardFilters.VMSF_NONE) { VMPreparedCommand curCmd = new VMPreparedCommand(); curCmd.setOpCode(VMCommands.VM_STANDARD); curCmd.getOp1().setData(filterType.getFilter()); curCmd.getOp1().setType(VMOpType.VM_OPNONE); curCmd.getOp2().setType(VMOpType.VM_OPNONE); codeSize = 0; prg.getCmd().add(curCmd); prg.setCmdCount(prg.getCmdCount()+1); // TODO // curCmd->Op1.Data=FilterType; // >>>>>> CurCmd->Op1.Addr=&CurCmd->Op1.Data; <<<<<<<<<< not set // do i need to ? // >>>>>> CurCmd->Op2.Addr=&CurCmd->Op2.Data; <<<<<<<<<< " // CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; // CodeSize=0; } int dataFlag = fgetbits(); faddbits(1); // Read static data contained in DB operators. This data cannot be // changed, // it is a part of VM code, not a filter parameter. if ((dataFlag & 0x8000) != 0) { long dataSize = (long) ((long) ReadData(this) & 0xffFFffFF + 1); for (int i = 0; inAddr < codeSize && i < dataSize; i++) { prg.getStaticData().add( Byte.valueOf((byte) (fgetbits() >> 8))); faddbits(8); } } while (inAddr < codeSize) { VMPreparedCommand curCmd = new VMPreparedCommand(); int data = fgetbits(); if ((data & 0x8000) == 0) { curCmd.setOpCode(VMCommands.findVMCommand((data >> 12))); faddbits(4); } else { curCmd.setOpCode(VMCommands .findVMCommand((data >> 10) - 24)); faddbits(6); } if ((VMCmdFlags.VM_CmdFlags[curCmd.getOpCode().getVMCommand()] & VMCmdFlags.VMCF_BYTEMODE) != 0) { curCmd.setByteMode((fgetbits() >> 15) == 1 ? true : false); faddbits(1); } else { curCmd.setByteMode(false); } curCmd.getOp1().setType(VMOpType.VM_OPNONE); curCmd.getOp2().setType(VMOpType.VM_OPNONE); int opNum = (VMCmdFlags.VM_CmdFlags[curCmd.getOpCode() .getVMCommand()] & VMCmdFlags.VMCF_OPMASK); // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; <<<??? if (opNum > 0) { decodeArg(curCmd.getOp1(), curCmd.isByteMode()); if (opNum == 2) decodeArg(curCmd.getOp2(), curCmd.isByteMode()); else { if (curCmd.getOp1().getType() == VMOpType.VM_OPINT && (VMCmdFlags.VM_CmdFlags[curCmd.getOpCode() .getVMCommand()] & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC)) != 0) { int distance = curCmd.getOp1().getData(); if (distance >= 256) distance -= 256; else { if (distance >= 136) { distance -= 264; } else { if (distance >= 16) { distance -= 8; } else { if (distance >= 8) { distance -= 16; } } } distance += prg.getCmdCount(); } curCmd.getOp1().setData(distance); } } } prg.setCmdCount(prg.getCmdCount() + 1); prg.getCmd().add(curCmd); } } VMPreparedCommand curCmd = new VMPreparedCommand(); curCmd.setOpCode(VMCommands.VM_RET); // TODO CurCmd->Op1.Addr=&CurCmd->Op1.Data; // CurCmd->Op2.Addr=&CurCmd->Op2.Data; curCmd.getOp1().setType(VMOpType.VM_OPNONE); curCmd.getOp2().setType(VMOpType.VM_OPNONE); // for (int i=0;i<prg.getCmdCount();i++) // { // VM_PreparedCommand *Cmd=&Prg->Cmd[I]; // if (Cmd->Op1.Addr==NULL) // Cmd->Op1.Addr=&Cmd->Op1.Data; // if (Cmd->Op2.Addr==NULL) // Cmd->Op2.Addr=&Cmd->Op2.Data; // } prg.getCmd().add(curCmd); prg.setCmdCount(prg.getCmdCount()+1); // #ifdef VM_OPTIMIZE if (codeSize != 0) { optimize(prg); } } private void decodeArg(VMPreparedOperand op, boolean byteMode) { int data = fgetbits(); if ((data & 0x8000) != 0) { op.setType(VMOpType.VM_OPREG); op.setData((data >> 12) & 7); op.setOffset(op.getData()); faddbits(4); } else { if ((data & 0xc000) == 0) { op.setType(VMOpType.VM_OPINT); if (byteMode) { op.setData((data >> 6) & 0xff); faddbits(10); } else { faddbits(2); op.setData(ReadData(this)); } } else { op.setType(VMOpType.VM_OPREGMEM); if ((data & 0x2000) == 0) { op.setData((data >> 10) & 7); op.setOffset(op.getData()); op.setBase(0); faddbits(6); } else { if ((data & 0x1000) == 0) { op.setData((data >> 9) & 7); op.setOffset(op.getData()); faddbits(7); } else { op.setData(0); faddbits(4); } op.setBase(ReadData(this)); } } } } private void optimize(VMPreparedProgram prg) { List<VMPreparedCommand> commands = prg.getCmd(); for (VMPreparedCommand cmd : commands) { switch (cmd.getOpCode()) { case VM_MOV: cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_MOVB : VMCommands.VM_MOVD); continue; case VM_CMP: cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_CMPB : VMCommands.VM_CMPD); continue; } if ((VMCmdFlags.VM_CmdFlags[cmd.getOpCode().getVMCommand()] & VMCmdFlags.VMCF_CHFLAGS) == 0) { continue; } boolean flagsRequired = false; for (int i = commands.indexOf(cmd) + 1; i < commands.size(); i++) { int flags = VMCmdFlags.VM_CmdFlags[commands.get(i).getOpCode() .getVMCommand()]; if ((flags & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC | VMCmdFlags.VMCF_USEFLAGS)) != 0) { flagsRequired = true; break; } if ((flags & VMCmdFlags.VMCF_CHFLAGS) != 0) { break; } } if (flagsRequired) { continue; } switch (cmd.getOpCode()) { case VM_ADD: cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_ADDB : VMCommands.VM_ADDD); continue; case VM_SUB: cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_SUBB : VMCommands.VM_SUBD); continue; case VM_INC: cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_INCB : VMCommands.VM_INCD); continue; case VM_DEC: cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_DECB : VMCommands.VM_DECD); continue; case VM_NEG: cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_NEGB : VMCommands.VM_NEGD); continue; } } } public static int ReadData(BitInput rarVM) { int data = rarVM.fgetbits(); switch (data & 0xc000) { case 0: rarVM.faddbits(6); return ((data >> 10) & 0xf); case 0x4000: if ((data & 0x3c00) == 0) { data = 0xffffff00 | ((data >> 2) & 0xff); rarVM.faddbits(14); } else { data = (data >> 6) & 0xff; rarVM.faddbits(10); } return (data); case 0x8000: rarVM.faddbits(2); data = rarVM.fgetbits(); rarVM.faddbits(16); return (data); default: rarVM.faddbits(2); data = (rarVM.fgetbits() << 16); rarVM.faddbits(16); data |= rarVM.fgetbits(); rarVM.faddbits(16); return (data); } } private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) { VMStandardFilterSignature stdList[]={ new VMStandardFilterSignature(53, 0xad576887, VMStandardFilters.VMSF_E8), new VMStandardFilterSignature(57, 0x3cd7e57e, VMStandardFilters.VMSF_E8E9), new VMStandardFilterSignature(120, 0x3769893f, VMStandardFilters.VMSF_ITANIUM), new VMStandardFilterSignature(29, 0x0e06077d, VMStandardFilters.VMSF_DELTA), new VMStandardFilterSignature(149, 0x1c2c5dc8, VMStandardFilters.VMSF_RGB), new VMStandardFilterSignature(216, 0xbc85e701, VMStandardFilters.VMSF_AUDIO), new VMStandardFilterSignature(40, 0x46b9c560, VMStandardFilters.VMSF_UPCASE) }; int CodeCRC = RarCRC.checkCrc(0xffffffff,code,0,code.length)^0xffffffff; for (int i=0;i<stdList.length;i++){ if (stdList[i].getCRC()==CodeCRC && stdList[i].getLength()==code.length){ return(stdList[i].getType()); } } return(VMStandardFilters.VMSF_NONE); } private void ExecuteStandardFilter(VMStandardFilters filterType) { switch(filterType) { case VMSF_E8: case VMSF_E8E9: { int dataSize=R[4]; long fileOffset=R[6]&0xFFffFFff; if (dataSize>=VM_GLOBALMEMADDR){ break; } int fileSize=0x1000000; byte cmpByte2=(byte) ((filterType==VMStandardFilters.VMSF_E8E9) ? 0xe9:0xe8); for (int curPos=0;curPos<dataSize-4;) { byte curByte=mem[curPos++]; if (curByte==0xe8 || curByte==cmpByte2) { // #ifdef PRESENT_INT32 // sint32 Offset=CurPos+FileOffset; // sint32 Addr=GET_VALUE(false,Data); // if (Addr<0) // { // if (Addr+Offset>=0) // SET_VALUE(false,Data,Addr+FileSize); // } // else // if (Addr<FileSize) // SET_VALUE(false,Data,Addr-Offset); // #else long offset=curPos+fileOffset; long Addr=getValue(false,mem,curPos); if ((Addr & 0x80000000)!=0) { if (((Addr+offset) & 0x80000000)==0) setValue(false,mem,curPos,(int)Addr+fileSize); } else { if (((Addr-fileSize) & 0x80000000)!=0){ setValue(false,mem,curPos,(int)(Addr-offset)); } } // #endif curPos+=4; } } } break; case VMSF_ITANIUM: { int dataSize=R[4]; long fileOffset=R[6]&0xFFffFFff; if (dataSize>=VM_GLOBALMEMADDR){ break; } int curPos=0; final byte Masks[]={4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0}; fileOffset>>>=4; while (curPos<dataSize-21) { int Byte=(mem[curPos]&0x1f)-0x10; if (Byte>=0) { byte cmdMask=Masks[Byte]; if (cmdMask!=0) for (int i=0;i<=2;i++) if ((cmdMask & (1<<i))!=0) { int startPos=i*41+5; int opType=filterItanium_GetBits(curPos,startPos+37,4); if (opType==5) { int offset=filterItanium_GetBits(curPos,startPos+13,20); filterItanium_SetBits(curPos,(int)(offset-fileOffset)&0xfffff,startPos+13,20); } } } curPos+=16; fileOffset++; } } break; case VMSF_DELTA: { int dataSize=R[4]&0xFFffFFff; int channels=R[0]&0xFFffFFff; int srcPos=0; int border=(dataSize*2) &0xFFffFFff; setValue(false,mem,VM_GLOBALMEMADDR+0x20,(int)dataSize); if (dataSize>=VM_GLOBALMEMADDR/2){ break; } // bytes from same channels are grouped to continual data blocks, // so we need to place them back to their interleaving positions for (int curChannel=0;curChannel<channels;curChannel++) { byte PrevByte=0; for (int destPos=dataSize+curChannel;destPos<border;destPos+=channels){ mem[destPos]=(PrevByte-=mem[srcPos++]); } } } break; case VMSF_RGB: { // byte *SrcData=Mem,*DestData=SrcData+DataSize; int dataSize=R[4],width=R[0]-3,posR=R[1]; int channels=3; int srcPos = 0; int destDataPos = dataSize; setValue(false,mem,VM_GLOBALMEMADDR+0x20,dataSize); if (dataSize>=VM_GLOBALMEMADDR/2 || posR<0){ break; } for (int curChannel=0;curChannel<channels;curChannel++) { long prevByte=0; for (int i=curChannel;i<dataSize;i+=channels) { long predicted; int upperPos=i-width; if (upperPos>=3) { int upperDataPos=destDataPos+upperPos; int upperByte=mem[(int)upperDataPos]&0xff; int upperLeftByte=mem[upperDataPos-3]&0xff; predicted=prevByte+upperByte-upperLeftByte; int pa=Math.abs((int)(predicted-prevByte)); int pb=Math.abs((int)(predicted-upperByte)); int pc=Math.abs((int)(predicted-upperLeftByte)); if (pa<=pb && pa<=pc){ predicted=prevByte; } else{ if (pb<=pc){ predicted=upperByte; } else{ predicted=upperLeftByte; } } } else{ predicted=prevByte; } prevByte=(predicted-mem[srcPos++]&0xff)&0xff; mem[destDataPos+i]=(byte)(prevByte&0xff); } } for (int i=posR,border=dataSize-2;i<border;i+=3) { byte G=mem[destDataPos+i+1]; mem[destDataPos+i]+=G; mem[destDataPos+i+2]+=G; } } break; case VMSF_AUDIO: { int dataSize=R[4],channels=R[0]; int srcPos = 0; int destDataPos = dataSize; //byte *SrcData=Mem,*DestData=SrcData+DataSize; setValue(false,mem,VM_GLOBALMEMADDR+0x20,dataSize); if (dataSize>=VM_GLOBALMEMADDR/2){ break; } for (int curChannel=0;curChannel<channels;curChannel++) { long prevByte=0; long prevDelta=0; long Dif[] = new long[7]; int D1=0,D2=0,D3; int K1=0,K2=0,K3=0; for (int i=curChannel,byteCount=0;i<dataSize;i+=channels,byteCount++) { D3=D2; D2=(int)prevDelta-D1; D1=(int)prevDelta; long predicted=8*prevByte+K1*D1+K2*D2+K3*D3; predicted=(predicted>>>3) & 0xff; long curByte=mem[srcPos++]&0xff; predicted = (predicted - curByte)&UINT_MASK; mem[destDataPos+i]=(byte)predicted; prevDelta=(byte)(predicted-prevByte); prevByte=predicted; int D=((byte)curByte)<<3; Dif[0]+=Math.abs(D); Dif[1]+=Math.abs(D-D1); Dif[2]+=Math.abs(D+D1); Dif[3]+=Math.abs(D-D2); Dif[4]+=Math.abs(D+D2); Dif[5]+=Math.abs(D-D3); Dif[6]+=Math.abs(D+D3); if ((byteCount & 0x1f)==0) { long minDif=Dif[0], numMinDif=0; Dif[0]=0; for (int j=1;j<Dif.length;j++) { if (Dif[j]<minDif) { minDif=Dif[j]; numMinDif=j; } Dif[j]=0; } switch((int)numMinDif) { case 1: if (K1>=-16) K1--; break; case 2: if (K1 < 16) K1++; break; case 3: if (K2>=-16) K2--; break; case 4: if (K2 < 16) K2++; break; case 5: if (K3>=-16) K3--; break; case 6: if (K3 < 16) K3++; break; } } } } } break; case VMSF_UPCASE: { int dataSize=R[4],srcPos=0,destPos=dataSize; if (dataSize>=VM_GLOBALMEMADDR/2){ break; } while (srcPos<dataSize) { byte curByte=mem[srcPos++]; if (curByte==2 && (curByte=mem[srcPos++])!=2){ curByte-=32; } mem[destPos++]=curByte; } setValue(false,mem,VM_GLOBALMEMADDR+0x1c,destPos-dataSize); setValue(false,mem,VM_GLOBALMEMADDR+0x20,dataSize); } break; } } private void filterItanium_SetBits(int curPos, int bitField, int bitPos, int bitCount) { int inAddr=bitPos/8; int inBit=bitPos&7; int andMask=0xffffffff>>>(32-bitCount); andMask=~(andMask<<inBit); bitField<<=inBit; for (int i=0;i<4;i++) { mem[curPos+inAddr+i]&=andMask; mem[curPos+inAddr+i]|=bitField; andMask=(andMask>>>8)|0xff000000; bitField>>>=8; } } private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) { int inAddr=bitPos/8; int inBit=bitPos&7; int bitField=(int)(mem[curPos+inAddr++]&0xff); bitField|=(int) ((mem[curPos+inAddr++]&0xff) << 8); bitField|=(int) ((mem[curPos+inAddr++]&0xff) << 16); bitField|=(int) ((mem[curPos+inAddr]&0xff) << 24); bitField >>>= inBit; return(bitField & (0xffffffff>>>(32-bitCount))); } public void setMemory(int pos,byte[] data,int offset,int dataSize) { if (pos<VM_MEMSIZE){ //&& data!=Mem+Pos) //memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos)); for (int i = 0; i < Math.min(data.length-offset,dataSize); i++) { if((VM_MEMSIZE-pos)<i){ break; } mem[pos+i] = data[offset+i]; } } } } //