yara
yara启动参数
-f, --fast-scan 快速扫描
-r, --recursive 递归扫描目录
-s, --print-string 打印匹配的字符串
-n, --negate 只打印不匹配的结果
-p, --thread=NUMBER 设置线程数
-D, --print-module-data 打印模块数据
几个简单的例子
Example1
rule apt_CN_BlueTraveller {
strings:
// fullword - 完整匹配字符串
// ascii - 多字节字符串
$a1 = "PROXY_PROXY_PROXY_PROXY" fullword ascii
$a2 = "0ROXY_TYPE" fullword ascii
$b1 = "cmd.exe /c hostname" fullword ascii
$b2 = "/O.htm" fullword ascii
$b3 = "%s%04d/%s" fullword ascii
$b4 = "http://%s/%s/%s/" fullword ascii
$c1 = "cmd.exe /c" fullword ascii
$c2 = "Upload failed..." fullword ascii
$c3 = "Download OK!" fullword ascii
$c4 = "-download" fullword ascii
$c5 = "-exit" fullword ascii
$c6 = "james" fullword ascii
condition:
// 文件开头是'MZ'标志 &&
uint16(0) == 0x5A4D and
// (匹配$a*中的任意个数规则 ||
// 匹配$b中的任意2个规则 ||
// 匹配$c中的任意4个规则) &&
(any of ($a*) or 2 of ($b*) or 4 of ($c*))
// 文件大小小于400000字节
and filesize < 400000
}
Example2
rule apt_DiplomaticDuck {
strings:
$http = "http://%s" ascii
$a1 = "IEXPLORE.EXE" fullword ascii
$a2 = "%s\\cmd.exe" fullword ascii
$a3 = "GetLastActivePopup"
$a4 = "SleepEx" fullword ascii
$a5 = "CryptDestroyKey" fullword ascii
$a6 = "ShellExecuteA" fullword ascii
$a7 = "PathFileExistsA" fullword ascii
condition:
uint16(0) == 0x5A4D
// 找到$http的个数为5个
and (#http == 5 and 5 of ($a*))
and filesize < 400000
}
编写规则注意点
- 当字符串比较短的时候,使用
fullword
关键字 - 尽量不要根据一些常见的导入/导出函数来指定规则
- 记住要使用
filesize
- 总是要检查文件头部信息(PE、ELF等)
- 不使用运行时期生成的字符串
尽量不要把所有可能的
strings
部分作为必要条件- 比如使用
5 of ...
来代替all of ...
- 比如使用
yara的模块
PE模块
使用import "pe"
导入pe模块
以下使用pe模块的例子:
pe.characteristics & pe.DLL
pe.exports("SpLsaModeInitialize")
pe.imports(“kernel32.dll”, “WriteProcessMemory”)
pe.machine == pe.MACHINE_AMD64
pe.timestamp == 1434793542
pe.locale(0x0419) or pe.language(0x19)
pe.version_info["CompanyName"] contains "Adobe"
pe.imphash() == "b8bb385806b89680e13fc0cf24f4431e"
pe.sections[pe.section_index(".payload")].raw_data_offset
pe.sections[4].name == ".payload"
pe.signatures[1].serial == "d9:5d:2c:aa:09:3b:f4:3a:02:9f:7e:29:16:ea:e7:fb"
Hash模块
使用import "hash"
导入hash模块
for any i in (0..pe.number_of_sections - 1):
(hash.md5(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size)
== "d41d8cd98f00b204e9800998ecf8427e")
for any i in (0..pe.number_of_resources - 1):
(hash.sha256(pe.resources[i].offset, pe.resources[i].length)
=="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Time模块
使用import "Time"
导入time模块
condition:
pe.timestamp > time.now()
pe.timestamp > time.now() - 86400 // 过去24小时内
and pe.timestamp < time.now()
Math模块
使用import "math"
导入math模块
condition:
math.in_range(math.entropy(
pe.sections[pe.section_index[".rsrc"]].raw_data_offset,
pe.sections[pe.section_index[".rsrc"]].raw_data_size,
), 6.66, 8.0)
yara编写总结
字符串
// 不加修饰的字符串
$string="mystring"
// 完全匹配字符串
$fullword="mystring" fullword
// 宽字符
$wide="mystring" wide
// ascii的宽字符
$wide_ascii="mystring" wide ascii
// 忽略大小写
$case_sensitive="MyString" nocase
// 混合使用:完全匹配、ascii、宽字符、忽略大小写
$mix="mystring" fullword ascii wide nocase
// 16进制的字符串
$hex_string={01 02 03 04 05}
// 带有通配符,?占位一个
$hex_wildcards={01 ?? ?3 04 05}
// 中间跳过2-10个字节
$hex_jump={01 [2-10] 04 05}
// 中间跳过2个及以上的字节,即[2-infinite]
$hex_infinite={01 [2-] 04 05}
// 即[0-infinite]
$hex_no_bound={01 [-] 04 05}
// 或
$hex_str_or={01 (02 03 | 03 04) 05}
$hex_str_mult_or={01 (02 | 03 | 04 ?? 05) 06}
// 正则
$regex=/regexp .* blah/
$md5_regex = /[A-Za-z0-9]{32}/
字符串匹配条件
// $a在偏移0处
($a at 0)
// $a在PE的入口点上
($a at pe.entry_point)
// $a在$b后的16偏移处,@代表位置
$a at (@b+16)
// 没有匹配到$b
not $b
// $a匹配到的个数为5,$b匹配到的个数大于7,#代表个数
(#a == 5) or (#b > 7)
// $a在0-100之间,$b在100-filesize之间
$a in (0..100) and $b in (100..filesize)
// $a在PE入口点到入口点后偏移10位置之间
$a in (pe.entry_point .. pe.entry_point + 10)
// 其中匹配到2个
2 of ($a,$b,$c)
// 它们之间匹配到2个
2 of them
// 在任意的$a*中,匹配到2个
2 of ($a*)
// 它们中的所有都匹配到
all of them
// 它们中匹配到任意个
any of them
给定位置的整型
uint8(offs) == 255
uint16(offs) == 8192
uint32(offs) == 0xcafebabe
int8(offs) == -12
int16(offs) == -12000
int32(offs) == -1200768
// 以下有be后缀的为大端表示
int16be(offs) == -44777
uint16be(offs) == 0x4D5A
uint32be(offs) == 0xD0CF11E0
文件检查
// PE格式
uint16(0) == 0x5A4D // 好的,效率高
($mz at 0) // 坏的,效率低
// ELF或者Mac
(uint32(0) == 0x464c457f) // ELF
(uint32(0) == 0xfeedfacf) or (uint32(0) == 0xcffaedfe) or (uint32(0) == 0xfeedface) or (uint32(0) == 0xcefaedfe) // Mac
// 文件大小检查
(filesize > 512) or (filesize < 5000000) or (filesize < 5MB)
pe模块
// 是dll
pe.characteristics & pe.DLL
// 拥有导出名SpLsaModeInitialize
pe.exports("SpLsaModeInitialize")
// 有导入函数kernel32中的WriteProcessMemory
pe.imports("kernel32.dll", "WriteProcessMemory")
// 是64位的PE文件
pe.machine == pe.MACHINE_AMD64
//时间戳
pe.timestamp == 1434793542
// 地区和语言
pe.locale(0x0419) or pe.language(0x19)
// 节区数量大于5
pe.number_of_sections > 5
// 索引为4的节的名字位.payload
pe.sections[4].name == ".payload"
// 公司组织名包含Adobe
pe.version_info["CompanyName"] contains "Adobe"
// .payload节的.raw_data_offset
pe.sections[pe.section_index(".payload")].raw_data_offset
// 资源数量大于5
pe.number_of_resources > 5
// 索引为1的资源名为RSRCNAME
pe.resources[1].name_string == "RSRCNAME"
让内鬼康康又发了什么