# vm逆向

vm逆向

虚拟机逆向与实现-CSDN博客

对上面博客的总结。

vm逆向题,一般是小型虚拟机程序,可以理解为一种模拟器,有start,dispatcher,opcode等结构。常见使用while-switch/if这类循环+选择结构来实现简单的虚拟机模拟,如下:

逆向重点:

  • 分析入口,搞清输入和opcode的位置

  • 理清结构,包括dispatcher和各handler

  • 逆向各handler,分析opcode意义

小型虚拟机实现

目标:

  • 定义一套opcode

  • 实现opcode解释器

要点:

  • 定义系列虚拟寄存器ri,指针eip指向正在解释的地址,opcode及其对应处理函数的列表

  • 初始化。将寄存器置0,eip指向opcode首地址,并初始化opcode列表每一项的opcode值以及对应的handle函数。

  • start。用while循环结构,如果eip目前指向的opcode不为ret(或其他标识程序结束的指令),那么调用dispatcher来执行当前eip所指向的指令。

  • dispatcher。在opcode列表中查找当前需要的opcode,如果找到,那么执行对应的handler函数,退出遍历。

  • 注意要关注handler函数所占字节数,函数执行完毕后要将eip偏移相应位移。

例题:moectf2024 moejvav

用jadx打开,看Main:

package defpackage;

