<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    BPF之路二(e)BPF匯編

    VSole2021-12-28 16:18:32

    原始的BPF匯編

    https://www.kernel.org/doc/html/latest/networking/filter.html#networking-filter

    原始的BPF又稱之為class BPF(cBPF), BPF與eBPF類似于i386與amd64的關系, 最初的BPF只能用于套接字的過濾,內核源碼樹中tools/bpf/bpf_asm可以用于編寫這種原始的BPF程序,

    cBPF架構的基本元素如下

    元素描述A32bit寬的累加器X32bit寬的X寄存器M[]16*32位寬的雜項寄存器寄存器, 又稱為臨時寄存器, 可尋找范圍:0~15

    類似于一個int32_t M[16];的小內存

    cBPF匯編的一條指令為64字節, 在頭文件中有定義 . 如下. 這種結構被組裝為一個 4 元組數組,其中包含code、jt、jf 和 k 值. jt 和 jf 是用于提供代碼的跳轉偏移量, k為通用值

    struct sock_filter {    /* Filter block */        __u16   code;   /* 16位寬的操作碼 */        __u8    jt;     /* 如果條件為真時的8位寬的跳轉偏移  */        __u8    jf;     /* 如果條件為假時的8位寬的跳轉偏移 */        __u32   k;      /* 雜項參數 */};
    

    對于套接字過濾,把struct sock_filter數組的指針通過setsockopt(2) 傳遞給內核。例子:

    #include #include #include #include /* ... */
    /* From the example above: tcpdump -i em1 port 22 -dd */struct sock_filter code[] = {        { 0x28,  0,  0, 0x0000000c },        { 0x15,  0,  8, 0x000086dd },        { 0x30,  0,  0, 0x00000014 },        { 0x15,  2,  0, 0x00000084 },        { 0x15,  1,  0, 0x00000006 },        { 0x15,  0, 17, 0x00000011 },        { 0x28,  0,  0, 0x00000036 },        { 0x15, 14,  0, 0x00000016 },        { 0x28,  0,  0, 0x00000038 },        { 0x15, 12, 13, 0x00000016 },        { 0x15,  0, 12, 0x00000800 },        { 0x30,  0,  0, 0x00000017 },        { 0x15,  2,  0, 0x00000084 },        { 0x15,  1,  0, 0x00000006 },        { 0x15,  0,  8, 0x00000011 },        { 0x28,  0,  0, 0x00000014 },        { 0x45,  6,  0, 0x00001fff },        { 0xb1,  0,  0, 0x0000000e },        { 0x48,  0,  0, 0x0000000e },        { 0x15,  2,  0, 0x00000016 },        { 0x48,  0,  0, 0x00000010 },        { 0x15,  0,  1, 0x00000016 },        { 0x06,  0,  0, 0x0000ffff },        { 0x06,  0,  0, 0x00000000 },};
    struct sock_fprog bpf = {        .len = ARRAY_SIZE(code),        .filter = code,};
    sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));    //建立套接字if (sock < 0)        /* ... bail out ... */
    ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); //把bpf程序附加到套接字上if (ret < 0)        /* ... bail out ... */
    /* ... */close(sock);
    

    由于性能有限, 因此后面cBPF由發展成為eBPF, 有新的指令和架構. 原始的BPF指令會被自動翻譯為新的eBPF指令

    eBPF虛擬機

    eBPF虛擬機是一個RISC指令, 帶有寄存器的虛擬機, 內部有11個64位寄存器, 一個程序計數器(PC), 以及一個512字節的固定大小的棧. 9個通用寄存器可以讀寫, 一個是只能讀的棧指針寄存器(SP), 以及一個隱含的程序計數器, 我們只能根據PC進行固定偏移的跳轉. 虛擬機寄存器總是64位的(就算是32位物理機也是這樣的), 并且支持32位子寄存器尋址(寄存器高32位自動設置為0)

    • r0: 保存函數調用和當前程序退出的返回值
    • r1~r5: 作為函數調用參數, 當程序開始運行時, r1包含一個指向context參數的指針
    • r6~r9: 在內核函數調用之間得到保留
    • r10: 只讀的指向512字節棧的棧指針

    加載BPF程序時提供的的程序類型(prog_type)決定了內核里面哪些函數子集可以調用, 也決定了程序啟動時通過r1提供的context參數. r0中保存的返回值含義也由程序類型決定.

    對于eBPF到eBPF, eBPF到內核, 每個函數調用最多5個參數, 保存在寄存器r1~r5中. 并且傳遞參數時, 寄存器r1~r5只能保存常數或者指向堆棧的指針, 不能是任意內存的指針. 所有的內存訪問必須先把數據加載到eBPF堆棧中, 然后才能使用. 這樣的限制簡化內存模型, 幫助eBPF驗證器進行正確性檢查

    BPF可以訪問內核核心提供(除去模塊擴展的部分)的內核助手函數, 類似于系統調用, 這些助手函數在內核中通過BPF_CALL_*宏進行定義. bpf.h文件提供了所有BPF能訪問的內核助手函數的聲明.

    以bpf_trace_printk為例子, 這個函數在內核中通過BPF_CALL_5進行定義, 并且有5對類型與參數名, 定義參數的類型對于eBPF很重要, 因為每一個eBPF程序加載時eBPF驗證器都要確保寄存器數據類型與被調用函數的參數類型匹配.

    BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, u64, arg2, u64, arg3){    ...}
    

    這樣設計是為了讓虛擬機指令與原生的指令集(x86 arm)盡可能匹配, 這樣JIT編譯出的指令可以更簡單高效, 所有寄存器都一對一地映射到硬件寄存器。例如,x86_64 JIT 編譯器可以將它們映射為

    R0 - raxR1 - rdiR2 - rsiR3 - rdxR4 - rcxR5 - r8R6 - rbxR7 - r13R8 - r14R9 - r15R10 - rbp
    

    eBPF指令編碼

    每個eBPF指令都是固定的8字節, 大概有100條指令, 被劃分為8個類型. 虛擬機支持從通用內存(映射, 棧, contexts比如數據包, ..)中進行1-8字節的讀寫, 支持前后有無條件的跳轉, 支持數據與邏輯操作(ALU指令), 支持函數調用.

    一個eBPF程序就是64位指令的序列, 所有的eBPF指令都有同樣的基礎格式:

    • 8bit操作碼
    • 4bit目標寄存器
    • 4bit源寄存器
    • 16bit偏移
    • 32bit立即數
    msb最高bit                                                    lsb最低bit+------------------------+----------------+----+----+--------+|immediate               |offset          |src |dst |opcode  |+------------------------+----------------+----+----+--------+|       32               |    16          | 4  | 4  |    8   |
    

    大多數指令并不會使用全部的區域, 不使用的區域應該設置為0

    操作碼的最低3bit表示指令類別, 這個把相關的操作碼組合在一起

    LD/LDX/ST/STX操作碼有如下結構

    msb      lsb+---+--+---+|mde|sz|cls|+---+--+---+| 3 |2 | 3 |
    

    sz區域表示目標內存區域的大小, mde區域是內存訪問模式, uBPF只支持通用MEM訪問模式

    ALU/ALU64/JMP操作碼的結構

    msb      lsb+----+-+---+|op  |s|cls|+----+-+---+| 4  |1| 3 |
    

    如果s是0, 那么源操作數就是imm, 如果s是1, 那么源操作數就是src. op部分指明要執行哪一個ALU或者分支操作

    bpf.h中使用struct bpf_insn來描述一個eBPF指令, 其定義與上文是一致的. 因此一段eBPF程序也可以用一個struct bpf_insn數組來描述

    struct bpf_insn {    __u8    code;        /* 操作碼 opcode */    __u8    dst_reg:4;    /* 目標寄存器 dest register */    __u8    src_reg:4;    /* 源寄存器 source register */    __s16    off;        /* 有符號的偏移 signed offset */    __s32    imm;        /* 有符號的立即數 signed immediate constant */};
    

    ALU指令: 64-bit

    操作對象為64位

    操作碼助記符偽代碼0x07add dst, immdst += imm0x0fadd dst, srcdst += src0x17sub dst, immdst -= imm0x1fsub dst, srcdst -= src0x27mul dst, immdst *= imm0x2fmul dst, srcdst *= src0x37div dst, immdst /= imm0x3fdiv dst, srcdst /= src0x47or dst, immdst0x4for dst, srcdst0x57and dst, immdst &= imm0x5fand dst, srcdst &= src0x67lsh dst, immdst <<= imm0x6flsh dst, srcdst <<= src0x77rsh dst, immdst >>= imm (logical)0x7frsh dst, srcdst >>= src (logical)0x87neg dstdst = -dst0x97mod dst, immdst %= imm0x9fmod dst, srcdst %= src0xa7xor dst, immdst ^= imm0xafxor dst, srcdst ^= src0xb7mov dst, immdst = imm0xbfmov dst, srcdst = src0xc7arsh dst, immdst >>= imm (arithmetic)0xcfarsh dst, srcdst >>= src (arithmetic)

    ALU指令:32-bit

    這些操作碼只使用了他們操作數的低32位, 并且用0初始化目標寄存器的高32位(操作對象是32位)

    操作碼助記符偽代碼0x04add32 dst, immdst += imm0x0cadd32 dst, srcdst += src0x14sub32 dst, immdst -= imm0x1csub32 dst, srcdst -= src0x24mul32 dst, immdst *= imm0x2cmul32 dst, srcdst *= src0x34div32 dst, immdst /= imm0x3cdiv32 dst, srcdst /= src0x44or32 dst, immdst0x4cor32 dst, srcdst0x54and32 dst, immdst &= imm0x5cand32 dst, srcdst &= src0x64lsh32 dst, immdst <<= imm0x6clsh32 dst, srcdst <<= src0x74rsh32 dst, immdst >>= imm (logical)0x7crsh32 dst, srcdst >>= src (logical)0x84neg32 dstdst = -dst0x94mod32 dst, immdst %= imm0x9cmod32 dst, srcdst %= src0xa4xor32 dst, immdst ^= imm0xacxor32 dst, srcdst ^= src0xb4mov32 dst, immdst = imm0xbcmov32 dst, srcdst = src0xc4arsh32 dst, immdst >>= imm (arithmetic)0xccarsh32 dst, srcdst >>= src (arithmetic)

    字節交換指令

    操作碼助記符偽代碼0xd4 (imm == 16)le16 dstdst = htole16(dst)0xd4 (imm == 32)le32 dstdst = htole32(dst)0xd4 (imm == 64)le64 dstdst = htole64(dst)0xdc (imm == 16)be16 dstdst = htobe16(dst)0xdc (imm == 32)be32 dstdst = htobe32(dst)0xdc (imm == 64)be64 dstdst = htobe64(dst)

    內存指令

    操作碼助記符偽代碼0x18lddw dst, immdst = imm0x20ldabsw src, dst, immSee kernel documentation0x28ldabsh src, dst, imm…0x30ldabsb src, dst, imm…0x38ldabsdw src, dst, imm…0x40ldindw src, dst, imm…0x48ldindh src, dst, imm…0x50ldindb src, dst, imm…0x58ldinddw src, dst, imm…0x61ldxw dst, [src+off]dst = (uint32_t ) (src + off)0x69ldxh dst, [src+off]dst = (uint16_t ) (src + off)0x71ldxb dst, [src+off]dst = (uint8_t ) (src + off)0x79ldxdw dst, [src+off]dst = (uint64_t ) (src + off)0x62stw [dst+off], imm(uint32_t ) (dst + off) = imm0x6asth [dst+off], imm(uint16_t ) (dst + off) = imm0x72stb [dst+off], imm(uint8_t ) (dst + off) = imm0x7astdw [dst+off], imm(uint64_t ) (dst + off) = imm0x63stxw [dst+off], src(uint32_t ) (dst + off) = src0x6bstxh [dst+off], src(uint16_t ) (dst + off) = src0x73stxb [dst+off], src(uint8_t ) (dst + off) = src0x7bstxdw [dst+off], src(uint64_t ) (dst + off) = src

    分支指令

    操作碼助記符偽代碼0x05ja +offPC += off0x15jeq dst, imm, +offPC += off if dst == imm0x1djeq dst, src, +offPC += off if dst == src0x25jgt dst, imm, +offPC += off if dst > imm0x2djgt dst, src, +offPC += off if dst > src0x35jge dst, imm, +offPC += off if dst >= imm0x3djge dst, src, +offPC += off if dst >= src0xa5jlt dst, imm, +offPC += off if dst < imm0xadjlt dst, src, +offPC += off if dst < src0xb5jle dst, imm, +offPC += off if dst <= imm0xbdjle dst, src, +offPC += off if dst <= src0x45jset dst, imm, +offPC += off if dst & imm0x4djset dst, src, +offPC += off if dst & src0x55jne dst, imm, +offPC += off if dst != imm0x5djne dst, src, +offPC += off if dst != src0x65jsgt dst, imm, +offPC += off if dst > imm (signed)0x6djsgt dst, src, +offPC += off if dst > src (signed)0x75jsge dst, imm, +offPC += off if dst >= imm (signed)0x7djsge dst, src, +offPC += off if dst >= src (signed)0xc5jslt dst, imm, +offPC += off if dst < imm (signed)0xcdjslt dst, src, +offPC += off if dst < src (signed)0xd5jsle dst, imm, +offPC += off if dst <= imm (signed)0xddjsle dst, src, +offPC += off if dst <= src (signed)0x85call immFunction call0x95exitreturn r0

    https://github.com/iovisor/bpf-docs/blob/master/eBPF.md

    匯編編寫eBPF程序

    根據上表我們可以直接寫eBPF字節碼

    struct bpf_insn bpf_prog[] = {    { 0xb7, 0, 0, 0, 0x123 },   // mov r0, 0x123    { 0xb7, 1, 0, 0, 0x456 },   // mov r1, 0x456    { 0x0F, 0, 1, 0, 0 },       // add r0, r1    { 0x95, 0, 0, 0, 0x0 },     // exit };
    

    利用上一章說過的方法加載BPF程序, 驗證器輸出的日志如下, 表示已經接受了此程序

    用字節碼很不直觀, 我們可以通過對初始化struct bpf_insn進行一個包裹, 以方便編寫, 不明白的話可以對照上面的指令編碼

    首先進行指令類型sc的定義, 表示指令屬于那個大類

    #define BPF_CLASS(code) ((code) & 0x07) //指令種類為指令操作碼的低3bit#define BPF_ALU64    0x07    /* 操作64位對象的ALU指令種類 */#define    BPF_JMP        0x05  //跳轉指令類別
    

    接著進行操作碼op部分的定義, 這部分表示具體是哪個操作碼, 也就是指令要干什么

    #define BPF_OP(code)    ((code) & 0xf0)  //操作數為操作碼的高4bit#define BPF_MOV        0xb0    /* 把寄存器移動到寄存器 */#define    BPF_ADD        0x00     //加法操作#define BPF_EXIT    0x90    /* 從函數中返回 */
    

    對于ALU與JMP指令的操作碼, 還有1bit的s需要定義, 表示操作的來源

    #define BPF_SRC(code)   ((code) & 0x08)    //只占用第4bit一個bit#define        BPF_K        0x00    //源操作數是立即數, 立即數的值在imm中表示#define        BPF_X        0x08    //源操作數是寄存器,具體是哪一個寄存器在src字段表示
    

    下一步對于寄存器進行定義, 就是用枚舉類型對r0~r10從0~10進行編

    enum {    BPF_REG_0 = 0,    BPF_REG_1,    BPF_REG_2,    BPF_REG_3,    BPF_REG_4,    BPF_REG_5,    BPF_REG_6,    BPF_REG_7,    BPF_REG_8,    BPF_REG_9,    BPF_REG_10,    __MAX_BPF_REG,};
    

    基本元素都有了之后就可組合為表示指令的宏

    /*    給寄存器賦值, mov DST, IMM    操作碼: BPF_ALU64 | BPF_MOV表示要進行賦值操作, BPF_K表示要源是立即數IMM*/#define BPF_MOV64_IMM(DST, IMM)                    \    ((struct bpf_insn) {                    \        .code  = BPF_ALU64 | BPF_MOV | BPF_K,        \        .dst_reg = DST,                    \        .src_reg = 0,                    \        .off   = 0,                    \        .imm   = IMM })
    
    /*    兩個寄存器之間的ALU運算指令: OP DST, SRC;     OP可以是加減乘除..., DST SRC表示是那個寄存器    操作碼: BPF_ALU64|BPF_OP(OP)表示執行什么ALU64操作, BPF_X表示源操作數是寄存器*/#define BPF_ALU64_REG(OP, DST, SRC)                \    ((struct bpf_insn) {                    \        .code  = BPF_ALU64 | BPF_OP(OP) | BPF_X,    \        .dst_reg = DST,                    \        .src_reg = SRC,                    \        .off   = 0,                    \        .imm   = 0 })
    /*    退出指令: exit    操作碼: BPF_JMP|BPF_EXIT表示要進行跳轉指令類比中的退出指令*/#define BPF_EXIT_INSN()                        \    ((struct bpf_insn) {                    \        .code  = BPF_JMP | BPF_EXIT,            \        .dst_reg = 0,                    \        .src_reg = 0,                    \        .off   = 0,                    \        .imm   = 0 })
    

    借用以上宏定義, 我們可以不用令人困惑的常數重新編寫這個eBPF程序, 效果與之前一樣

     struct bpf_insn bpf_prog[] = {        BPF_MOV64_IMM(BPF_REG_0, 0x123),                 //{ 0xb7, 0, 0, 0, 0x123 },  mov r0, 0x123        BPF_MOV64_IMM(BPF_REG_1, 0x456),                 //{ 0xb7, 1, 0, 0, 0x456 },  mov r1, 0x456        BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),    //{ 0x0F, 0, 1, 0, 0 }, add r0, r1        BPF_EXIT_INSN()                                  //{ 0x95, 0, 0, 0, 0x0 } exit     };
    

    實際上, 在#include 中含有指令操作碼等常數的定義, 在內核的源碼目錄samples/bpf/bpf_insn.h就含有上述指令的宏定義, 而且更全面, 我們只要把此文件與源碼放在同一目錄, 然后#include "./bpf_insn.h"就可以直接使用這些宏來定義eBPF指令的字節碼

    C編寫eBPF指令

    還是一樣的程序, 我們換成C寫, 由于gcc不支持編譯BPF程序, 因此要用clang或者llvm來編譯, -target bpf表示編譯為eBPF字節碼, -c表示編譯為目標文件即可, 因為eBPF是沒有入口點的, 沒法編譯為可執行文件. 轉換過程: C---llvm--->eBPF---JIT--->本機指令

    //clang -target bpf -c ./prog.c -o ./prog.ounsigned long prog(void){    unsigned long a=0x123;    unsigned long b=0x456;    return a+b;}
    

    編譯出來的目標文件是ELF格式, 通過readelf可以看到最終編譯出的字節碼

    objdump不支持反匯編eBPF, 可以使用llvm-objdump對字節碼進行反編譯, r10是棧指針, *(u32 *)(r10-4) = r1是在向棧中寫入局部變量, 整體結構與之前用匯編寫的類似

    如果想要執行eBPF字節碼的話需要先從ELF格式的目標文件中提取.text段, 利用llvm-objcopy可以做到

    如何從elf中提取指定段https://stackoverflow.com/questions/3925075/how-to-extract-only-the-raw-contents-of-an-elf-section

    之后編寫一個加載器負責從prog.text中讀入字節碼, 放入緩沖區中, 然后使用BPF_PROG_LOAD命令進行bpf系統調用, 從而把字節碼注入內核, 加載器代碼如下, 整體與之前類似. 不明白的可以看前一篇文章

    //gcc ./loader.c -o loader#include #include   //為了exit()函數#include     //為了uint64_t等標準類型的定義#include     //為了錯誤處理#include     //位于/usr/include/linux/bpf.h, 包含BPF系統調用的一些常量, 以及一些結構體的定義#include     //為了syscall()
    //類型轉換, 減少warning, 也可以不要#define ptr_to_u64(x) ((uint64_t)x)
    //對于系統調用的包裝, __NR_bpf就是bpf對應的系統調用號, 一切BPF相關操作都通過這個系統調用與內核交互int bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size){    return syscall(__NR_bpf, cmd, attr, size);}
    //用于保存BPF驗證器的輸出日志#define LOG_BUF_SIZE 0x1000char bpf_log_buf[LOG_BUF_SIZE];
    //通過系統調用, 向內核加載一段BPF指令int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn* insns, int insn_cnt, const char* license){    union bpf_attr attr = {        .prog_type = type,        //程序類型        .insns = ptr_to_u64(insns),    //指向指令數組的指針        .insn_cnt = insn_cnt,    //有多少條指令        .license = ptr_to_u64(license),    //指向整數字符串的指針        .log_buf = ptr_to_u64(bpf_log_buf),    //log輸出緩沖區        .log_size = LOG_BUF_SIZE,    //log緩沖區大小        .log_level = 2,    //log等級    };
        return bpf(BPF_PROG_LOAD, &attr, sizeof(attr));}
    //BPF程序就是一個bpf_insn數組, 一個struct bpf_insn代表一條bpf指令struct bpf_insn bpf_prog[0x100];
    int main(int argc, char **argv){    //用法 loader <保存字節碼的文件> <字節碼長度, 字節為單位>
        //讀入文件中的內容到bpf_prog數組中    int text_len = atoi(argv[2]);    int file = open(argv[1], O_RDONLY);    if(read(file, (void *)bpf_prog, text_len)<0){          perror("read prog fail");        exit(-1);    }    close(file);
        //加載執行    int prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, bpf_prog, text_len/sizeof(bpf_prog[0]), "GPL");    if(prog_fd<0){        perror("BPF load prog");        exit(-1);    }    printf("prog_fd: %d", prog_fd);    printf("%s", bpf_log_buf);    //輸出程序日志}
    

    clang編譯出9條指令, 一個72字節, 使用命令./loader ./prog.text 72執行的結果如下

    字節碼通用寄存器
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    VMPWN的入門系列-1
    2023-07-27 09:45:00
    今天的文章有點長,圖片比較多,請耐心閱讀5.1 實驗一 VMPWN15.1.1 題目簡介這是一道基礎的VM相關題目,VMPWN的入門級別題目。
    匯編語言是一種用于電子計算機、微處理器、微控制器或其他可編程器件的低級語言,亦稱為符號語言。Smali匯編基礎Smali語言最早是由JesusFreke發布在Google Code上的一個開源項目,并不是擁有官方標準的語言。因此也將Smali語言稱作Android虛擬機的反匯編語言。基本類型Smali基本數據類型中包含兩種類型,原始類型和引用類型。而在Smali中則是以LpackageName/objectName的形式表示對象類型。
    假如想在x86平臺運行arm程序,稱arm為source ISA, 而x86為target ISA, 在虛擬化的角度來說arm就是Guest, x86為Host。這種問題被稱為Code-Discovery Problem。每個體系結構對應的helper函數在target/xxx/helper.h頭文件中定義。
    BPF之路二(e)BPF匯編
    2021-12-28 16:18:32
    原始的BPF又稱之為class BPF(cBPF), BPF與eBPF類似于i386與amd64的關系
    VMPWN的入門系列-2
    2023-08-03 09:29:42
    解釋器是一種計算機程序,用于解釋和執行源代碼。與編譯器不同,解釋器不會將源代碼轉換為機器語言,而是直接執行源代碼。即,這個程序接收一定的解釋器語言,然后按照一定的規則對其進行解析,完成相應的功能,從本質上來看依然是一個虛擬機。總的來說,如果輸入字符數小于0x10,string類的大概成員應該如下struct?
    交互式反匯編器,簡稱為IDA。是目前最棒的一個靜態反編譯軟件,為眾多0day世界的成員和ShellCode安全分析人士不可缺少的利器!此章節讓我們熟悉通過IDA修改參數、函數、返回值,同時詳細解讀標志位的概念,熟悉堆棧及詳細解讀ARM三級流水線概念和ARM編碼編譯為二進制的全過程。
    mruby是一個Ruby語言的輕量級實現,mruby工作方式類似CPython,它可以將Ruby源碼編譯為字節,再在虛擬機中解釋運行。
    Adhrit是一款針對Android移動端操作系統的安全分析工具,該工具可以幫助廣大研究人員根據Ghera基準,深入執行滲透測試偵查階段的任務并進行靜態字節分析。Adhrit是一個開源的Android APK逆向工程和分析工具,旨在為移動安全測試的自動化實現提供有效的解決方案。Adhrit的構建注重靈活性和模塊化,并使用了Ghera基準來識別Android應用程序中的漏洞模式。
    內存生成器 -- msmap?
    2023-01-15 10:24:23
    0x01 工具介紹Msmap是一個內存生成器,兼容多種容器、組件、編碼器、WebShell / Proxy / Killer?本文中涉及到的所有操作均得到了客戶單位的授權,并且在漏洞修復后得以公開。請勿在未授權狀態下進行任何形式的滲透測試!!!!WsFilter暫不支持自動編譯。如果使用了加密編碼器,密碼需要與路徑相同。python generator.py Java Tomcat Valve RAW AntSword passwd. python generator.py Java Tomcat Listener AES128 AntSword passwd. python generator.py Java Tomcat Servlet RC4 AntSword passwd. python generator.py Java Tomcat WsFilter AES128 JSPJS passwd. python generator.py Java Tomcat Valve AES128 Behinder rebeyond. python generator.py Java Tomcat Valve AES128 Godzilla superidol
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类