安静的小酒吧 发表于 2016-4-12 17:13

一个感染U盘木马分析

本帖最后由 安静的小酒吧 于 2016-4-12 18:28 编辑

一个感染U盘木马分析——IDAPython 让生活更美好样本名称:jusched.exe样本类型:Win32;木马;感染U盘样本大小:210KbMD5:F24F0FBDB38CF52E18EC9C899990B53ESHA-1:1C0CC3C1255E295958D310C269267D66169BAF36
0x00 前言前两天在一台内网机器上插U盘,发现U盘多出了很多用U盘里面的文件夹名称命名的exe文件,很显然是被感染了,然后就着手分析,发现样本并不复杂,但是所有的API函数地址都是动态获取然后保存在全局变量,同时所有的字符串都是加密的,这让我想起来了在Freebuf看到的一篇文章《IDAPython:让你的生活更美好》,使用IDAPython脚本批量解密并重命名函数名称,会让工作简单很多。0x01 加密算法分析(1)样本中共有两种字符串加密方式,一种是针对API函数名称和动态链接库名称的,这种是一个字符串内部字符顺序调整的加密算法,我也不知道该归为哪一类。
加密字符串和动态获取API地址IDA F5后的代码如下 int __cdecl sub_401180(int a1, char *a2, char a3){
char v4; // @1
int j; // @9
int k; // @1
int v7; // @9
int i; // @1

memset(&v4, 0xCCu, 0x50u);
k = strlen(a2);
for ( i = 0; i < k + 1 && a2 && a2 != 10 && a2 != 13; ++i )
    ;
if ( a3 == 1 )
{
    v7 = 0;
    for ( j = 3; j >= 0; --j )
    {
      for ( k = j; k < i; k += 4 )
      *(_BYTE *)(v7++ + a1) = a2;
    }
    *(_BYTE *)(v7 + a1) = 0;
}
else
{
    v7 = 0;
    for ( j = 3; j >= 0; --j )
    {
      for ( k = j; k < i; k += 4 )
      *(_BYTE *)(k + a1) = a2;
    }
    *(_BYTE *)(v7 + a1) = 0;
}
return sub_401046();
}
Python改写后如下(代码略丑,勿喷):def decstr(decs,flag):
    k=len(decs)
    slen=k
    tmp=0
    plain=
    if flag==1:
      j=3
      while j>=0:
            k=j
            while k<slen:
                plain=decs
                tmp+=1
                k+=4
            j-=1
    else:
      j=3
      while j>=0:
            k=j
            while k<slen:
                plain=decs
                tmp+=1
                k+=4
            j-=1
    return ''.join(plain)
看一下这个代码调用关系:.text:0040227E               push    0       ;区分加密还是解密,0加密,1解密
.text:00402280               push    offset aMlnatuaeedhlgo ; "MlnAtuaeedHlGoed"
.text:00402285               lea   eax,
.text:00402288               push    eax             ; int
.text:00402289               call    sub_401041;解密函数
.text:0040228E               add   esp, 0Ch
.text:00402291               mov   esi, esp
.text:00402293               lea   ecx,
.text:00402296               push    ecx             ; _DWORD
.text:00402297               mov   edx, dword_42CC90
.text:0040229D               push    edx             ; _DWORD
.text:0040229E               call    dword_43A17C;GetProcAddress()
.text:004022A4               cmp   esi, esp
.text:004022A6               call    __chkesp
.text:004022AB               mov   dword_43A188, eax;将获取到的函数地址保存
多以IDAPython的脚本就分一下几个部分:1.      通过交叉引用关系找到所有对sub_401041函数的调用2.      找出sub_401041函数的待解密字符串这个参数对应的字符串并解密3.      添加注释(方便代码阅读)4.      重命名通过上面字符串获得的API函数地址保存的全局变量名称(下面很多代码都是模仿FreeBuf那篇文章写得)def find_function_arg(addr):#获取解密函数的参数
    while 1:
      addr=idc.PrevHead(addr)
      addr=idc.PrevHead(addr)
      addr=idc.PrevHead(addr)
      if GetMnem(addr)=="push":
            opv=GetOperandValue(addr, 0)
            addr=idc.PrevHead(addr)
            flag=GetOperandValue(addr,0)
            return (opv,flag)
    return ""

def get_string(addr):#通过字符串地址获得字符串
    out=""
    while 1:
      c=chr(Byte(addr))
      if c in string.printable:
            out+=c
      else:
            break
      addr+=1
    return out

def rename_func(addr,fname):#重命名
    count=0
    while 1:
      count+=1
      addr=idc.NextHead(addr)
      if GetOperandValue(addr,0)==0x0043A17C:
            while 1:
                count+=1
                addr=idc.NextHead(addr)
                if GetMnem(addr)=="mov" and GetOpnd(addr,1)=="eax":
                  addr=GetOperandValue(addr,0)
                  idc.MakeName(addr,fname)
                  break
            break
      if count==20:
            break

for x in XrefsTo(0x00401041,flags=0):
    ref=find_function_arg(x.frm)
    if ref!="":
      s=get_string(ref)
      dec=decstr(s,ref)
      print dec
      MakeComm(x.frm, dec)
      rename_func(x.frm,dec+'_r')