import exceptions.BuDaoLePaoException;
import exceptions.DxIsNanTongException;
import exceptions.GenshinImpactException;
import exceptions.LuoIsNotDogException;
import exceptions.NotSigninException;
import exceptions.NullCafeException;
import exceptions.StarrySkyMeowNotFoundException;
import exceptions.TokioEatWhatException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/* renamed from: Main  reason: default package */
/* loaded from: moejvav.jar:Main.class */
public class Main {
    public static void main(String[] args) {
        System.out.println("这里是moejvav! 请输入你的flag:");
        String flag = new Scanner(System.in).next();
        if (flag.length() != 44) {
            System.out.println("flag长度不对");
            return;
        }
        List<Byte> array = new ArrayList<>();
        for (byte b : flag.getBytes(StandardCharsets.UTF_8)) {
            array.add(Byte.valueOf((byte) ((Byte.valueOf(b).byteValue() ^ 202) + 32)));
        }
        int[] vmInsn = new int[310];
        vmInsn[0] = 0;
        vmInsn[1] = 1;
        vmInsn[2] = 60;
        vmInsn[3] = 2;
        vmInsn[4] = -20;
        vmInsn[5] = 6;
        vmInsn[6] = -25;
        vmInsn[7] = 0;
        vmInsn[8] = 1;
        vmInsn[9] = 60;
        vmInsn[10] = 2;
        vmInsn[11] = -20;
        vmInsn[12] = 6;
        vmInsn[13] = -27;
        vmInsn[14] = 0;
        vmInsn[15] = 1;
        vmInsn[16] = 60;
        vmInsn[17] = 2;
        vmInsn[18] = -20;
        vmInsn[19] = 6;
        vmInsn[20] = -33;
        vmInsn[21] = 0;
        vmInsn[22] = 1;
        vmInsn[23] = 60;
        vmInsn[24] = 2;
        vmInsn[25] = -20;
        vmInsn[26] = 6;
        vmInsn[27] = -31;
        vmInsn[28] = 0;
        vmInsn[29] = 1;
        vmInsn[30] = 60;
        vmInsn[31] = 2;
        vmInsn[32] = -20;
        vmInsn[33] = 6;
        vmInsn[34] = -50;
        vmInsn[35] = 0;
        vmInsn[36] = 1;
        vmInsn[37] = 60;
        vmInsn[38] = 2;
        vmInsn[39] = -20;
        vmInsn[40] = 6;
        vmInsn[41] = -36;
        vmInsn[42] = 0;
        vmInsn[43] = 1;
        vmInsn[44] = 60;
        vmInsn[45] = 2;
        vmInsn[46] = -20;
        vmInsn[47] = 6;
        vmInsn[48] = -39;
        vmInsn[49] = 0;
        vmInsn[50] = 1;
        vmInsn[51] = 60;
        vmInsn[52] = 2;
        vmInsn[53] = -20;
        vmInsn[54] = 6;
        vmInsn[55] = -24;
        vmInsn[56] = 0;
        vmInsn[57] = 1;
        vmInsn[58] = 60;
        vmInsn[59] = 2;
        vmInsn[60] = -20;
        vmInsn[61] = 6;
        vmInsn[62] = -52;
        vmInsn[63] = 0;
        vmInsn[64] = 1;
        vmInsn[65] = 60;
        vmInsn[66] = 2;
        vmInsn[67] = -20;
        vmInsn[68] = 6;
        vmInsn[69] = -29;
        vmInsn[70] = 0;
        vmInsn[71] = 1;
        vmInsn[72] = 60;
        vmInsn[73] = 2;
        vmInsn[74] = -20;
        vmInsn[75] = 6;
        vmInsn[76] = -52;
        vmInsn[77] = 0;
        vmInsn[78] = 1;
        vmInsn[79] = 14;
        vmInsn[80] = 2;
        vmInsn[81] = 5;
        vmInsn[82] = 6;
        vmInsn[83] = -64;
        vmInsn[84] = 0;
        vmInsn[85] = 1;
        vmInsn[86] = 14;
        vmInsn[87] = 2;
        vmInsn[88] = 5;
        vmInsn[89] = 6;
        vmInsn[90] = -58;
        vmInsn[91] = 0;
        vmInsn[92] = 1;
        vmInsn[93] = 14;
        vmInsn[94] = 2;
        vmInsn[95] = 5;
        vmInsn[96] = 6;
        vmInsn[97] = -63;
        vmInsn[98] = 0;
        vmInsn[99] = 1;
        vmInsn[100] = 14;
        vmInsn[101] = 2;
        vmInsn[102] = 5;
        vmInsn[103] = 6;
        vmInsn[104] = -52;
        vmInsn[105] = 0;
        vmInsn[106] = 1;
        vmInsn[107] = 14;
        vmInsn[108] = 2;
        vmInsn[109] = 5;
        vmInsn[110] = 6;
        vmInsn[111] = -90;
        vmInsn[112] = 0;
        vmInsn[113] = 1;
        vmInsn[114] = 14;
        vmInsn[115] = 2;
        vmInsn[116] = 5;
        vmInsn[117] = 6;
        vmInsn[118] = -39;
        vmInsn[119] = 0;
        vmInsn[120] = 1;
        vmInsn[121] = 14;
        vmInsn[122] = 2;
        vmInsn[123] = 5;
        vmInsn[124] = 6;
        vmInsn[125] = -43;
        vmInsn[126] = 0;
        vmInsn[127] = 1;
        vmInsn[128] = 14;
        vmInsn[129] = 2;
        vmInsn[130] = 5;
        vmInsn[131] = 6;
        vmInsn[132] = 26;
        vmInsn[133] = 0;
        vmInsn[134] = 1;
        vmInsn[135] = 14;
        vmInsn[136] = 2;
        vmInsn[137] = 5;
        vmInsn[138] = 6;
        vmInsn[139] = 25;
        vmInsn[140] = 0;
        vmInsn[141] = 1;
        vmInsn[142] = 14;
        vmInsn[143] = 2;
        vmInsn[144] = 5;
        vmInsn[145] = 6;
        vmInsn[146] = -49;
        vmInsn[147] = 0;
        vmInsn[148] = 1;
        vmInsn[149] = 14;
        vmInsn[150] = 2;
        vmInsn[151] = 5;
        vmInsn[152] = 6;
        vmInsn[153] = -64;
        vmInsn[154] = 0;
        vmInsn[155] = 1;
        vmInsn[156] = 10;
        vmInsn[157] = 2;
        vmInsn[158] = 5;
        vmInsn[159] = 6;
        vmInsn[160] = -51;
        vmInsn[161] = 0;
        vmInsn[162] = 1;
        vmInsn[163] = 10;
        vmInsn[164] = 2;
        vmInsn[165] = 5;
        vmInsn[166] = 6;
        vmInsn[167] = 25;
        vmInsn[168] = 0;
        vmInsn[169] = 1;
        vmInsn[170] = 10;
        vmInsn[171] = 2;
        vmInsn[172] = 5;
        vmInsn[173] = 6;
        vmInsn[174] = -45;
        vmInsn[175] = 0;
        vmInsn[176] = 1;
        vmInsn[177] = 10;
        vmInsn[178] = 2;
        vmInsn[179] = 5;
        vmInsn[180] = 6;
        vmInsn[181] = -55;
        vmInsn[182] = 0;
        vmInsn[183] = 1;
        vmInsn[184] = 10;
        vmInsn[185] = 2;
        vmInsn[186] = 5;
        vmInsn[187] = 6;
        vmInsn[188] = -47;
        vmInsn[189] = 0;
        vmInsn[190] = 1;
        vmInsn[191] = 10;
        vmInsn[192] = 2;
        vmInsn[193] = 5;
        vmInsn[194] = 6;
        vmInsn[195] = 24;
        vmInsn[196] = 0;
        vmInsn[197] = 1;
        vmInsn[198] = 10;
        vmInsn[199] = 2;
        vmInsn[200] = 5;
        vmInsn[201] = 6;
        vmInsn[202] = -41;
        vmInsn[203] = 0;
        vmInsn[204] = 1;
        vmInsn[205] = 10;
        vmInsn[206] = 2;
        vmInsn[207] = 5;
        vmInsn[208] = 6;
        vmInsn[209] = -60;
        vmInsn[210] = 0;
        vmInsn[211] = 1;
        vmInsn[212] = 10;
        vmInsn[213] = 2;
        vmInsn[214] = 5;
        vmInsn[215] = 6;
        vmInsn[216] = 22;
        vmInsn[217] = 0;
        vmInsn[218] = 1;
        vmInsn[219] = 10;
        vmInsn[220] = 2;
        vmInsn[221] = 5;
        vmInsn[222] = 6;
        vmInsn[223] = -40;
        vmInsn[224] = 0;
        vmInsn[225] = 1;
        vmInsn[226] = 10;
        vmInsn[227] = 2;
        vmInsn[228] = 5;
        vmInsn[229] = 6;
        vmInsn[230] = -60;
        vmInsn[231] = 0;
        vmInsn[232] = 2;
        vmInsn[233] = 14;
        vmInsn[234] = 2;
        vmInsn[235] = 10;
        vmInsn[236] = 6;
        vmInsn[237] = -15;
        vmInsn[238] = 0;
        vmInsn[239] = 2;
        vmInsn[240] = 14;
        vmInsn[241] = 2;
        vmInsn[242] = 10;
        vmInsn[243] = 6;
        vmInsn[244] = 50;
        vmInsn[245] = 0;
        vmInsn[246] = 2;
        vmInsn[247] = 14;
        vmInsn[248] = 2;
        vmInsn[249] = 10;
        vmInsn[250] = 6;
        vmInsn[251] = -51;
        vmInsn[252] = 0;
        vmInsn[253] = 2;
        vmInsn[254] = 14;
        vmInsn[255] = 2;
        vmInsn[256] = 10;
        vmInsn[257] = 6;
        vmInsn[258] = -31;
        vmInsn[259] = 0;
        vmInsn[260] = 2;
        vmInsn[261] = 14;
        vmInsn[262] = 2;
        vmInsn[263] = 10;
        vmInsn[264] = 6;
        vmInsn[265] = 50;
        vmInsn[266] = 0;
        vmInsn[267] = 2;
        vmInsn[268] = 14;
        vmInsn[269] = 2;
        vmInsn[270] = 10;
        vmInsn[271] = 6;
        vmInsn[272] = 50;
        vmInsn[273] = 0;
        vmInsn[274] = 2;
        vmInsn[275] = 14;
        vmInsn[276] = 2;
        vmInsn[277] = 10;
        vmInsn[278] = 6;
        vmInsn[279] = -35;
        vmInsn[280] = 0;
        vmInsn[281] = 2;
        vmInsn[282] = 14;
        vmInsn[283] = 2;
        vmInsn[284] = 10;
        vmInsn[285] = 6;
        vmInsn[286] = 50;
        vmInsn[287] = 0;
        vmInsn[288] = 2;
        vmInsn[289] = 14;
        vmInsn[290] = 2;
        vmInsn[291] = 10;
        vmInsn[292] = 6;
        vmInsn[293] = -35;
        vmInsn[294] = 0;
        vmInsn[295] = 2;
        vmInsn[296] = 14;
        vmInsn[297] = 2;
        vmInsn[298] = 10;
        vmInsn[299] = 6;
        vmInsn[300] = 51;
        vmInsn[301] = 0;
        vmInsn[302] = 2;
        vmInsn[303] = 14;
        vmInsn[304] = 2;
        vmInsn[305] = 10;
        vmInsn[306] = 6;
        vmInsn[307] = -17;
        vmInsn[308] = 114514;
        vmInsn[309] = 1919810;
        Exception[] exceptions2 = {new BuDaoLePaoException(), new DxIsNanTongException(), new GenshinImpactException(), new LuoIsNotDogException(), new NotSigninException(), new NullCafeException(), new StarrySkyMeowNotFoundException(), new TokioEatWhatException(), new RuntimeException()};
        int i = 0;
        int store = 0;
        while (i < vmInsn.length) {
            int insn = vmInsn[i];
            i++;
            if (insn == 114514) {
                break;
            }
            try {
                throw exceptions2[insn];
                break;
            } catch (BuDaoLePaoException e) {
                store = array.get(0).byteValue();
                array.remove(0);
            } catch (DxIsNanTongException e2) {
                store ^= vmInsn[i];
                i++;
            } catch (GenshinImpactException e3) {
                store += vmInsn[i];
                i++;
            } catch (LuoIsNotDogException e4) {
                store &= vmInsn[i];
                i++;
            } catch (NotSigninException e5) {
                store <<= vmInsn[i];
                i++;
            } catch (NullCafeException e6) {
                store |= vmInsn[i];
                i++;
            } catch (StarrySkyMeowNotFoundException e7) {
                i++;
                if (store != vmInsn[i]) {
                    vmInsn[i] = 7;
                }
            } catch (TokioEatWhatException e8) {
                vmInsn[i] = 8;
            } catch (Exception e9) {
                System.out.println("wrong flag, oh no...");
                throw new RuntimeException(e9);
            }
        }
        System.out.println("输入的flag正确!");
    }
}

