Merge pull request #335 from ameihm0912/yara

Yara module
This commit is contained in:
Aaron Meihm 2017-04-12 09:58:25 -05:00 коммит произвёл GitHub
Родитель 98da472365 378dd9d8ce
Коммит de41ae30a0
31 изменённых файлов: 2274 добавлений и 14 удалений

Просмотреть файл

@ -12,7 +12,7 @@ services:
before_install:
# this is a fix to get rng-tools to work in travis-ci
- sudo apt-get update -qq
- sudo apt-get install --yes rng-tools
- sudo apt-get install --yes rng-tools autoconf automake gcc
- sudo rm -f /dev/random
- sudo mknod -m 0666 /dev/random c 1 9
- echo HRNGDEVICE=/dev/urandom | sudo tee /etc/default/rng-tools
@ -20,6 +20,14 @@ before_install:
script:
- export OLDPATH=$(pwd)
- cd
- curl -OL https://github.com/VirusTotal/yara/archive/v3.5.0.tar.gz
- tar -zxf v3.5.0.tar.gz
- cd yara-3.5.0
- ./bootstrap.sh
- ./configure --disable-shared --disable-magic --disable-cuckoo --without-crypto
- make
- sudo make install
- cd ..
- mkdir -p "$GOPATH/src/mig.ninja/"
- mv "$OLDPATH" "$GOPATH/src/mig.ninja/"
- cd "$GOPATH/src/mig.ninja/mig"
@ -33,7 +41,7 @@ script:
- diff client/mig/available_modules.go conf/available_modules.go
# enable all the modules we have for the test
- sed -i 's,//_,_,' conf/available_modules.go
- make
- make WITHYARA=yes
- docker build -t mozilla/mig .
- |
if [ ! -z "$TRAVIS_TAG" ]; then

Просмотреть файл

@ -6,7 +6,7 @@ MAINTAINER Mozilla
RUN apt-get update && \
apt-get install -y sudo golang git make \
curl rng-tools tmux postgresql rabbitmq-server \
libreadline-dev && \
libreadline-dev automake autoconf libtool && \
echo '%mig ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/mig && \
groupadd -g 10001 mig && \
useradd -g 10001 -u 10001 -d /mig -m mig

Просмотреть файл

@ -14,6 +14,19 @@ else
BINSUFFIX := ""
endif
# Set this to yes if you want yara support and want to use the yara module
#
# This assumes yara has been compiled with the following options:
# --disable-shared --disable-magic --disable-cuckoo --without-crypto
#
# If you have built yara some other way or have yara shared libraries
# installed you will need to adjust the makefile
#
# You may have to set the CPATH and LIBRARY_PATH environment variables
# if you have installed the yara headers and library somewhere the build
# tools can't locate
WITHYARA=no
# These variables control signature operations used when building various
# targets on OSX.
#
@ -21,7 +34,7 @@ endif
# sign the mig-agent and mig-loader binaries when built on OSX. If empty,
# the compiled binaries will not be signed.
#
# OSXPACKSIGID if set will result in the specified identify being used to
# OSXPACKSIGID if set will result in the specified identity being used to
# sign the mig-loader package (osx-loader-pkg). If empty the .pkg will not
# be signed.
#
@ -83,6 +96,7 @@ endif
GCC := gcc
CFLAGS :=
LDFLAGS :=
CGOLDFLAGS :=
GOOPTS :=
GO := GOOS=$(OS) GOARCH=$(ARCH) GO15VENDOREXPERIMENT=1 go
GOGETTER := GOPATH=$(shell pwd)/.tmpdeps go get -d
@ -98,6 +112,18 @@ CLIENTTARGETS := mig-cmd mig-console mig-action-generator mig-action-verifier
AGENTTARGETS := mig-agent mig-loader
ALLTARGETS := $(AGENTTARGETS) $(SERVERTARGETS) $(CLIENTTARGETS)
ifeq ($(WITHYARA),yes)
ifeq ($(OS),linux)
CGOLDFLAGS += -lyara -lm
else ifeq ($(OS),darwin)
# Nothing special required here for this to work on darwin
else
$(error WITHYARA not supported for this platform)
endif
endif
export CGO_LDFLAGS = $(CGOLDFLAGS)
all: test $(ALLTARGETS)
tag:
@ -195,6 +221,7 @@ go_vendor_dependencies:
$(GOGETTER) golang.org/x/net/ipv4
$(GOGETTER) golang.org/x/net/ipv6
$(GOGETTER) gopkg.in/gcfg.v1
$(GOGETTER) github.com/hillu/go-yara
$(GOGETTER) github.com/cheggaaa/pb
$(GOGETTER) github.com/stretchr/testify
$(GOGETTER) github.com/fsnotify/fsnotify
@ -424,7 +451,22 @@ test: test-modules
test-modules:
# test all modules
$(GO) test mig.ninja/mig/modules/...
$(GO) test mig.ninja/mig/modules/
$(GO) test mig.ninja/mig/modules/agentdestroy
$(GO) test mig.ninja/mig/modules/example
$(GO) test mig.ninja/mig/modules/examplepersist
$(GO) test mig.ninja/mig/modules/file
$(GO) test mig.ninja/mig/modules/fswatch
$(GO) test mig.ninja/mig/modules/memory
$(GO) test mig.ninja/mig/modules/netstat
$(GO) test mig.ninja/mig/modules/ping
$(GO) test mig.ninja/mig/modules/pkg
$(GO) test mig.ninja/mig/modules/scribe
$(GO) test mig.ninja/mig/modules/timedrift
ifeq ($(WITHYARA),yes)
$(GO) test mig.ninja/mig/modules/yara
endif
clean-agent:
if [ -d bin/ ]; then \

Просмотреть файл

@ -16,5 +16,6 @@ import (
_ "mig.ninja/mig/modules/pkg"
_ "mig.ninja/mig/modules/scribe"
_ "mig.ninja/mig/modules/timedrift"
//_ "mig.ninja/mig/modules/yara"
//_ "mig.ninja/mig/modules/example"
)

Просмотреть файл

@ -16,5 +16,6 @@ import (
_ "mig.ninja/mig/modules/pkg"
_ "mig.ninja/mig/modules/scribe"
_ "mig.ninja/mig/modules/timedrift"
//_ "mig.ninja/mig/modules/yara"
//_ "mig.ninja/mig/modules/example"
)

Просмотреть файл

@ -16,5 +16,6 @@ import (
_ "mig.ninja/mig/modules/pkg"
_ "mig.ninja/mig/modules/scribe"
_ "mig.ninja/mig/modules/timedrift"
//_ "mig.ninja/mig/modules/yara"
//_ "mig.ninja/mig/modules/example"
)

Просмотреть файл

@ -16,5 +16,6 @@ import (
_ "mig.ninja/mig/modules/pkg"
_ "mig.ninja/mig/modules/scribe"
_ "mig.ninja/mig/modules/timedrift"
//_ "mig.ninja/mig/modules/yara"
//_ "mig.ninja/mig/modules/example"
)

83
modules/yara/doc.rst Normal file
Просмотреть файл

@ -0,0 +1,83 @@
=================================
Mozilla InvestiGator: yara module
=================================
:Author: Aaron Meihm <ameihm@mozilla.com>
.. sectnum::
.. contents:: Table of Contents
The yara module provides the ability to scan systems the agent is running on
for objects which match provided yara rules. An investigator can send a list of
yara rules to the MIG agents along with an indication of what objects should be
scanned, and the agents will return any objects which matched and the rules that
matched against them.
Scanning is currently limited to files only at the moment.
Building MIG with Yara support
------------------------------
Yara support is not enabled by default and requires certain dependencies on the
build system to enable. Specifically, you will want the to make sure that the
`yara libraries <https://github.com/VirusTotal/yara>`_ are installed on the system
you are building MIG on.
To ensure that any systems with a yara enabled agent do not need to have the yara
library installed, MIG can be built with the yara library statically linked into
the MIG binary.
Fetch and install yara with the required options
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Download the yara tarball and compile it with the required options. You will need
a working c compiler in addition to automake and autoconf.
.. code::
$ curl -OL https://github.com/VirusTotal/yara/archive/v3.5.0.tar.gz
$ tar -zxvf v3.5.0.tar.gz
$ cd yara-3.5.0
$ ./bootstrap.sh
$ ./configure --disable-shared --disable-magic --disable-cuckoo --without-crypto
$ make
$ sudo make install
From here the agent can be compiled with yara support. The yara module should be
enabled in `conf/available_modules.go` (or whatever you have the Makefile variable
AVAILMOD set to). Then the agent can be compiled with yara support.
.. code::
$ make mig-agent WITHYARA=yes
The previous example applies to Linux. If you are building an OSX agent, you might
need a few extra environment variables to help locate things, such as:
.. code::
$ env CPATH=/my/path/to/yara/include LIBRARY_PATH=/my/path/to/yara/lib make mig-agent WITHYARA=yes
This should result in a mig-agent with the yara library builtin, which will work when
deployed to hosts without libyara. Note that, as modules are used in other MIG components
such as the client tools, you will likely want to set WITHYARA=yes when building the
client tools as well.
`tools/standalone_install.sh` also includes yara support, so can be reviewed for some
hints on the build process.
Usage
-----
Two options must be provided to the yara module.
The `rules` should specify the path on your system containing the yara rules
you want to send to the agents.
The `files` option should be set to a string which is essentially the arguments
you would provide to the file module. See the help output of the file module for
more information.
The following example shows a set of rules being used to scan everything in /bin
and in /sbin on each agent system.
.. code::
$ mig yara -t all -rules ./testrules.yara -files '-path /bin -path /sbin -name .'

Просмотреть файл

