|
本帖最后由 ssjjdns 于 2021-8-27 22:46 编辑
大家好我是芒果
芒果验证好久没更新了
壳子好久没更新了,因为以前基本啥也不会,所以写的东西也没有什么技术含量
现在和某些老师学了一点东西
现在准备重新写一下这个代码虚拟化系列

好进入正题了那就!
众所周知,这个代码虚拟化呢,就是一个壳的手段。将一段汇编代码移交至壳内部的虚拟机中执行,防止逆向分析的手段。
那么我们考虑对一段汇编代码进行虚拟化
我的帖子(一)解答了进入虚拟机前和退出虚拟机时后要做什么
现在帖子(二)将展示对一段汇编指令进行虚拟处理时,必要的操作
0x1将一段汇编代码 移至虚拟机执行 存在的问题</br>【我们把一段要移植到虚拟机内部执行的指令,称之为块】
我们期望,一种完美的情况就是,要被VM的汇编指令,不存在任何跳转。这样这一段指令我们就可以舒心的让虚拟机从头执行到尾。
但是,被VM的汇编指令中存在跳转,这些跳转,有可能跳到被VM的代码块之外的。这时候我们必须要退出虚拟机,然后去执行块外代码。
但是,又有一些跳转,是跳转到被VM的代码块内部的。
1.这些跳转来自于被vm的指令块内,即块内跳到块内。
2.也有可能是来自于被VM的指令块外部,即块外部跳到块内
对于情况1我们可以让虚拟机内部逻辑处理就好了
但是对于情况2
情况有点棘手比如下面这样
[如果你不知道下面在说什么,可以去看一下我的虚拟化(一)]
原来代码:
401000 push 12345678
40100A push xxxxxxxxx
40100C push xxxx
40100D call xxxx
............
401244 jmp 40100C or call 40100C
VM后:
401000 JMP xxxxxxxx //进入虚拟机
40100A xxxxxxxx //一些死代码,本来就是随机的字节,没有意义
40100C xxxxxxxx//一些死代码,本来就是随机的字节,没有意义
40100D xxxxxxxx//一些死代码,本来就是随机的字节,没有意义
.......
401244 jmp 40100C or call 40100C
比如401244处要求jmp或call到40100C处,但是40100C已经被我们处理成了死代码。后面执行的话cpu取的指令没有任何意义,软件就会卡死,而401244处的调用又恰好不属于被VM的指令集合里
换句话就是说,是外部代码需要跳转到虚拟机内部,但原来指令位置已经被替换成死代码了。
0x2 问题解决方案:利用编译原理-基本块划分(或控制流分析)来解决
[基本块的性质或定义:一个代码块,只可能从第一条执行到最后一条,中间不会有任何跳转,而跳转只可能出现在最后一条指令上]
既然我们已经明白了问题所在,那么解决方法也呼之欲出了,我曾为这个问题困扰了一整天。
然后上b站上翻了一下国防科技大学的编译原理 里面控制流分析学了一下,然后解决了
下面给出问题解决的算法
直接看图吧,不多bb了
图片共是两张,论坛可能有时候图片加载失败不知道啥原因,多刷新试试吧
用我自己的话说:
1.欲被划分的块的第一条指令 或 能由条件转移语句(jnz je jl.....) 或无条件转移语句(jmp)转移到的语句 或 紧跟在条件转移后面的语句
这三类指令都可以作为一个基本块的入口语句
2.对于以上每个入口语句,确定其所属的基本块,它是由该入口语句到下一入口语句(不包括该入口语句),或到一转移语句(包括该转移语句)之间的语句序列组成的
比如一条jnz 那么这个jnz的目标地址,就是一个块的开始
然后jnz指令下面的指令,就是另一个块的开始
如此划分基本块,我们的程序的控制流可以用一张有向图来表示 【不明白有向图是啥的,百度一下,一两句说不清,知识来源:离散数学 图论】
然后,我们只需要在基本块的头部开始进入虚拟机,在尾部退出虚拟机即可,中间的指令会依次顺序执行,不用再考虑跳转问题
至此,问题得到完美解决!!!!!!!!!!!!!!!
[至于在基本块尾部的跳转指令如何处理,要么原始执行,要么特殊处理【代码乱序】,【代码乱序】技术我会再开帖子讲解!!!]
下面附上代码[本来是想用易语言的,因为考虑到性能问题,直接C++写]代码一共206行 下拉鼠标可以看完整的
[C++] 纯文本查看 复制代码 include<bits/stdc++.h>
#define MAX_ZL_CNT 10000007
#define MAX_VM_CNT 10007
using namespace std;
string s[MAX_ZL_CNT],b[MAX_VM_CNT],e[MAX_VM_CNT];//S存指令,b存要vm的地址开头,e存要vm的地址结尾
map<string,int>h; //h存放string下标
int cnt,vm_cnt;//指令总数 被v的指令总数
struct rec{
int isJmp;
int isBegin;
int jmpFrom;
int jmpTo;
int div_id;
};
rec g[MAX_ZL_CNT];//g存放指令的性质
string ItoS(int x){
string tmp;
while(x){
tmp=char(x%10+48)+tmp;
x/=10;
}
return tmp;
}
string bu0(string x){
int l=8-x.length();
for(int i=1;i<=l;i++){
x="0"+x;
}
return x;
}
string toD(string x){
for(int i=0;i<x.size();i++){
if(int(x[i])>=97 && int(x[i])<=122){
x[i]=char(65+int(x[i])-97);
}
}
return x;
}
int toI(string x){
int base=1;
int ret=0;
for(int i=x.size()-1;i>=0;i--){
ret+=(int(x[i])-48)*base;
base*=10;
}
return ret;
}
string GetJmpType(string x){
int l=x.find("j");
int r=0;
for(int i=l;i<x.length();i++){
if(x[i]==' '){
r=i;
break;
}
}
return x.substr(l,r-l);
}
string GetJmpAddr(string x){
int l=x.find("0x");
return x.substr(l+2,x.length()-l-2);
}
string GetZL(string x){
int ccnt=0;
int cur=0;
for(int i=1;i<x.length();i++){
if(x[i-1]==' ' && x[i]!=' ')ccnt++;
if(ccnt==2){
cur=i;
break;
}
}
return x.substr(cur,x.length()-cur);
}
string GetBinCode(string x){
int cur1=0;
int cur2=0;
for(int i=1;i<x.length();i++){
if(x[i-1]==' ' && x[i]!=' ')cur1=i;
if(x[i-1]!=' ' && x[i]==' ' && cur1!=0){
cur2=i;
break;
}
}
return x.substr(cur1,cur2-cur1);
}
void DivIt(string x,string y){
int l=h[x];
int r=h[y];
int jc=r-l+1;
int kuai_cnt=1;
int f=0;//防止块重复做的标记
//下面扫一遍统计每条指令所属块
for(int i=0;i<jc;i++){
if(g[l+i].isBegin==0 && g[l+i].isJmp==0){//既不是块开头,也不是跳转语句
g[l+i].div_id=kuai_cnt;//标记属于那个块
continue;
}
//块开头优先判断
if(g[l+i].isBegin==1){
if(f!=1){
kuai_cnt++;
}
f=0;
g[l+i].div_id=kuai_cnt;//标记属于那个块
continue;
}
//其次判断是否是跳转指令
if(g[l+i].isJmp==1){
g[l+i].div_id=kuai_cnt;//标记属于那个块
kuai_cnt++;
f=1;
continue;
}
}
int j=0;
int tmp1=g[l-1].div_id;
g[l-1].div_id=-1;
int jout_cnt=0;
int outjin_cnt=0;
string jout[MAX_VM_CNT];//由块内部跳转到块外部的指令
string outjin[MAX_VM_CNT];//由外部跳转到块内部的指令
cout<<"ProtectBegin"<<endl;
for(int i=l;i<=r;i++){
if(g[i].div_id!=g[i-1].div_id)cout<<"kuai"<<++j<<":"<<endl;
//检测是否由块外部跳转进入块
if(g[i].jmpFrom!=0){
if(g[i].jmpFrom<l || g[i].jmpFrom >r){//如果是来自块外部的跳转的话
outjin_cnt++;
outjin[outjin_cnt]="<t><"+s[i].substr(0,8)+">"+"@"+ItoS(g[i].div_id)+"@<t>";
}
}
//如果是跳转指令,检测是跳转到块内部还是块的外部
if(g[i].isJmp==1){
if(g[i].jmpTo<l || g[i].jmpTo>r){//如果跳转到块的外部
jout_cnt++;
jout[jout_cnt]="<1>"+s[i].substr(0,8)+"<2>"+GetJmpType(s[i])+"<3>"+GetJmpAddr(s[i])+"<4>"+ItoS(g[i].div_id)+"<5>"+ItoS(i)+"<6>";
cout<<GetJmpType(s[i])+"|"+GetJmpAddr(s[i])+"@"<<ItoS(jout_cnt)<<"_"<<endl;
}
else cout<<"."<<GetJmpType(s[i])<<" kuai"<<g[g[i].jmpTo].div_id<<"_"<<endl;
}
else{
cout<<"."<<GetZL(s[i])<<"<"<<GetBinCode(s[i])<<">"<<ItoS(g[i].div_id)<<"_"<<endl;
}
}
g[l-1].div_id=tmp1;
cout<<"ProtectEnd"<<endl;
//输出跳转到块外部的指令
cout<<"{";
cout<<"jout__________________"<<endl;
for(int i=1;i<=jout_cnt;i++)cout<<jout[i]<<endl;
cout<<"outjin________________"<<endl;
for(int i=1;i<=outjin_cnt;i++)cout<<outjin[i]<<endl;
cout<<"}";
cout<<endl<<"==========================================================="<<endl;
}
int main(){
// cout<<ItoS(250);
freopen("111.txt","r",stdin);
freopen("out.txt","w",stdout);
//--------------预处理所有跳转-------------------------------
int f=0;
while(getline(cin,s[++cnt])){
g[cnt].isJmp=0;
g[cnt].isBegin=0;
h.insert(make_pair(s[cnt].substr(0,8),cnt));
}
cnt--;//由于getline多读入一次才会结束的,修正 cnt值
vm_cnt=toI(s[cnt]);
for(int i=1;i<=cnt-vm_cnt-1;i++){
string a=s[i];
if(f==1){
g[i].isBegin=1;//前一句指令是跳转语句
f=0;
}
int cur=a.find("j");
if(cur!=a.npos){ //找到跳转指令的 操作数
if(a.find("0x")==a.npos)continue;//如果有jxx 寄存器这种形式的指令,直接跳过
f=1;
cur=a.find("0x");
a=a.substr(cur+2,a.length()-cur-1);
a=bu0(a);//补够8位
a=toD(a);//转大写
g[h[a]].isBegin=1;
g[i].jmpTo=h[a];
g[i].isJmp=1;
g[h[a]].jmpFrom=i;
//cout<<a<<endl;
}
}
//cout<<vm_cnt<<endl;
for(int i=1;i<=vm_cnt;i++){
b[i]=s[cnt-i].substr(0,8);
e[i]=s[cnt-i].substr(8,8);
DivIt(b[i],e[i]);
}
return 0;
}
|
评分
-
参与人数 44 | 威望 +1 |
HB +144 |
THX +24 |
收起
理由
|
吃麻花麻花疼
| |
+ 2 |
+ 1 |
[吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守! |
猫妖的故事
| |
+ 1 |
|
|
lies
| |
+ 1 |
|
|
再来壹瓶
| |
+ 1 |
|
[吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守! |
花盗睡鼠
| |
+ 2 |
+ 1 |
[吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守! |
虚心学习
| |
|
+ 1 |
[吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩! |
创客者V2.0
| |
+ 1 |
|
|
459121520
| |
|
+ 1 |
|
爱学习的老冯头
| |
+ 1 |
|
[吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意! |
冷亦飞
| |
+ 1 |
|
|
l278785481
| |
+ 1 |
|
|
小严在河南
| |
+ 1 |
+ 1 |
|
仙之初
| |
+ 1 |
+ 1 |
[吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少! |
河图
| |
+ 1 |
+ 1 |
[吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守! |
temp
| |
+ 1 |
+ 1 |
|
playboy
| |
+ 2 |
|
|
我是好人
| |
+ 1 |
|
[吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩! |
ldljlzw
| |
+ 1 |
|
|
山野屌丝
| |
|
+ 1 |
|
PDWORD
| |
|
+ 1 |
|
消逝的过去
| |
|
+ 1 |
[吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩! |
拿着雪糕
| |
+ 1 |
|
|
jsntsjg
| |
+ 1 |
|
|
wangcongha
| |
+ 1 |
|
[吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守! |
baky1223
| |
|
+ 1 |
[吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩! |
bnjzzheng
| |
+ 1 |
|
[吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩! |
大彩笔
| |
+ 1 |
+ 1 |
|
SmallEXpel
| |
+ 1 |
|
[吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩! |
ZSSR2009525
| |
|
+ 1 |
|
king51999
| |
|
+ 1 |
[快捷评语]--积极评分,从我做起。感谢分享! |
87481067
| |
+ 1 |
|
[快捷评语]--2021年,我们爱0爱1 |
mengzhisuoliu1
| |
+ 1 |
|
|
janford
| |
+ 1 |
|
|
beamstyle
| |
+ 1 |
|
|
hnymsh
| |
+ 1 |
+ 1 |
[快捷评语]--积极评分,从我做起。感谢分享! |
小G一小只
| |
+ 1 |
|
求助主题超时无人接单,强制删除,撤销主题退还H钻。 |
blood1116
| |
|
+ 1 |
|
白云点缀的蓝
| |
+ 6 |
+ 1 |
|
GDjx
| |
+ 1 |
+ 1 |
|
hysmy17
| |
+ 1 |
+ 1 |
|
洋葱、
| |
+ 2 |
+ 1 |
|
橄榄绿
| |
+ 1 |
+ 1 |
|
小小沫涵
| |
+ 2 |
+ 1 |
|
Shark恒
| + 1 |
+ 100 |
+ 1 |
赞!高质量内容! |
查看全部评分
|