这里使用了try-catch抛出异常来实现switch分支选择结构,原理是throw出expections2数组中的函数,catch捕捉到对应编号的函数异常,编号即为该分支的case条件。这个虚拟机的opcode与其对应的handler可以明显地看出。每当opcode为0,取出flag的一个字符,opcode为1~5,对字符进行加密运算,opcode为6,进行一次check,若check不通过则说wrong flag。因此对每一次opcode6的结果一步步向上解密,直到遇到opcode0,则输出该字符,就能得到flag。

exp:

#include<bits/stdc++.h>
using namespace std;
int vmInsn[310];
int decode1(int x)
{
	return (x-32)^202;
}
int cracker_and(int chip,int x)
{
	for(int i=-255;i<=255;i++)
	   if(i&x==chip)return i;
}
int cracker_or(int chip,int x)
{
	for(int i=-255;i<=255;i++)
	   if(i|x==chip)return i;
}

int main()
{
	
        //vmInsn[...]=...
        int cnt=0;
		for(int i=0;;i++)
		{
			if(vmInsn[i]==114514)break;
			if(vmInsn[i]!=6)continue;
			int p=i,chip=vmInsn[p+1];
			while(1)
			{
				if(vmInsn[p-1]==0)break;
				p-=2;
			    int opnum=vmInsn[p+1];
			    switch(vmInsn[p])
			    {
			    	case 1:chip^=opnum;
			    	break;
			    	case 2:chip-=opnum;
			    	break;
			    	case 3:chip=cracker_and(chip,opnum);
			    	break;
			    	case 4:chip>>=opnum;
			    	break;
			    	case 5:chip=cracker_or(chip,opnum);
			    	break;
				}
			}
		printf("%c",decode1(chip));
			
		}
		return 0;
		//cout<<cnt;
 }
//moectf{jvav_eXcEpt10n_h4ndl3r_1s_s0_c00o0o1}


posted @   brs7  阅读(9)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示