@ -0,0 +1,126 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Aaron Meihm ameihm@mozilla.com [:alm]
package yara /* import "mig.ninja/mig/modules/yara" */
import (
"bufio"
"flag"
"fmt"
"io/ioutil"
"os"
"strings"
)
func printHelp(isCmd bool) {
dash := ""
if isCmd {
dash = "-"
}
fmt.Printf(`Query parameters
----------------
%srules <path> - yara rules path
ex: path ./myrules.yar
processes yara rules on agent
%sfiles <spec> - scan files using rules
ex: files '-path /bin -path /sbin -name ssh'
indicate files that should be scanned, argument is
parameters as supplied to the file module for scanning,
each matching file will be scanned using rules. see the
help output for the file module for available options.
`, dash, dash)
}
func (r *run) ParamsCreator() (interface{}, error) {
p := newParameters()
scanner := bufio.NewScanner(os.Stdin)
for {
fmt.Printf("search> ")
scanmore := scanner.Scan()
if err := scanner.Err(); err != nil {
fmt.Println("Invalid input. Try again")
continue
}
if !scanmore {
goto exit
}
input := scanner.Text()
if input == "done" {
goto exit
} else if input == "help" {
printHelp(false)
continue
}
arr := strings.SplitN(input, " ", 2)
if len(arr) != 2 {
fmt.Printf("Invalid input format!\n")
printHelp(false)
continue
}
checkType := arr[0]
checkValue := arr[1]
switch checkType {
case "rules":
rulebuf, err := ioutil.ReadFile(checkValue)
if err != nil {
fmt.Printf("%v\n", err)
continue
}
p.YaraRules = string(rulebuf)
case "files":
p.FileSearch = checkValue
default:
fmt.Printf("Invalid method!\nTry 'help'\n")
continue
}
}
exit:
r.Parameters = *p
return r.Parameters, r.ValidateParameters()
}
func (r *run) ParamsParser(args []string) (interface{}, error) {
var (
fs flag.FlagSet
yaraPath string
fileSearch string
)
if len(args) < 1 || args[0] == "" || args[0] == "help" {
printHelp(true)
return nil, nil
}
fs.Init("yara", flag.ContinueOnError)
fs.StringVar(&yaraPath, "rules", "", "see help")
fs.StringVar(&fileSearch, "files", "", "see help")
err := fs.Parse(args)
if err != nil {
return nil, err
}
p := newParameters()
if yaraPath == "" {
return nil, fmt.Errorf("-rules option is required")
}
rulebuf, err := ioutil.ReadFile(yaraPath)
if err != nil {
return nil, err
}
p.YaraRules = string(rulebuf)
p.FileSearch = fileSearch
// Right now file searching is the only supported search, so this
// option must be specified.
if p.FileSearch == "" {
return nil, fmt.Errorf("-files option is required")
}
r.Parameters = *p
return r.Parameters, r.ValidateParameters()
}

230
modules/yara/yara.go Normal file
Просмотреть файл

@ -0,0 +1,230 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Aaron Meihm ameihm@mozilla.com [:alm]
// yara module implementation for MIG.
package yara /* import "mig.ninja/mig/modules/yara" */
import (
"bytes"
"encoding/json"
"fmt"
yara "github.com/hillu/go-yara"
"regexp"
"runtime"
"strings"
"time"
"mig.ninja/mig/modules"
"mig.ninja/mig/modules/file"
)
type module struct {
}
func (m *module) NewRun() modules.Runner {
return new(run)
}
func init() {
modules.Register("yara", new(module))
}
type run struct {
Parameters parameters
Results modules.Result
}
func buildResults(e YaraElements, r *modules.Result) (buf []byte, err error) {
r.Success = true
r.Elements = e
if len(e.Matches) > 0 {
r.FoundAnything = true
}
buf, err = json.Marshal(r)
return
}
// Convert sub-module arguments supplied as a string in the arguments of the
// yara module query to a slice. For example, parses input like:
// -path /etc -name test -content "test file"
//
// into:
// ["-path", "/etc", "-name", "test", "content", "test file"]
func moduleArguments(args string) (ret []string) {
r := regexp.MustCompile("'.+'|\".+\"|\\S+")
m := r.FindAllString(args, -1)
for _, x := range m {
b := strings.Trim(x, "\"")
b = strings.Trim(b, "'")
ret = append(ret, b)
}
return
}
// If a file scan is being conducted, this locates any files we will include in the
// scan. This function makes use of the file module for this purpose.
func findFiles(args []string) ([]string, error) {
ret := make([]string, 0)
run := modules.Available["file"].NewRun()
param, err := run.(modules.HasParamsParser).ParamsParser(args)
if err != nil {
return ret, err
}
buf, err := modules.MakeMessage(modules.MsgClassParameters, param, false)
if err != nil {
return ret, err
}
rdr := modules.NewModuleReader(bytes.NewReader(buf))
res := run.Run(rdr)
var modresult modules.Result
var sr file.SearchResults
err = json.Unmarshal([]byte(res), &modresult)
if err != nil {
return ret, err
}
err = modresult.GetElements(&sr)
if err != nil {
return ret, err
}
p0, ok := sr["s1"]
if !ok {
return ret, fmt.Errorf("result in file module call was missing")
}
for _, x := range p0 {
ret = append(ret, x.File)
}
return ret, nil
}
func (r *run) Run(in modules.ModuleReader) (resStr string) {
defer func() {
if e := recover(); e != nil {
// return error in json
r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("%v", e))
r.Results.Success = false
err, _ := json.Marshal(r.Results)
resStr = string(err)
return
}
}()
// Restrict go runtime processor utilization here, this might be moved
// into a more generic agent module function at some point.
runtime.GOMAXPROCS(1)
// Read module parameters from stdin
err := modules.ReadInputParameters(in, &r.Parameters)
if err != nil {
panic(err)
}
err = r.ValidateParameters()
if err != nil {
panic(err)
}
yaracomp, err := yara.NewCompiler()
if err != nil {
panic(err)
}
err = yaracomp.AddString(r.Parameters.YaraRules, "default")
if err != nil {
panic(err)
}
rules, err := yaracomp.GetRules()
if err != nil {
panic(err)
}
e := &YaraElements{}
if r.Parameters.FileSearch != "" {
flist, err := findFiles(moduleArguments(r.Parameters.FileSearch))
if err != nil {
panic(err)
}
for _, x := range flist {
mr, err := rules.ScanFile(x, 0, time.Second*10)
if err != nil {
emsg := fmt.Sprintf("%v: %v", x, err)
r.Results.Errors = append(r.Results.Errors, emsg)
continue
}
if len(mr) != 0 {
nm := YaraMatch{Object: x}
for _, y := range mr {
nm.MatchedRules = append(nm.MatchedRules, y.Rule)
}
e.Matches = append(e.Matches, nm)
}
}
}
buf, err := buildResults(*e, &r.Results)
if err != nil {
panic(err)
}
resStr = string(buf)
return
}
func (r *run) ValidateParameters() (err error) {
if r.Parameters.YaraRules == "" {
return fmt.Errorf("yara rules are a required option")
}
if r.Parameters.FileSearch != "" {
run := modules.Available["file"].NewRun()
_, err = run.(modules.HasParamsParser).ParamsParser(moduleArguments(r.Parameters.FileSearch))
if err != nil {
return err
}
}
return nil
}
func (r *run) PrintResults(result modules.Result, foundOnly bool) (prints []string, err error) {
var (
elem YaraElements
)
err = result.GetElements(&elem)
if err != nil {
panic(err)
}
for _, x := range elem.Matches {
var rn []string
for _, y := range x.MatchedRules {
rn = append(rn, y)
}
prints = append(prints, fmt.Sprintf("%v [%v]", x.Object, strings.Join(rn, ",")))
}
if !foundOnly {
for _, we := range result.Errors {
prints = append(prints, we)
}
}
return
}
type YaraMatch struct {
Object string // Object matched (e.g., file name)
MatchedRules []string // Matched rule
}
type YaraElements struct {
Matches []YaraMatch // Module returns a list of matches
}
type parameters struct {
YaraRules string `json:"yara"` // Yara rules as a string
FileSearch string `json:"filesearch"` // file module parameters for file search
}
func newParameters() *parameters {
return &parameters{}
}

16
modules/yara/yara_test.go Normal file
Просмотреть файл

@ -0,0 +1,16 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Aaron Meihm ameihm@mozilla.com [:alm]
package yara /* import "mig.ninja/mig/modules/yara" */
import (
"mig.ninja/mig/testutil"
"testing"
)
func TestRegistration(t *testing.T) {
testutil.CheckModuleRegistration(t, "yara")
}

Просмотреть файл

@ -86,12 +86,15 @@ fi
go_version=$(go version)
echo $go_version | grep -E -q --regexp="go1\.[0-4]" && echo -e "installed version of go is ${go_version}\nwe need at least version 1.5" && fail
which git 2>&1 1>/dev/null || pkglist="$pkglist git"
which make 2>&1 1>/dev/null || pkglist="$pkglist make"
which gcc 2>&1 1>/dev/null || pkglist="$pkglist gcc"
which tmux 2>&1 1>/dev/null || pkglist="$pkglist tmux"
which curl 2>&1 1>/dev/null || pkglist="$pkglist curl"
which rngd 2>&1 1>/dev/null || pkglist="$pkglist rng-tools"
which git 2>&1 1>/dev/null || pkglist="$pkglist git"
which make 2>&1 1>/dev/null || pkglist="$pkglist make"
which gcc 2>&1 1>/dev/null || pkglist="$pkglist gcc"
which tmux 2>&1 1>/dev/null || pkglist="$pkglist tmux"
which curl 2>&1 1>/dev/null || pkglist="$pkglist curl"
which rngd 2>&1 1>/dev/null || pkglist="$pkglist rng-tools"
which autoconf 2>&1 1>/dev/null || pkglist="$pkglist autoconf"
which automake 2>&1 1>/dev/null || pkglist="$pkglist automake"
which libtool 2>&1 1>/dev/null || pkglist="$pkglist libtool"
if [ "$pkglist" != "" ]; then
echo "missing packages: $pkglist"
@ -117,6 +120,13 @@ if [ "$isRPM" = true ]; then
sudo service postgresql restart
fi
# Fetch and install a version of libyara with our desired configuration
echo -e "\n---- Building libyara\n"
curl -OL https://github.com/VirusTotal/yara/archive/v3.5.0.tar.gz || fail
tar -zxf v3.5.0.tar.gz || fail
(cd yara-3.5.0 && ./bootstrap.sh && ./configure --disable-shared --disable-magic --disable-cuckoo --without-crypto) || fail
(cd yara-3.5.0 && make && sudo make install) || fail
echo -e "\n---- Building MIG Scheduler\n"
make mig-scheduler || fail
id mig || sudo useradd -r mig || fail
@ -137,12 +147,12 @@ sudo chown mig /usr/local/bin/mig-worker-agent-verif || fail
sudo chmod 550 /usr/local/bin/mig-worker-agent-verif || fail
echo -e "\n---- Building MIG Clients\n"
make mig-console || fail
make mig-console WITHYARA=yes || fail
sudo cp bin/linux/amd64/mig-console /usr/local/bin/ || fail
sudo chown mig /usr/local/bin/mig-console || fail
sudo chmod 555 /usr/local/bin/mig-console || fail
make mig-cmd || fail
make mig-cmd WITHYARA=yes || fail
sudo cp bin/linux/amd64/mig /usr/local/bin/ || fail
sudo chown mig /usr/local/bin/mig || fail
sudo chmod 555 /usr/local/bin/mig || fail
@ -354,7 +364,7 @@ var AGENTKEY = []byte("")
EOF
echo -e "\n---- Building and running local agent\n"
make mig-agent AGTCONF=conf/mig-agent-conf.go BUILDENV=demo || fail
make mig-agent AGTCONF=conf/mig-agent-conf.go BUILDENV=demo WITHYARA=yes || fail
sudo cp bin/linux/amd64/mig-agent-latest /sbin/mig-agent || fail
sudo chown root /sbin/mig-agent || fail
sudo chmod 500 /sbin/mig-agent || fail