解密前:
解密后: 重命名前:
重命名后:
0x02 加密算法分析(2)除了前一种针对API函数名称加密的算法外,另外一种是针对其他普通字符串加密的,该加密算法是一个类似rot13的加密算法,只是这里扩展到了94个可见字符。IDA F5的算法如下:char *__cdecl sub_401580(int a1, char *a2)
{
char *result; // eax@1
char v3; // @1
int j; // @3
char *i; // @1
char *v6; // @1

memset(&v3, 0xCCu, 0x4Cu);
result = (char *)strlen(a2);
v6 = result;
for ( i = 0; (signed int)i < (signed int)v6; ++i )
{
    for ( j = 0; j < 94; ++j )
    {
      if ( a2[(_DWORD)i] == byte_4270A0 )
      {
      result = &i;
      i = byte_4270A0[(j + 47) % 94];
      break;
      }
      result = (char *)(j + 1);
    }
    if ( j == 94 )
    {
      result = &a2[(_DWORD)i];
      i = a2[(_DWORD)i];
    }
}
i = 0;
return result;
}
使用Python改写后如下:table=' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~'

def decstr(decs):
    k=len(decs)
    out=''
    for i in range(k):
      for j in range(len(table)):
            if decs==table:
                out+=table[(j+47)%94]
                break
    return out由于这些字符串是全局使用的字符串,每次都经过解密,为了方便阅读反编译代码直接在与字符串上面patch即可,分析时忽略解密函数,该过程于上面类似也需要以下几步:(1)      通过交叉引用定位解密函数的参数(2)      通过字符串参数地址获取字符串并解密(3)      Patch被加密的字符串完整代码如下:import idc
import idaapi
import string

table=' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~'

def decstr(decs):
    k=len(decs)
    out=''
    for i in range(k):
      for j in range(len(table)):
            if decs==table:
                out+=table[(j+47)%94]
                break
    return out


def find_function_arg(addr):
    while 1:
      addr=idc.PrevHead(addr)
      addr=idc.PrevHead(addr)
      addr=idc.PrevHead(addr)
      if GetMnem(addr)=="push":
            opv=GetOperandValue(addr, 0)
            addr=idc.PrevHead(addr)
            flag=GetOperandValue(addr,0)
            return (opv,flag)
    return ""

def get_string(addr):
    out=""
    while 1:
      c=chr(Byte(addr))
      if c in table:
            out+=c
      else:
            break
      addr+=1
    return out

def pathstr(addr,pstr):
    for i in pstr:
      idc.PatchByte(addr,ord(i))
      addr+=1


for x in XrefsTo(0x40104B,flags=0):
    ref=find_function_arg(x.frm)
    if ref!="":
      s=get_string(ref)
      print s,
      dec=decstr(s)
      print dec
      pathstr(ref,dec)Patch前:
Patch后:
0x03 样本结构分析经过上面的处理之后样本的反编译代码可读性非常高了,样本功能大概分为以下几部分:1.      自身环境判断2.      驻留进系统3.      回连4.      感染U盘样本不是很复杂,功能也很传统,就不一一列举每个功能了,感兴趣可以自己分析。0x04 查杀方法该样本没有很复杂的隐藏手段查杀的话下面两步就可以:1.      在任务管理器里面结束jusched.exe这个进程2.      在C:\Program Files (x86)\目录里面搜索jusched.exe,它是被保存在一个用随机的16进制数命名的目录里,删除就好了。0x05 小结1.      只是为了尽快清除木马,所以没有做太细致的分析,不正确之处还请指正2.      IDAPython可以让生活更美好 样本文件、idb文件、Python脚本(解压密码:52pojie):FreeBuf关于IDAPython:http://www.freebuf.com/sectool/92107.html

安静的小酒吧 发表于 2016-4-18 22:50

lpplite 发表于 2016-4-18 14:44
不错。但是最可恨的U盘病毒,是导致U盘无法使用的那种。格式化也不行,量产也没用的。那种病毒才是太气人了 ...

这种我倒是没见过,有样本的话能不能给一个我尝试看看?

lpplite 发表于 2016-4-19 08:03

安静的小酒吧 发表于 2016-4-18 22:50
这种我倒是没见过,有样本的话能不能给一个我尝试看看?

我不懂技术。。。现在有的只有一两个已经不能使用的U盘了。病毒我是抓不到的。{:1_908:}

huxiaokui 发表于 2016-4-12 17:53

留名~ 感谢分享~

chaselove 发表于 2016-4-12 18:01

学习下,支持楼主

eonegh 发表于 2016-4-12 18:30

记得以前学校机房都是这种木马,不过在它发作时我就截下它的.ini文件。好像就是一个脚本!

pqzhen9999 发表于 2016-4-12 19:19

学习学习,谢谢分享!

14219247 发表于 2016-4-12 22:25

吾爱破解论坛 www.52pojie.cn
这玩意看不懂啊

majia1317 发表于 2016-4-13 00:25

谢谢分享,过程写的很详细。

dingk 发表于 2016-4-15 10:20

IDA Python写的66哒,求带!

安静的小酒吧 发表于 2016-4-15 17:54

dingk 发表于 2016-4-15 10:20
IDA Python写的66哒,求带!

freebuf那个系列不错,还有那个IDAPythonbook

eing888 发表于 2016-4-15 18:42

有查杀这样的病毒的软件就好了,经常碰到这个病毒
页: [1] 2 3
查看完整版本: 一个感染U盘木马分析