16
vendor/github.com/hillu/go-yara/.travis.yml сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,16 @@
language: go
go:
- 1.6.x
- 1.7.x
- 1.8.x
- tip
dist: xenial
sudo: required
before_install:
- sudo apt-get update
- sudo apt-get install bison flex automake autoconf libtool make gcc
- wget --no-verbose -O- https://github.com/VirusTotal/yara/archive/v3.5.0.tar.gz | tar -C ${TRAVIS_BUILD_DIR} -xzf -
- ( cd ${TRAVIS_BUILD_DIR}/yara-3.5.0 && ./bootstrap.sh && ./configure && make )
- export CGO_CFLAGS=-I${TRAVIS_BUILD_DIR}/yara-3.5.0/libyara/include
- export CGO_LDFLAGS=-L${TRAVIS_BUILD_DIR}/yara-3.5.0/libyara/.libs
- export LD_LIBRARY_PATH=${TRAVIS_BUILD_DIR}/yara-3.5.0/libyara/.libs

23
vendor/github.com/hillu/go-yara/LICENSE сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,23 @@
Copyright (c) 2015, Hilko Bengen <bengen@hilluzination.de>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

94
vendor/github.com/hillu/go-yara/README.md сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,94 @@
# go-yara
[![GoDoc](https://godoc.org/github.com/hillu/go-yara?status.svg)](https://godoc.org/github.com/hillu/go-yara)
[![Travis](https://travis-ci.org/hillu/go-yara.svg?branch=master)](https://travis-ci.org/hillu/go-yara)
Go bindings for [YARA](http://plusvic.github.io/yara/), staying as
close as sensible to the library's C-API while taking inspiration from
the `yara-python` implementation.
YARA 3.4.0 or higher is required for full functionality. If you need
to build with YARA 3.3.0, please build with the `yara3.3` build tag.
(The `compat-yara-3.3` branch has been removed.)
## Installation
### Unix
On a Unix system with libyara properly installed, this should work,
provided that `GOPATH` is set:
```
go get github.com/hillu/go-yara
go install github.com/hillu/go-yara
```
Depending on what location libyara and its headers have been
installed, proper `CFLAGS` and `LDFLAGS` may have to be added to
`cgo.go` or be specified via environment variables (`CGO_CFLAGS` and
`CGO_LDFLAGS`).
Linker errors buried in the CGO output such as
undefined reference to `yr_compiler_add_file'
probably mean that the linker is looking at an old version of the YARA
library.
### Cross-building for Windows
YARA and go-yara can be cross-built on a Debian system as long as the
Go compiler contains Windows runtime libraries with CGO support
([cf.](https://github.com/hillu/golang-go-cross)).
The YARA library is built from the source tree with the MinGW compiler
using the usual `./configure && make && make install`. Then go-yara is
built and installed to `GOPATH` using `go install`. Some environment
variables need to be passed to the `go` tool:
- `GOOS`, `GOARCH` indicate the cross compilation
target.
- `CGO_ENABLED` is set to 1 beacuse it defaults to 0 when
cross-compiling.
- `CC` has to specified because the `go` tool has no knowledge on what
C compiler to use (it defaults to the system C compiler, usually
gcc).
- The C compiler in turn needs to know where to find headers and
libraries, these locations are specified via the `CGO_CFLAGS` and
`CGO_LDFLAGS` variables.
32bit:
```
cd ${YARA_SRC}
./configure --host=i686-w64-mingw32 --disable-magic --disable-cuckoo --without-crypto
make
make install prefix=./i686-w64-mingw32
cd ${GO_YARA_SRC}
GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc \
CGO_CFLAGS=-I${YARA_SRC}/i686-w64-mingw32/include \
CGO_LDFLAGS=-L${YARA_SRC}/i686-w64-mingw32/lib \
go install --ldflags '-extldflags "-static"' github.com/hillu/go-yara
```
64bit:
```
cd ${YARA_SRC}
./configure --host=x86_64-w64-mingw32 --disable-magic --disable-cuckoo --without-crypto
make
make install prefix=./x86_64-w64-mingw32
cd ${GO_YARA_SRC}
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc \
CGO_CFLAGS=-I${YARA_SRC}/x86_64-w64-mingw32/include \
CGO_LDFLAGS=-L${YARA_SRC}/x86_64-w64-mingw32/lib \
go install --ldflags '-extldflags "-static"' github.com/hillu/go-yara
```
## License
BSD 2-clause, see LICENSE file in the source distribution.
## Author
Hilko Bengen <bengen@hilluzination.de>

56
vendor/github.com/hillu/go-yara/callback-util.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,56 @@
package yara
import (
"strconv"
"sync"
)
/*
The closure type stores (pointers to) arbitrary data, returning a
(usually small) uintptr. The uintptr value can be passed through C
code to exported callback functions written in Go that can use it to
access the data without violating the rules for passing pointers
through C code.
Concurrent access to the stored data is protected through a
sync.RWMutex.
*/
type closure struct {
m map[uintptr]interface{}
sync.RWMutex
}
func (c *closure) Put(elem interface{}) uintptr {
c.Lock()
if c.m == nil {
c.m = make(map[uintptr]interface{})
}
defer c.Unlock()
for i := uintptr(0); ; i++ {
_, ok := c.m[i]
if !ok {
c.m[i] = elem
return i
}
}
}
func (c *closure) Get(id uintptr) interface{} {
c.RLock()
defer c.RUnlock()
if r, ok := c.m[id]; ok {
return r
}
panic("get: element " + strconv.Itoa(int(id)) + " not found")
}
func (c *closure) Delete(id uintptr) {
c.Lock()
defer c.Unlock()
if _, ok := c.m[id]; !ok {
panic("delete: element " + strconv.Itoa(int(id)) + " not found")
}
delete(c.m, id)
}
var callbackData closure

8
vendor/github.com/hillu/go-yara/cgo.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,8 @@
// Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.
package yara
// #cgo LDFLAGS: -lyara
import "C"

215
vendor/github.com/hillu/go-yara/compiler.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,215 @@
// Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.
package yara
/*
#ifdef _WIN32
#define fdopen _fdopen
#define dup _dup
#endif
#include <stdio.h>
#include <unistd.h>
#include <yara.h>
// This signature should be generated by cgo from the exported
// function below
void compilerCallback(int, char*, int, char*, void*);
*/
import "C"
import (
"errors"
"os"
"runtime"
"unsafe"
)
//export compilerCallback
func compilerCallback(errorLevel C.int, filename *C.char, linenumber C.int, message *C.char, userData unsafe.Pointer) {
c := callbackData.Get(uintptr(userData)).(*Compiler)
msg := CompilerMessage{
Filename: C.GoString(filename),
Line: int(linenumber),
Text: C.GoString(message),
}
switch errorLevel {
case C.YARA_ERROR_LEVEL_ERROR:
c.Errors = append(c.Errors, msg)
case C.YARA_ERROR_LEVEL_WARNING:
c.Warnings = append(c.Warnings, msg)
}
}
// A Compiler encapsulates the YARA compiler that transforms rules
// into YARA's internal, binary form which in turn is used for
// scanning files or memory blocks.
type Compiler struct {
*compiler
Errors []CompilerMessage
Warnings []CompilerMessage
}
type compiler struct {
cptr *C.YR_COMPILER
}
// A CompilerMessage contains an error or warning message produced
// while compiling sets of rules using AddString or AddFile.
type CompilerMessage struct {
Filename string
Line int
Text string
}
// NewCompiler creates a YARA compiler.
func NewCompiler() (*Compiler, error) {
var yrCompiler *C.YR_COMPILER
if err := newError(C.yr_compiler_create(&yrCompiler)); err != nil {
return nil, err
}
c := &Compiler{compiler: &compiler{cptr: yrCompiler}}
runtime.SetFinalizer(c.compiler, (*compiler).finalize)
return c, nil
}
func (c *compiler) finalize() {
C.yr_compiler_destroy(c.cptr)
runtime.SetFinalizer(c, nil)
}
// Destroy destroys the YARA data structure representing a compiler.
// Since a Finalizer for the underlying YR_COMPILER structure is
// automatically set up on creation, it should not be necessary to
// explicitly call this method.
func (c *Compiler) Destroy() {
if c.compiler != nil {
c.compiler.finalize()
c.compiler = nil
}
}
// AddFile compiles rules from a file. Rules are added to the
// specified namespace.
func (c *Compiler) AddFile(file *os.File, namespace string) (err error) {
fd := C.dup(C.int(file.Fd()))
fh, err := C.fdopen(fd, C.CString("r"))
if err != nil {
return err
}
defer C.fclose(fh)
var ns *C.char
if namespace != "" {
ns = C.CString(namespace)
defer C.free(unsafe.Pointer(ns))
}
filename := C.CString(file.Name())
defer C.free(unsafe.Pointer(filename))
id := callbackData.Put(c)
defer callbackData.Delete(id)
C.yr_compiler_set_callback(c.cptr, C.YR_COMPILER_CALLBACK_FUNC(C.compilerCallback), unsafe.Pointer(id))
numErrors := int(C.yr_compiler_add_file(c.cptr, fh, ns, filename))
if numErrors > 0 {
var buf [1024]C.char
msg := C.GoString(C.yr_compiler_get_error_message(
c.cptr, (*C.char)(unsafe.Pointer(&buf[0])), 1024))
err = errors.New(msg)
}
return
}
// AddString compiles rules from a string. Rules are added to the
// specified namespace.
func (c *Compiler) AddString(rules string, namespace string) (err error) {
var ns *C.char
if namespace != "" {
ns = C.CString(namespace)
defer C.free(unsafe.Pointer(ns))
}
crules := C.CString(rules)
defer C.free(unsafe.Pointer(crules))
id := callbackData.Put(c)
defer callbackData.Delete(id)
C.yr_compiler_set_callback(c.cptr, C.YR_COMPILER_CALLBACK_FUNC(C.compilerCallback), unsafe.Pointer(id))
numErrors := int(C.yr_compiler_add_string(c.cptr, crules, ns))
if numErrors > 0 {
var buf [1024]C.char
msg := C.GoString(C.yr_compiler_get_error_message(
c.cptr, (*C.char)(unsafe.Pointer(&buf[0])), 1024))
err = errors.New(msg)
}
return
}
// DefineVariable defines a named variable for use by the compiler.
// Boolean, int64, float64, and string types are supported.
func (c *Compiler) DefineVariable(name string, value interface{}) (err error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
switch value.(type) {
case bool:
var v int
if value.(bool) {
v = 1
}
err = newError(C.yr_compiler_define_boolean_variable(
c.cptr, cname, C.int(v)))
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
value := toint64(value)
err = newError(C.yr_compiler_define_integer_variable(
c.cptr, cname, C.int64_t(value)))
case float64:
err = newError(C.yr_compiler_define_float_variable(
c.cptr, cname, C.double(value.(float64))))
case string:
cvalue := C.CString(value.(string))
defer C.free(unsafe.Pointer(cvalue))
err = newError(C.yr_compiler_define_string_variable(
c.cptr, cname, cvalue))
default:
err = errors.New("wrong value type passed to DefineVariable; bool, int64, float64, string are accepted")
}
return
}
// GetRules returns the compiled ruleset.
func (c *Compiler) GetRules() (*Rules, error) {
var yrRules *C.YR_RULES
if err := newError(C.yr_compiler_get_rules(c.cptr, &yrRules)); err != nil {
return nil, err
}
r := &Rules{rules: &rules{cptr: yrRules}}
runtime.SetFinalizer(r.rules, (*rules).finalize)
return r, nil
}
// Compile compiles rules and an (optional) set of variables into a
// Rules object in a single step.
func Compile(rules string, variables map[string]interface{}) (r *Rules, err error) {
var c *Compiler
if c, err = NewCompiler(); err != nil {
return
}
for k, v := range variables {
if err = c.DefineVariable(k, v); err != nil {
return
}
}
if err = c.AddString(rules, ""); err != nil {
return
}
r, err = c.GetRules()
return
}
// MustCompile is like Compile but panics if the rules and optional
// variables can't be compiled. Like regexp.MustCompile, it allows for
// simple, safe initialization of global or test data.
func MustCompile(rules string, variables map[string]interface{}) (r *Rules) {
r, err := Compile(rules, variables)
if err != nil {
panic(err)
}
return
}

38
vendor/github.com/hillu/go-yara/compiler_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,38 @@
package yara
import "testing"
func TestCompiler(t *testing.T) {
c, _ := NewCompiler()
if err := c.AddString(
"rule test : tag1 { meta: author = \"Hilko Bengen\" strings: $a = \"abc\" fullword condition: $a }", "",
); err != nil {
t.Errorf("error: %s", err)
}
if err := c.AddString("xxx", ""); err == nil {
t.Error("did not recognize error")
} else {
t.Logf("expected error: %s", err)
}
}
func TestPanic(t *testing.T) {
defer func() {
err := recover()
if err == nil {
t.Error("MustCompile with broken data did not panic")
} else {
t.Logf("Everything ok, MustCompile panicked: %v", err)
}
}()
_ = MustCompile("asflkjkl", nil)
}
func TestWarnings(t *testing.T) {
c, _ := NewCompiler()
c.AddString("rule foo { bar }", "")
if len(c.Errors) == 0 {
t.Error()
}
t.Logf("Recorded Errors=%#v, Warnings=%#v", c.Errors, c.Warnings)
}

41
vendor/github.com/hillu/go-yara/crash_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,41 @@
package yara
import (
"fmt"
"runtime"
"testing"
)
// Making a copy of Compiler struct should not cause a crash.
func TestCompilerFinalizer(t *testing.T) {
var c Compiler
func() {
fmt.Println("Create compiler")
c1, _ := NewCompiler()
c = *c1
}()
fmt.Println("Trigger GC")
runtime.GC()
fmt.Println("Trigger Gosched")
runtime.Gosched()
fmt.Println("Manually call destructure on copy")
c.Destroy()
t.Log("Did not crash due to yr_*_destroy() being called twice. Yay.")
}
// Making a copy of Rules struct should not cause a crash.
func TestRulesFinalizer(t *testing.T) {
var r Rules
func() {
fmt.Println("Create rules")
r1, _ := Compile("rule test { condition: true }", nil)
r = *r1
}()
fmt.Println("Trigger GC")
runtime.GC()
fmt.Println("Trigger Gosched")
runtime.Gosched()
fmt.Println("Manually call destructure on copy")
r.Destroy()
t.Log("Did not crash due to yr_*_destroy() being called twice. Yay.")
}

67
vendor/github.com/hillu/go-yara/error.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,67 @@
// Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.
package yara
// #include <yara.h>
import "C"
import (
"errors"
"fmt"
)
func newError(code C.int) error {
if code == 0 {
return nil
}
if str, ok := errorStrings[code]; ok {
return errors.New(str)
}
return fmt.Errorf("unknown error %d", code)
}
// FIXME: This should be generated from yara/error.h
var errorStrings = map[C.int]string{
C.ERROR_INSUFICIENT_MEMORY: "insufficient memory",
C.ERROR_COULD_NOT_ATTACH_TO_PROCESS: "could not attach to process",
C.ERROR_COULD_NOT_OPEN_FILE: "could not open file",
C.ERROR_COULD_NOT_MAP_FILE: "could not map file",
C.ERROR_INVALID_FILE: "invalid file",
C.ERROR_CORRUPT_FILE: "corrupt file",
C.ERROR_UNSUPPORTED_FILE_VERSION: "unsupported file version",
C.ERROR_INVALID_REGULAR_EXPRESSION: "invalid regular expression",
C.ERROR_INVALID_HEX_STRING: "invalid hex string",
C.ERROR_SYNTAX_ERROR: "syntax error",
C.ERROR_LOOP_NESTING_LIMIT_EXCEEDED: "loop nesting limit exceeded",
C.ERROR_DUPLICATED_LOOP_IDENTIFIER: "duplicated loop identifier",
C.ERROR_DUPLICATED_IDENTIFIER: "duplicated identifier",
C.ERROR_DUPLICATED_TAG_IDENTIFIER: "duplicated tag identifier",
C.ERROR_DUPLICATED_META_IDENTIFIER: "duplicated meta identifier",
C.ERROR_DUPLICATED_STRING_IDENTIFIER: "duplicated string identifier",
C.ERROR_UNREFERENCED_STRING: "unreferenced string",
C.ERROR_UNDEFINED_STRING: "undefined string",
C.ERROR_UNDEFINED_IDENTIFIER: "undefined identifier",
C.ERROR_MISPLACED_ANONYMOUS_STRING: "misplaced anonymous string",
C.ERROR_INCLUDES_CIRCULAR_REFERENCE: "includes circular reference",
C.ERROR_INCLUDE_DEPTH_EXCEEDED: "include depth exceeded",
C.ERROR_WRONG_TYPE: "wrong type",
C.ERROR_EXEC_STACK_OVERFLOW: "exec stack overflow",
C.ERROR_SCAN_TIMEOUT: "scan timeout",
C.ERROR_TOO_MANY_SCAN_THREADS: "too many scan threads",
C.ERROR_CALLBACK_ERROR: "callback error",
C.ERROR_INVALID_ARGUMENT: "invalid argument",
C.ERROR_TOO_MANY_MATCHES: "too many matches",
C.ERROR_INTERNAL_FATAL_ERROR: "internal fatal error",
C.ERROR_NESTED_FOR_OF_LOOP: "nested for of loop",
C.ERROR_INVALID_FIELD_NAME: "invalid field name",
C.ERROR_UNKNOWN_MODULE: "unknown module",
C.ERROR_NOT_A_STRUCTURE: "not a structure",
C.ERROR_NOT_INDEXABLE: "not indexable",
C.ERROR_NOT_A_FUNCTION: "not a function",
C.ERROR_INVALID_FORMAT: "invalid format",
C.ERROR_TOO_MANY_ARGUMENTS: "too many arguments",
C.ERROR_WRONG_ARGUMENTS: "wrong arguments",
C.ERROR_WRONG_RETURN_TYPE: "wrong return type",
C.ERROR_DUPLICATED_STRUCTURE_MEMBER: "duplicated structure member",
}

17
vendor/github.com/hillu/go-yara/main_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,17 @@
package yara
import (
"os"
"testing"
)
func TestMain(m *testing.M) {
if r, err := Compile(`rule test : tag1 { meta: author = "Hilko Bengen" strings: $a = "abc" fullword condition: $a }`, nil); err != nil {
os.Exit(1)
} else if err = r.Save("testrules.yac"); err != nil {
os.Exit(1)
}
rc := m.Run()
os.Remove("testrules.yac")
os.Exit(rc)
}

430
vendor/github.com/hillu/go-yara/ported_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,430 @@
package yara
import (
"fmt"
"testing"
)
// This file contains tests that were ported from yara/yara-python/tests.py
var pe32file = []byte{
0x4d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4c, 0x01, 0x01, 0x00,
0x5d, 0xbe, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x00, 0x03, 0x01, 0x0b, 0x01, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00,
0x60, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x64, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x60, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x60, 0x6a, 0x2a, 0x58, 0xc3,
}
var elf32file = []byte{
0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
0x60, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x01, 0x00, 0x28, 0x00,
0x04, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0x6c, 0x00, 0x00, 0x00,
0x6c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb8, 0x01, 0x00, 0x00, 0x00, 0xbb, 0x2a, 0x00, 0x00, 0x00, 0xcd, 0x80,
0x00, 0x54, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x69, 0x64, 0x65,
0x20, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x20, 0x32,
0x2e, 0x30, 0x35, 0x2e, 0x30, 0x31, 0x00, 0x00, 0x2e, 0x73, 0x68, 0x73,
0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x60, 0x80, 0x04, 0x08, 0x60, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6c, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
}
var elf64file = []byte{
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x40, 0x00,
0x04, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00,
0x00, 0xbb, 0x2a, 0x00, 0x00, 0x00, 0xcd, 0x80, 0x00, 0x54, 0x68, 0x65,
0x20, 0x4e, 0x65, 0x74, 0x77, 0x69, 0x64, 0x65, 0x20, 0x41, 0x73, 0x73,
0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x20, 0x32, 0x2e, 0x30, 0x35, 0x2e,
0x30, 0x31, 0x00, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61,
0x62, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
func TestBooleanOperators(t *testing.T) {
assertTrueRules(t, []string{
"rule test { condition: true }",
"rule test { condition: true or false }",
"rule test { condition: true and true }",
"rule test { condition: 0x1 and 0x2}",
}, []byte("dummy"))
assertFalseRules(t, []string{
"rule test { condition: false }",
"rule test { condition: true and false }",
"rule test { condition: false or false }",
}, []byte("dummy"))
}
func TestComparisonOperators(t *testing.T) {
assertTrueRules(t, []string{
"rule test { condition: 2 > 1 }",
"rule test { condition: 1 < 2 }",
"rule test { condition: 2 >= 1 }",
"rule test { condition: 1 <= 1 }",
"rule test { condition: 1 == 1 }",
"rule test { condition: 1.5 == 1.5}",
"rule test { condition: 1.0 == 1}",
"rule test { condition: 1.5 >= 1.0}",
"rule test { condition: 1.5 >= 1}",
"rule test { condition: 1.0 >= 1}",
"rule test { condition: 0.5 < 1}",
"rule test { condition: 0.5 <= 1}",
"rule rest { condition: 1.0 <= 1}",
"rule rest { condition: \"abc\" == \"abc\"}",
"rule rest { condition: \"abc\" <= \"abc\"}",
"rule rest { condition: \"abc\" >= \"abc\"}",
"rule rest { condition: \"ab\" < \"abc\"}",
"rule rest { condition: \"abc\" > \"ab\"}",
"rule rest { condition: \"abc\" < \"abd\"}",
"rule rest { condition: \"abd\" > \"abc\"}",
}, []byte("dummy"))
assertFalseRules(t, []string{
"rule test { condition: 1 != 1}",
"rule test { condition: 2 > 3}",
"rule test { condition: 2 > 3}",
"rule test { condition: 2.1 < 2}",
"rule test { condition: \"abc\" != \"abc\"}",
"rule test { condition: \"abc\" > \"abc\"}",
"rule test { condition: \"abc\" < \"abc\"}",
}, []byte("dummy"))
}
func TestArithmeticOperators(t *testing.T) {
assertTrueRules(t, []string{
"rule test { condition: (1 + 1) * 2 == (9 - 1) \\ 2 }",
"rule test { condition: 5 % 2 == 1 }",
"rule test { condition: 1.5 + 1.5 == 3}",
"rule test { condition: 3 \\ 2 == 1}",
"rule test { condition: 3.0 \\ 2 == 1.5}",
"rule test { condition: 1 + -1 == 0}",
"rule test { condition: -1 + -1 == -2}",
"rule test { condition: 4 --2 * 2 == 8}",
"rule test { condition: -1.0 * 1 == -1.0}",
"rule test { condition: 1-1 == 0}",
"rule test { condition: -2.0-3.0 == -5}",
"rule test { condition: --1 == 1}",
"rule test { condition: 1--1 == 2}",
"rule test { condition: -0x01 == -1}",
}, []byte("dummy"))
}
func TestBitwiseOperators(t *testing.T) {
assertTrueRules(t, []string{
"rule test { condition: 0x55 | 0xAA == 0xFF }",
"rule test { condition: ~0xAA ^ 0x5A & 0xFF == (~0xAA) ^ (0x5A & 0xFF) }",
"rule test { condition: ~0x55 & 0xFF == 0xAA }",
"rule test { condition: 8 >> 2 == 2 }",
"rule test { condition: 1 << 3 == 8 }",
"rule test { condition: 1 | 3 ^ 3 == 1 | (3 ^ 3) }",
}, []byte("dummy"))
assertFalseRules(t, []string{
"rule test { condition: ~0xAA ^ 0x5A & 0xFF == 0x0F }",
"rule test { condition: 1 | 3 ^ 3 == (1 | 3) ^ 3}",
}, []byte("dummy"))
}
func TestStrings(t *testing.T) {
assertTrueRules(t, []string{
"rule test { strings: $a = \"a\" condition: $a }",
"rule test { strings: $a = \"ab\" condition: $a }",
"rule test { strings: $a = \"abc\" condition: $a }",
"rule test { strings: $a = \"xyz\" condition: $a }",
"rule test { strings: $a = \"abc\" nocase fullword condition: $a }",
"rule test { strings: $a = \"aBc\" nocase condition: $a }",
"rule test { strings: $a = \"abc\" fullword condition: $a }",
}, []byte("---- abc ---- xyz"))
assertFalseRules(t, []string{
"rule test { strings: $a = \"a\" fullword condition: $a }",
"rule test { strings: $a = \"ab\" fullword condition: $a }",
"rule test { strings: $a = \"abc\" wide fullword condition: $a }",
}, []byte("---- abc ---- xyz"))
assertTrueRules(t, []string{
"rule test { strings: $a = \"a\" wide condition: $a }",
"rule test { strings: $a = \"a\" wide ascii condition: $a }",
"rule test { strings: $a = \"ab\" wide condition: $a }",
"rule test { strings: $a = \"ab\" wide ascii condition: $a }",
"rule test { strings: $a = \"abc\" wide condition: $a }",
"rule test { strings: $a = \"abc\" wide nocase fullword condition: $a }",
"rule test { strings: $a = \"aBc\" wide nocase condition: $a }",
"rule test { strings: $a = \"aBc\" wide ascii nocase condition: $a }",
"rule test { strings: $a = \"---xyz\" wide nocase condition: $a }",
}, []byte("---- a\x00b\x00c\x00 -\x00-\x00-\x00-\x00x\x00y\x00z\x00"))
assertTrueRules(t, []string{
"rule test { strings: $a = \"abc\" fullword condition: $a }",
}, []byte("abc"))
assertFalseRules(t, []string{
"rule test { strings: $a = \"abc\" fullword condition: $a }",
}, []byte("xabcx"))
assertFalseRules(t, []string{
"rule test { strings: $a = \"abc\" fullword condition: $a }",
}, []byte("xabc"))
assertFalseRules(t, []string{
"rule test { strings: $a = \"abc\" fullword condition: $a }",
}, []byte("abcx"))
assertFalseRules(t, []string{
"rule test { strings: $a = \"abc\" ascii wide fullword condition: $a }",
}, []byte("abcx"))
assertTrueRules(t, []string{
"rule test { strings: $a = \"abc\" ascii wide fullword condition: $a }",
}, []byte("a\x00abc"))
assertTrueRules(t, []string{
"rule test { strings: $a = \"abc\" wide fullword condition: $a }",
}, []byte("a\x00b\x00c\x00"))
assertFalseRules(t, []string{
"rule test { strings: $a = \"abc\" wide fullword condition: $a }",
}, []byte("x\x00a\x00b\x00c\x00x\x00"))
assertFalseRules(t, []string{
"rule test { strings: $a = \"ab\" wide fullword condition: $a }",
}, []byte("x\x00a\x00b\x00"))
assertFalseRules(t, []string{
"rule test { strings: $a = \"abc\" wide fullword condition: $a }",
}, []byte("x\x00a\x00b\x00c\x00"))
assertTrueRules(t, []string{
"rule test { strings: $a = \"abc\" wide fullword condition: $a }",
}, []byte("x\x01a\x00b\x00c\x00"))
assertTrueRules(t, []string{"" +
"rule test {\n" +
" strings:\n" +
" $a = \"abcdef\"\n" +
" $b = \"cdef\"\n" +
" $c = \"ef\"\n" +
" condition:\n" +
" all of them\n" +
"}",
}, []byte("abcdef"))
}
func TestWildcardStrings(t *testing.T) {
assertTrueRules(t, []string{"" +
"rule test {\n" +
" strings:\n" +
" $s1 = \"abc\"\n" +
" $s2 = \"xyz\"\n" +
" condition:\n" +
" for all of ($*) : ($)\n" +
"}",
}, []byte("---- abc ---- A\x00B\x00C\x00 ---- xyz"))
}
func TestHexStrings(t *testing.T) {
assertTrueRules(t, []string{
"rule test { strings: $a = { 64 01 00 00 60 01 } condition: $a }",
"rule test { strings: $a = { 64 0? 00 00 ?0 01 } condition: $a }",
"rule test { strings: $a = { 64 01 [1-3] 60 01 } condition: $a }",
"rule test { strings: $a = { 64 01 [1-3] (60|61) 01 } condition: $a }",
"rule test { strings: $a = { 4D 5A [-] 6A 2A [-] 58 C3} condition: $a }",
"rule test { strings: $a = { 4D 5A [300-] 6A 2A [-] 58 C3} condition: $a }",
}, pe32file)
assertFalseRules(t, []string{
"rule test { strings: $a = { 4D 5A [0-300] 6A 2A } condition: $a }",
}, pe32file)
assertTrueRules(t, []string{
"rule test { strings: $a = { 31 32 [-] 38 39 } condition: $a }",
"rule test { strings: $a = { 31 32 [-] 33 34 [-] 38 39 } condition: $a }",
"rule test { strings: $a = { 31 32 [1] 34 35 [2] 38 39 } condition: $a }",
"rule test { strings: $a = { 31 32 [1-] 34 35 [1-] 38 39 } condition: $a }",
"rule test { strings: $a = { 31 32 [0-3] 34 35 [1-] 38 39 } condition: $a }",
}, []byte("123456789"))
assertTrueRules(t, []string{
"rule test { strings: $a = { 31 32 [-] 38 39 } condition: all of them }",
}, []byte("123456789"))
assertFalseRules(t, []string{
"rule test { strings: $a = { 31 32 [-] 32 33 } condition: $a }",
"rule test { strings: $a = { 35 36 [-] 31 32 } condition: $a }",
"rule test { strings: $a = { 31 32 [2-] 34 35 } condition: $a }",
"rule test { strings: $a = { 31 32 [0-3] 37 38 } condition: $a }",
}, []byte("123456789"))
rules := makeRules(t, "rule test { strings: $a = { 61 [0-3] (62|63) } condition: $a }")
matches, _ := rules.ScanMem([]byte("abbb"), 0, 0)
if matches[0].Strings[0].Name != "$a" ||
matches[0].Strings[0].Offset != 0 ||
string(matches[0].Strings[0].Data) != "ab" {
t.Error("wrong match")
}
}
// TODO: TestCount
// TODO: TestAt
// TODO: TestOffset
// TODO: TestOf
// TODO: TestFor
// TODO: TestRE
func TestEntrypoint(t *testing.T) {
assertTrueRules(t, []string{
"rule test { strings: $a = { 6a 2a 58 c3 } condition: $a at entrypoint }",
}, pe32file)
assertTrueRules(t, []string{
"rule test { strings: $a = { b8 01 00 00 00 bb 2a } condition: $a at entrypoint }",
}, elf32file)
assertTrueRules(t, []string{
"rule test { strings: $a = { b8 01 00 00 00 bb 2a } condition: $a at entrypoint }",
}, elf64file)
assertFalseRules(t, []string{
"rule test { condition: entrypoint >= 0 }",
}, []byte("dummy"))
}
func TestFilesize(t *testing.T) {
assertTrueRules(t, []string{
fmt.Sprintf("rule test { condition: filesize == %d }", len(pe32file)),
}, pe32file)
}
// TODO: TestCompileFile
// TODO: TestCompileFiles
// TODO: TestIncludeFiles
type params map[string]interface{}
func TestExternals(t *testing.T) {
for _, sample := range []struct {
rule string
params
predicate bool
}{
{"rule test { condition: ext_int == 15 }", params{"ext_int": 15}, true},
{"rule test { condition: ext_int == -15}", params{"ext_int": -15}, true},
{"rule test { condition: ext_float == 3.14 }", params{"ext_float": 3.14}, true},
{"rule test { condition: ext_float == -0.5 }", params{"ext_float": -0.5}, true},
{"rule test { condition: ext_bool }", params{"ext_bool": true}, true},
{"rule test { condition: ext_str }", params{"ext_str": ""}, false},
{"rule test { condition: ext_str }", params{"ext_str": "foo"}, true},
{"rule test { condition: ext_bool }", params{"ext_bool": false}, false},
{"rule test { condition: ext_str contains \"ssi\" }", params{"ext_str": "mississippi"}, true},
{"rule test { condition: ext_str matches /foo/ }", params{"ext_str": ""}, false},
{"rule test { condition: ext_str matches /foo/ }", params{"ext_str": "FOO"}, false},
{"rule test { condition: ext_str matches /foo/i }", params{"ext_str": "FOO"}, true},
{"rule test { condition: ext_str matches /ssi(s|p)/ }", params{"ext_str": "mississippi"}, true},
{"rule test { condition: ext_str matches /ppi$/ }", params{"ext_str": "mississippi"}, true},
{"rule test { condition: ext_str matches /ssi$/ }", params{"ext_str": "mississippi"}, false},
{"rule test { condition: ext_str matches /^miss/ }", params{"ext_str": "mississippi"}, true},
{"rule test { condition: ext_str matches /^iss/ }", params{"ext_str": "mississippi"}, false},
{"rule test { condition: ext_str matches /ssi$/ }", params{"ext_str": "mississippi"}, false},
} {
r, err := Compile(sample.rule, sample.params)
if err != nil {
t.Errorf("rule=%s params=%+v: Compile error: %s", sample.rule, sample.params, err)
continue
}
m, _ := r.ScanMem([]byte("dummy"), 0, 0)
if sample.predicate != (len(m) > 0) {
t.Errorf("rule=%s params=%+v: expected %t, got %t",
sample.rule, sample.params, sample.predicate, (len(m) > 0))
}
}
}
// TODO: TestCallback
// TODO: TestCompare
// TODO: TestComments
func TestModules(t *testing.T) {
assertTrueRules(t, []string{
"import \"tests\" rule test { condition: tests.constants.one + 1 == tests.constants.two }",
"import \"tests\" rule test { condition: tests.constants.foo == \"foo\" }",
"import \"tests\" rule test { condition: tests.struct_array[1].i == 1 }",
"import \"tests\" rule test { condition: tests.struct_array[0].i == 1 or true}",
"import \"tests\" rule test { condition: tests.integer_array[0] == 0}",
"import \"tests\" rule test { condition: tests.integer_array[1] == 1}",
"import \"tests\" rule test { condition: tests.string_array[0] == \"foo\"}",
"import \"tests\" rule test { condition: tests.string_array[2] == \"baz\"}",
"import \"tests\" rule test { condition: tests.string_dict[\"foo\"] == \"foo\"}",
"import \"tests\" rule test { condition: tests.string_dict[\"bar\"] == \"bar\"}",
"import \"tests\" rule test { condition: tests.isum(1,2) == 3}",
"import \"tests\" rule test { condition: tests.isum(1,2,3) == 6}",
"import \"tests\" rule test { condition: tests.fsum(1.0,2.0) == 3.0}",
"import \"tests\" rule test { condition: tests.fsum(1.0,2.0,3.0) == 6.0}",
"import \"tests\" rule test { condition: tests.length(\"dummy\") == 5}",
}, []byte("dummy"))
assertFalseRules(t, []string{
"import \"tests\" rule test { condition: tests.struct_array[0].i == 1 }",
"import \"tests\" rule test { condition: tests.isum(1,1) == 3}",
"import \"tests\" rule test { condition: tests.fsum(1.0,1.0) == 3.0}",
}, []byte("dummy"))
}
func TestIntegerFunctions(t *testing.T) {
assertTrueRules(t, []string{
"rule test { condition: uint8(0) == 0xAA}",
"rule test { condition: uint16(0) == 0xBBAA}",
"rule test { condition: uint32(0) == 0xDDCCBBAA}",
"rule test { condition: uint8be(0) == 0xAA}",
"rule test { condition: uint16be(0) == 0xAABB}",
"rule test { condition: uint32be(0) == 0xAABBCCDD}",
}, []byte("\xAA\xBB\xCC\xDD"))
}

70
vendor/github.com/hillu/go-yara/rules-callback.c сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,70 @@
/*
Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
Use of this source code is governed by the license that can be
found in the LICENSE file.
*/
#include <yara.h>
#include "_cgo_export.h"
int rules_callback(int message, void *message_data, void *user_data) {
if (message == CALLBACK_MSG_RULE_MATCHING) {
YR_RULE* rule = (YR_RULE*) message_data;
char* ns = rule->ns->name;
if(ns == NULL) {
ns = "";
}
newMatch(user_data, ns, (char*)rule->identifier);
YR_META* meta;
yr_rule_metas_foreach(rule, meta) {
switch (meta->type) {
case META_TYPE_INTEGER:
addMetaInt(user_data, (char*)meta->identifier, meta->integer);
break;
case META_TYPE_STRING:
addMetaString(user_data, (char*)meta->identifier, meta->string);
break;
case META_TYPE_BOOLEAN:
addMetaBool(user_data, (char*)meta->identifier, meta->integer);
break;
}
}
const char* tag_name;
yr_rule_tags_foreach(rule, tag_name) {
addTag(user_data, (char*)tag_name);
}
YR_STRING* string;
YR_MATCH* m;
yr_rule_strings_foreach(rule, string) {
yr_string_matches_foreach(string, m) {
#if YR_VERSION_HEX >= 0x030500
/* YR_MATCH members have been renamed in YARA 3.5 */
addString(user_data, string->identifier, m->offset, m->data, (int)m->data_length);
#else
addString(user_data, string->identifier, m->offset, m->data, (int)m->length);
#endif
}
}
}
return CALLBACK_CONTINUE;
}
#ifdef _WIN32
/*
Helper function that is merely used to cast fd from int to HANDLE.
CGO treats HANDLE (void*) to an unsafe.Pointer. This confuses the
go1.4 garbage collector, leading to runtime errors such as:
runtime: garbage collector found invalid heap pointer *(0x5b80ff14+0x4)=0xa0 s=nil
*/
int _yr_rules_scan_fd(
YR_RULES* rules,
int fd,
int flags,
YR_CALLBACK_FUNC callback,
void* user_data,
int timeout)
{
return yr_rules_scan_fd(rules, (YR_FILE_DESCRIPTOR)fd, flags, callback, user_data, timeout);
}
#endif

241
vendor/github.com/hillu/go-yara/rules.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,241 @@
// Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.
// Package yara provides bindings to the YARA library.
package yara
/*
#include <yara.h>
int rules_callback(int message, void *message_data, void *user_data);
*/
import "C"
import (
"errors"
"reflect"
"runtime"
"time"
"unsafe"
)
// Rules contains a compiled YARA ruleset.
type Rules struct {
*rules
}
type rules struct {
cptr *C.YR_RULES
}
var dummy *[]MatchRule
// A MatchRule represents a rule successfully matched against a block
// of data.
type MatchRule struct {
Rule string
Namespace string
Tags []string
Meta map[string]interface{}
Strings []MatchString
}
// A MatchString represents a string declared and matched in a rule.
type MatchString struct {
Name string
Offset uint64
Data []byte
}
func init() {
_ = C.yr_initialize()
}
//export newMatch
func newMatch(userData unsafe.Pointer, namespace, identifier *C.char) {
matches := callbackData.Get(uintptr(userData)).(*[]MatchRule)
*matches = append(*matches, MatchRule{
Rule: C.GoString(identifier),
Namespace: C.GoString(namespace),
Tags: []string{},
Meta: map[string]interface{}{},
Strings: []MatchString{},
})
}
//export addMetaInt
func addMetaInt(userData unsafe.Pointer, identifier *C.char, value C.int) {
matches := callbackData.Get(uintptr(userData)).(*[]MatchRule)
i := len(*matches) - 1
(*matches)[i].Meta[C.GoString(identifier)] = int32(value)
}
//export addMetaString
func addMetaString(userData unsafe.Pointer, identifier *C.char, value *C.char) {
matches := callbackData.Get(uintptr(userData)).(*[]MatchRule)
i := len(*matches) - 1
(*matches)[i].Meta[C.GoString(identifier)] = C.GoString(value)
}
//export addMetaBool
func addMetaBool(userData unsafe.Pointer, identifier *C.char, value C.int) {
matches := callbackData.Get(uintptr(userData)).(*[]MatchRule)
i := len(*matches) - 1
(*matches)[i].Meta[C.GoString(identifier)] = bool(value != 0)
}
//export addTag
func addTag(userData unsafe.Pointer, tag *C.char) {
matches := callbackData.Get(uintptr(userData)).(*[]MatchRule)
i := len(*matches) - 1
(*matches)[i].Tags = append((*matches)[i].Tags, C.GoString(tag))
}
//export addString
func addString(userData unsafe.Pointer, identifier *C.char, offset C.uint64_t, data unsafe.Pointer, length C.int) {
ms := MatchString{
Name: C.GoString(identifier),
Offset: uint64(offset),
Data: make([]byte, int(length)),
}
var tmpSlice []byte
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&tmpSlice))
hdr.Data = uintptr(data)
hdr.Len = int(length)
copy(ms.Data, tmpSlice)
matches := callbackData.Get(uintptr(userData)).(*[]MatchRule)
i := len(*matches) - 1
(*matches)[i].Strings = append((*matches)[i].Strings, ms)
}
// ScanFlags are used to tweak the behavior of Scan* functions.
type ScanFlags int
const (
// ScanFlagsFastMode avoids multiple matches of the same string
// when not necessary.
ScanFlagsFastMode = C.SCAN_FLAGS_FAST_MODE
// ScanFlagsProcessMemory causes the scanned data to be
// interpreted like live, in-prcess memory rather than an on-disk
// file.
ScanFlagsProcessMemory = C.SCAN_FLAGS_PROCESS_MEMORY
)
// ScanMem scans an in-memory buffer using the ruleset.
func (r *Rules) ScanMem(buf []byte, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
var ptr *C.uint8_t
if len(buf) > 0 {
ptr = (*C.uint8_t)(unsafe.Pointer(&(buf[0])))
}
id := callbackData.Put(&matches)
defer callbackData.Delete(id)
err = newError(C.yr_rules_scan_mem(
r.cptr,
ptr,
C.size_t(len(buf)),
C.int(flags),
C.YR_CALLBACK_FUNC(C.rules_callback),
unsafe.Pointer(id),
C.int(timeout/time.Second)))
return
}
// ScanFile scans a file using the ruleset.
func (r *Rules) ScanFile(filename string, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
cfilename := C.CString(filename)
defer C.free(unsafe.Pointer(cfilename))
id := callbackData.Put(&matches)
defer callbackData.Delete(id)
err = newError(C.yr_rules_scan_file(
r.cptr,
cfilename,
C.int(flags),
C.YR_CALLBACK_FUNC(C.rules_callback),
unsafe.Pointer(id),
C.int(timeout/time.Second)))
return
}
// ScanProc scans a live process using the ruleset.
func (r *Rules) ScanProc(pid int, flags int, timeout time.Duration) (matches []MatchRule, err error) {
id := callbackData.Put(&matches)
defer callbackData.Delete(id)
err = newError(C.yr_rules_scan_proc(
r.cptr,
C.int(pid),
C.int(flags),
C.YR_CALLBACK_FUNC(C.rules_callback),
unsafe.Pointer(id),
C.int(timeout/time.Second)))
return
}
// Save writes a compiled ruleset to filename.
func (r *Rules) Save(filename string) (err error) {
cfilename := C.CString(filename)
defer C.free(unsafe.Pointer(cfilename))
err = newError(C.yr_rules_save(r.cptr, cfilename))
return
}
// LoadRules retrieves a compiled ruleset from filename.
func LoadRules(filename string) (*Rules, error) {
r := &Rules{rules: &rules{}}
cfilename := C.CString(filename)
defer C.free(unsafe.Pointer(cfilename))
if err := newError(C.yr_rules_load(cfilename,
&(r.rules.cptr))); err != nil {
return nil, err
}
runtime.SetFinalizer(r.rules, (*rules).finalize)
return r, nil
}
func (r *rules) finalize() {
C.yr_rules_destroy(r.cptr)
runtime.SetFinalizer(r, nil)
}
// Destroy destroys the YARA data structure representing a ruleset.
// Since a Finalizer for the underlying YR_RULES structure is
// automatically set up on creation, it should not be necessary to
// explicitly call this method.
func (r *Rules) Destroy() {
if r.rules != nil {
r.rules.finalize()
r.rules = nil
}
}
// DefineVariable defines a named variable for use by the compiler.
// Boolean, int64, float64, and string types are supported.
func (r *Rules) DefineVariable(name string, value interface{}) (err error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
switch value.(type) {
case bool:
var v int
if value.(bool) {
v = 1
}
err = newError(C.yr_rules_define_boolean_variable(
r.cptr, cname, C.int(v)))
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
value := toint64(value)
err = newError(C.yr_rules_define_integer_variable(
r.cptr, cname, C.int64_t(value)))
case float64:
err = newError(C.yr_rules_define_float_variable(
r.cptr, cname, C.double(value.(float64))))
case string:
cvalue := C.CString(value.(string))
defer C.free(unsafe.Pointer(cvalue))
err = newError(C.yr_rules_define_string_variable(
r.cptr, cname, cvalue))
default:
err = errors.New("wrong value type passed to DefineVariable; bool, int64, float64, string are accepted")
}
return
}

184
vendor/github.com/hillu/go-yara/rules_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,184 @@
package yara
import (
"bytes"
"compress/bzip2"
"fmt"
"io/ioutil"
"os"
"os/exec"
"testing"
)
func makeRules(t *testing.T, rule string) *Rules {
c, err := NewCompiler()
if c == nil || err != nil {
t.Fatal("NewCompiler():", err)
}
if err = c.AddString(rule, ""); err != nil {
t.Fatal("AddString():", err)
}
r, err := c.GetRules()
if err != nil {
t.Fatal("GetRules:", err)
}
return r
}
func TestSimpleMatch(t *testing.T) {
r := makeRules(t,
"rule test : tag1 { meta: author = \"Hilko Bengen\" strings: $a = \"abc\" fullword condition: $a }")
m, err := r.ScanMem([]byte(" abc "), 0, 0)
if err != nil {
t.Errorf("ScanMem: %s", err)
}
t.Logf("Matches: %+v", m)
}
func TestSimpleFileMatch(t *testing.T) {
r, _ := Compile(
"rule test : tag1 { meta: author = \"Hilko Bengen\" strings: $a = \"abc\" fullword condition: $a }",
nil)
tf, _ := ioutil.TempFile("", "TestSimpleFileMatch")
defer os.Remove(tf.Name())
tf.Write([]byte(" abc "))
tf.Close()
m, err := r.ScanFile(tf.Name(), 0, 0)
if err != nil {
t.Errorf("ScanFile(%s): %s", tf.Name(), err)
}
t.Logf("Matches: %+v", m)
}
func TestSimpleFileDescriptorMatch(t *testing.T) {
r, _ := Compile(
"rule test : tag1 { meta: author = \"Hilko Bengen\" strings: $a = \"abc\" fullword condition: $a }",
nil)
tf, _ := ioutil.TempFile("", "TestSimpleFileMatch")
defer os.Remove(tf.Name())
tf.Write([]byte(" abc "))
tf.Seek(0, os.SEEK_SET)
m, err := r.ScanFileDescriptor(tf.Fd(), 0, 0)
if err != nil {
t.Errorf("ScanFile(%s): %s", tf.Name(), err)
}
t.Logf("Matches: %+v", m)
}
func TestEmpty(t *testing.T) {
r, _ := Compile("rule test { condition: true }", nil)
r.ScanMem([]byte{}, 0, 0)
t.Log("Scan of null-byte slice did not crash. Yay.")
}
func assertTrueRules(t *testing.T, rules []string, data []byte) {
for _, rule := range rules {
r := makeRules(t, rule)
if m, err := r.ScanMem(data, 0, 0); len(m) == 0 {
t.Errorf("Rule < %s > did not match data < %v >", rule, data)
} else if err != nil {
t.Errorf("Error %s", err)
}
}
}
func assertFalseRules(t *testing.T, rules []string, data []byte) {
for _, rule := range rules {
r := makeRules(t, rule)
if m, err := r.ScanMem(data, 0, 0); len(m) > 0 {
t.Errorf("Rule < %s > matched data < %v >", rule, data)
} else if err != nil {
t.Errorf("Error %s", err)
}
}
}
func TestLoad(t *testing.T) {
r, err := LoadRules("testrules.yac")
if r == nil || err != nil {
t.Fatalf("LoadRules: %s", err)
}
}
func TestReader(t *testing.T) {
rd, err := os.Open("testrules.yac")
if err != nil {
t.Fatalf("os.Open: %s", err)
}
r, err := ReadRules(rd)
if err != nil {
t.Fatalf("ReadRules: %+v", err)
}
m, err := r.ScanMem([]byte(" abc "), 0, 0)
if err != nil {
t.Errorf("ScanMem: %s", err)
}
t.Logf("Matches: %+v", m)
}
func TestWriter(t *testing.T) {
rd, err := os.Open("testrules.yac")
if err != nil {
t.Fatalf("os.Open: %s", err)
}
compareBuf, _ := ioutil.ReadAll(rd)
r, _ := Compile("rule test : tag1 { meta: author = \"Hilko Bengen\" strings: $a = \"abc\" fullword condition: $a }",
nil)
wr := bytes.Buffer{}
if err := r.Write(&wr); err != nil {
t.Fatal(err)
}
newBuf := wr.Bytes()
if len(compareBuf) != len(newBuf) {
t.Errorf("len(compareBuf) = %d, len(newBuf) = %d", len(compareBuf), len(newBuf))
}
if bytes.Compare(compareBuf, newBuf) != 0 {
t.Error("buffers are not equal")
}
}
// compress/bzip2 seems to return short reads which apparently leads
// to YARA complaining about corrupt files. Tested with Go 1.4, 1.5.
func TestReaderBZIP2(t *testing.T) {
rulesBuf := bytes.NewBuffer(nil)
for i := 0; i < 10000; i++ {
fmt.Fprintf(rulesBuf, "rule test%d : tag%d { meta: author = \"Hilko Bengen\" strings: $a = \"abc\" fullword condition: $a }", i, i)
}
r, _ := Compile(string(rulesBuf.Bytes()), nil)
cmd := exec.Command("bzip2", "-c")
compressStream, _ := cmd.StdinPipe()
buf := bytes.NewBuffer(nil)
cmd.Stdout = buf
if err := cmd.Start(); err != nil {
t.Errorf("start bzip2 process: %s", err)
return
}
if err := r.Write(compressStream); err != nil {
t.Errorf("pipe to bzip2 process: %s", err)
return
}
compressStream.Close()
if err := cmd.Wait(); err != nil {
t.Errorf("wait for bzip2 process: %s", err)
return
}
if _, err := ReadRules(bzip2.NewReader(bytes.NewReader(buf.Bytes()))); err != nil {
t.Errorf("read using compress/bzip2: %s", err)
return
}
}
// See https://github.com/hillu/go-yara/issues/5
func TestScanMemCgoPointer(t *testing.T) {
r := makeRules(t,
"rule test : tag1 { meta: author = \"Hilko Bengen\" strings: $a = \"abc\" fullword condition: $a }")
buf := &bytes.Buffer{}
buf.Write([]byte(" abc "))
if err := func() (p interface{}) {
defer func() { p = recover() }()
r.ScanMem(buf.Bytes(), 0, 0)
return nil
}(); err != nil {
t.Errorf("ScanMem panicked: %s", err)
}
}

84
vendor/github.com/hillu/go-yara/rules_yara34.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,84 @@
// Copyright © 2015-2016 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.
// This file contains functionality that require libyara 3.4 or higher
// +build !yara3.3
package yara
/*
#include <yara.h>
#ifdef _WIN32
int _yr_rules_scan_fd(
YR_RULES* rules,
int fd,
int flags,
YR_CALLBACK_FUNC callback,
void* user_data,
int timeout);
#else
#define _yr_rules_scan_fd yr_rules_scan_fd
#endif
size_t streamRead(void* ptr, size_t size, size_t nmemb, void* user_data);
size_t streamWrite(void* ptr, size_t size, size_t nmemb, void* user_data);
int rules_callback(int message, void *message_data, void *user_data);
*/
import "C"
import (
"io"
"runtime"
"time"
"unsafe"
)
// ScanFileDescriptor scans a file using the ruleset.
func (r *Rules) ScanFileDescriptor(fd uintptr, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
id := callbackData.Put(&matches)
defer callbackData.Delete(id)
err = newError(C._yr_rules_scan_fd(
r.cptr,
C.int(fd),
C.int(flags),
C.YR_CALLBACK_FUNC(C.rules_callback),
unsafe.Pointer(id),
C.int(timeout/time.Second)))
return
}
// Write writes a compiled ruleset to an io.Writer.
func (r *Rules) Write(wr io.Writer) (err error) {
id := callbackData.Put(wr)
defer callbackData.Delete(id)
stream := (*C.YR_STREAM)(C.malloc((C.sizeof_YR_STREAM)))
defer C.free(unsafe.Pointer(stream))
stream.user_data = unsafe.Pointer(id)
stream.write = C.YR_STREAM_WRITE_FUNC(C.streamWrite)
err = newError(C.yr_rules_save_stream(r.cptr, stream))
return
}
// ReadRules retrieves a compiled ruleset from an io.Reader
func ReadRules(rd io.Reader) (*Rules, error) {
r := &Rules{rules: &rules{}}
id := callbackData.Put(rd)
defer callbackData.Delete(id)
stream := (*C.YR_STREAM)(C.malloc((C.sizeof_YR_STREAM)))
defer C.free(unsafe.Pointer(stream))
stream.user_data = unsafe.Pointer(id)
stream.read = C.YR_STREAM_READ_FUNC(C.streamRead)
if err := newError(C.yr_rules_load_stream(stream,
&(r.rules.cptr))); err != nil {
return nil, err
}
runtime.SetFinalizer(r.rules, (*rules).finalize)
return r, nil
}

66
vendor/github.com/hillu/go-yara/stream.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,66 @@
// Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.
package yara
import (
"io"
"reflect"
"unsafe"
)
// #include <string.h>
import "C"
//export streamRead
func streamRead(ptr unsafe.Pointer, size, nmemb C.size_t, userData unsafe.Pointer) C.size_t {
if size == 0 || nmemb == 0 {
return nmemb
}
reader := callbackData.Get(uintptr(userData)).(io.Reader)
buf := make([]byte, 0)
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
hdr.Data = uintptr(ptr)
hdr.Len = int(size * nmemb)
hdr.Cap = hdr.Len
s := int(size)
for i := 0; i < int(nmemb); i++ {
if sz, err := io.ReadFull(reader, buf[i*s:(i+1)*s]); sz < int(size) && err != nil {
return C.size_t(i)
}
}
return nmemb
}
func writeFull(w io.Writer, buf []byte) (n int, err error) {
var i int
for n < len(buf) {
i, err = w.Write(buf[n:])
n += i
if err != nil {
break
}
}
return
}
//export streamWrite
func streamWrite(ptr unsafe.Pointer, size, nmemb C.size_t, userData unsafe.Pointer) C.size_t {
if size == 0 || nmemb == 0 {
return nmemb
}
writer := callbackData.Get(uintptr(userData)).(io.Writer)
buf := make([]byte, 0)
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
hdr.Data = uintptr(ptr)
hdr.Len = int(size * nmemb)
hdr.Cap = hdr.Len
s := int(size)
for i := 0; i < int(nmemb); i++ {
if sz, err := writeFull(writer, buf[i*s:(i+1)*s]); sz < int(size) && err != nil {
return C.size_t(i)
}
}
return nmemb
}

59
vendor/github.com/hillu/go-yara/stress_test.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,59 @@
package yara
import (
"fmt"
"os"
"os/user"
"path"
"path/filepath"
"sync"
"testing"
)
func TestFileWalk(t *testing.T) {
if os.ExpandEnv("${TEST_WALK}") == "" {
t.Skip("Set TEST_WALK to enable scanning files from user's HOME with a dummy ruleset.\n" +
"(Setting -test.timeout may be a good idea for this.)")
}
initialPath := os.ExpandEnv("${TEST_WALK_START}")
if initialPath == "" {
if u, err := user.Current(); err != nil {
t.Skip("Could get user's homedir. You can use TEST_WALK_START " +
"to set an initial path for filepath.Walk()")
} else {
initialPath = u.HomeDir
}
}
r, err := Compile("rule test: tag1 tag2 tag3 { meta: foo = 1 bar = \"xxx\" quux = false condition: true }", nil)
if err != nil {
t.Fatal(err)
}
wg := sync.WaitGroup{}
for i := 0; i < 32; i++ {
wg.Add(1)
go func(i int) {
filepath.Walk(initialPath, func(name string, info os.FileInfo, inErr error) error {
fmt.Printf("[%02d] %s\n", i, name)
if inErr != nil {
fmt.Printf("[%02d] Walk to \"%s\": %s\n", i, name, inErr)
return nil
}
if info.IsDir() && info.Mode()&os.ModeSymlink != 0 {
fmt.Printf("[%02d] Walk to \"%s\": Skipping symlink\n", i, name)
return filepath.SkipDir
}
if !info.Mode().IsRegular() || info.Size() >= 2000000 {
return nil
}
if m, err := r.ScanFile(name, 0, 0); err == nil {
fmt.Printf("[%02d] Scan \"%s\": %d\n", i, path.Base(name), len(m))
} else {
fmt.Printf("[%02d] Scan \"%s\": %s\n", i, path.Base(name), err)
}
return nil
})
wg.Done()
}(i)
}
wg.Wait()
}

1
vendor/github.com/hillu/go-yara/testdata/rules.yar сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
rule test : tag1 { meta: author = "Hilko Bengen" strings: $a = "abc" fullword condition: $a }

31
vendor/github.com/hillu/go-yara/util.go сгенерированный поставляемый Normal file
Просмотреть файл

@ -0,0 +1,31 @@
// Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.
package yara
func toint64(number interface{}) int64 {
switch number.(type) {
case int:
return int64(number.(int))
case int8:
return int64(number.(int8))
case int16:
return int64(number.(int16))
case int32:
return int64(number.(int32))
case int64:
return int64(number.(int64))
case uint:
return int64(number.(uint))
case uint8:
return int64(number.(uint8))
case uint16:
return int64(number.(uint16))
case uint32:
return int64(number.(uint32))
case uint64:
return int64(number.(uint64))
}
panic("wrong number")
}