commit fd3fd7ea3637f9fe370130b666dc102d79f6bfcd Author: stellarbears Date: Sun Apr 8 16:37:39 2018 +0300 Добавьте файлы проекта. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c4efe2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,261 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/YaraSharp.sln b/YaraSharp.sln new file mode 100644 index 0000000..80989af --- /dev/null +++ b/YaraSharp.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YaraSharp", "YaraSharp\YaraSharp.vcxproj", "{C005E3B9-2474-4FEA-B5F4-7BB897111E8F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libyara", "yara-master\windows\vs2015\libyara\libyara.vcxproj", "{E236CE39-D8F3-4DB6-985C-F2794FF17746}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F}.Debug|x64.ActiveCfg = Debug|x64 + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F}.Debug|x64.Build.0 = Debug|x64 + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F}.Debug|x86.ActiveCfg = Debug|Win32 + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F}.Debug|x86.Build.0 = Debug|Win32 + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F}.Release|x64.ActiveCfg = Release|x64 + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F}.Release|x64.Build.0 = Release|x64 + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F}.Release|x86.ActiveCfg = Release|Win32 + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F}.Release|x86.Build.0 = Release|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x64.ActiveCfg = Debug|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x64.Build.0 = Debug|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x86.ActiveCfg = Debug|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x86.Build.0 = Debug|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x64.ActiveCfg = Release|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x64.Build.0 = Release|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x86.ActiveCfg = Release|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {246FEDB8-B2A1-4051-85E1-F39A6026767B} + EndGlobalSection +EndGlobal diff --git a/YaraSharp/AssemblyInfo.cpp b/YaraSharp/AssemblyInfo.cpp new file mode 100644 index 0000000..f2e0a51 --- /dev/null +++ b/YaraSharp/AssemblyInfo.cpp @@ -0,0 +1,38 @@ +#include "stdafx.h" + +using namespace System; +using namespace System::Reflection; +using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly:AssemblyTitleAttribute(L"YaraSharp")]; +[assembly:AssemblyDescriptionAttribute(L"")]; +[assembly:AssemblyConfigurationAttribute(L"")]; +[assembly:AssemblyCompanyAttribute(L"")]; +[assembly:AssemblyProductAttribute(L"YaraSharp")]; +[assembly:AssemblyCopyrightAttribute(L"Copyright (c) 2018")]; +[assembly:AssemblyTrademarkAttribute(L"")]; +[assembly:AssemblyCultureAttribute(L"")]; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the value or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly:AssemblyVersionAttribute("1.0.*")]; + +[assembly:ComVisible(false)]; + +[assembly:CLSCompliantAttribute(true)]; \ No newline at end of file diff --git a/YaraSharp/Compiler.cpp b/YaraSharp/Compiler.cpp new file mode 100644 index 0000000..e6d10f8 --- /dev/null +++ b/YaraSharp/Compiler.cpp @@ -0,0 +1,100 @@ +#include "Stdafx.h" + +// CCompiler +namespace YaraSharp +{ + // + CCompiler::CCompiler(Dictionary^ ExternalVariables) + { + YR_COMPILER* TestCompiler; + ErrorUtility::ThrowOnError(yr_compiler_create(&TestCompiler)); + Compiler = TestCompiler; + + Errors = gcnew List(); + + CompilerCallback = gcnew YaraCompilerCallback(this, &CCompiler::HandleCompilerCallback); + auto funcPtr = Marshal::GetFunctionPointerForDelegate(CompilerCallback).ToPointer(); + yr_compiler_set_callback(Compiler, static_cast(funcPtr), nullptr); + + SetCompilerExternals(ExternalVariables); + } + // + CCompiler::~CCompiler() { if (Compiler) yr_compiler_destroy(Compiler); } + + // + int CCompiler::AddFile(String^ FilePath) + { + FILE* File; + Errors->Clear(); + auto NativePath = marshal_as(FilePath); + + auto FileOpenError = fopen_s(&File, NativePath.c_str(), "r"); + + if (FileOpenError) + ErrorUtility::ThrowOnError(String::Format(" : {0}", FileOpenError)); + + auto errors = yr_compiler_add_file(Compiler, File, nullptr, NativePath.c_str()); + + if (File) fclose(File); + + return errors; + } + // + void CCompiler::AddFiles(List^ FilePathList) + { + for each (auto FilePath in FilePathList) + AddFile(FilePath); + } + // + CRules^ CCompiler::GetRules() + { + YR_RULES* Rules; + + ErrorUtility::ThrowOnError( + yr_compiler_get_rules(Compiler, &Rules)); + + return gcnew CRules(Rules); + } + // externals + void CCompiler::SetCompilerExternals(Dictionary^ ExternalVariables) + { + if (ExternalVariables) + { + marshal_context CTX; + + for each (auto ExternalVariable in ExternalVariables) + { + const char* VariablePointer = CTX.marshal_as(ExternalVariable.Key); + Type^ VariableType = ExternalVariable.Value->GetType(); + int ExternalError = ERROR_SUCCESS; + + if (VariableType == Boolean::typeid) + ExternalError = yr_compiler_define_boolean_variable(Compiler, VariablePointer, (bool)ExternalVariable.Value); + else if (VariableType == Double::typeid) + ExternalError = yr_compiler_define_float_variable(Compiler, VariablePointer, (double)ExternalVariable.Value); + else if (VariableType == Int64::typeid || VariableType == Int32::typeid) + ExternalError = yr_compiler_define_integer_variable(Compiler, VariablePointer, (Int64)ExternalVariable.Value); + else if (VariableType == String::typeid) + ExternalError = yr_compiler_define_string_variable(Compiler, VariablePointer, CTX.marshal_as((String^)ExternalVariable.Value)); + else + throw gcnew NotSupportedException(String::Format(" external variable: '{0}'", VariableType->Name)); + + if (ExternalError != ERROR_SUCCESS) + ErrorUtility::ThrowOnError("(Compiler) external variable"); + } + } + } + + // + void CCompiler::HandleCompilerCallback(int ErrorLevel, const char* Filename, int LineNumber, const char* Message, void* UserData) + { + UNREFERENCED_PARAMETER(ErrorLevel); + UNREFERENCED_PARAMETER(UserData); + + auto msg = String::Format("{0} {1} : {2}", + marshal_as(Message), LineNumber, + Filename ? marshal_as(Filename) : "[none]"); + + Errors->Add(msg); + } +} \ No newline at end of file diff --git a/YaraSharp/Compiler.h b/YaraSharp/Compiler.h new file mode 100644 index 0000000..c5b8515 --- /dev/null +++ b/YaraSharp/Compiler.h @@ -0,0 +1,26 @@ +#pragma once + +namespace YaraSharp +{ + [UnmanagedFunctionPointer(CallingConvention::Cdecl)] + delegate void YaraCompilerCallback(int ErrorLevel, const char* Filename, int LineNumber, const char* Message, void* UserData); + + public ref class CCompiler sealed + { + public: + initonly YR_COMPILER* Compiler; + initonly List^ Errors; + YaraCompilerCallback ^ CompilerCallback; + + CCompiler(Dictionary^ ExternalVariables); + ~CCompiler(); + + CRules^ GetRules(); + int AddFile(String^ FilePath); + void AddFiles(List^ FilePathList); + + private: + void SetCompilerExternals(Dictionary^ ExternalVariables); + void HandleCompilerCallback(int ErrorLevel, const char* Filename, int LineNumber, const char* Message, void* UserData); + }; +} \ No newline at end of file diff --git a/YaraSharp/Context.cpp b/YaraSharp/Context.cpp new file mode 100644 index 0000000..6303df6 --- /dev/null +++ b/YaraSharp/Context.cpp @@ -0,0 +1,10 @@ +#include "Stdafx.h" + +// CContext +namespace YaraSharp +{ + // + CContext::CContext() { ErrorUtility::ThrowOnError(yr_initialize()); } + // + CContext::~CContext() { ErrorUtility::ThrowOnError(yr_finalize()); } +} \ No newline at end of file diff --git a/YaraSharp/Context.h b/YaraSharp/Context.h new file mode 100644 index 0000000..ca2de1d --- /dev/null +++ b/YaraSharp/Context.h @@ -0,0 +1,11 @@ +#pragma once + +namespace YaraSharp +{ + public ref class CContext sealed + { + public: + CContext(); + ~CContext(); + }; +} \ No newline at end of file diff --git a/YaraSharp/Exceptions.cpp b/YaraSharp/Exceptions.cpp new file mode 100644 index 0000000..2cc8289 --- /dev/null +++ b/YaraSharp/Exceptions.cpp @@ -0,0 +1,128 @@ +#include "Stdafx.h" + +// ErrorUtility +namespace YaraSharp +{ + void ErrorUtility::ThrowOnError(int error) + { + switch (error) + { + case ERROR_SUCCESS: + return; + + case ERROR_INSUFICIENT_MEMORY: + throw gcnew OutOfMemoryException(); + + default: + throw gcnew Exception(String::Format("Yara error: {0}. Code {1}", NiceErrorCode(error), error)); + } + } + void ErrorUtility::ThrowOnError(String^ error) + { + throw gcnew Exception(String::Format("Error: {0}", error)); + } + + String^ ErrorUtility::NiceErrorCode(int error) + { + // TODO: + switch (error) + { + case ERROR_INSUFICIENT_MEMORY: + return "ERROR_INSUFICIENT_MEMORY"; + case ERROR_COULD_NOT_ATTACH_TO_PROCESS: + return "COULD_NOT_ATTACH_TO_PROCESS"; + case ERROR_COULD_NOT_OPEN_FILE: + return "ERROR_COULD_NOT_OPEN_FILE"; + case ERROR_COULD_NOT_MAP_FILE: + return "ERROR_COULD_NOT_MAP_FILE"; + case ERROR_INVALID_FILE: + return "ERROR_INVALID_FILE"; + case ERROR_CORRUPT_FILE: + return "ERROR_CORRUPT_FILE"; + case ERROR_UNSUPPORTED_FILE_VERSION: + return "ERROR_UNSUPPORTED_FILE_VERSION"; + case ERROR_INVALID_REGULAR_EXPRESSION: + return "ERROR_INVALID_REGULAR_EXPRESSION"; + case ERROR_INVALID_HEX_STRING: + return "ERROR_INVALID_HEX_STRING"; + case ERROR_SYNTAX_ERROR: + return "ERROR_SYNTAX_ERROR"; + case ERROR_LOOP_NESTING_LIMIT_EXCEEDED: + return "ERROR_LOOP_NESTING_LIMIT_EXCEEDED"; + case ERROR_DUPLICATED_LOOP_IDENTIFIER: + return "ERROR_DUPLICATED_LOOP_IDENTIFIER"; + case ERROR_DUPLICATED_IDENTIFIER: + return "ERROR_DUPLICATED_IDENTIFIER"; + case ERROR_DUPLICATED_TAG_IDENTIFIER: + return "ERROR_DUPLICATED_TAG_IDENTIFIER"; + case ERROR_DUPLICATED_META_IDENTIFIER: + return "ERROR_DUPLICATED_META_IDENTIFIER"; + case ERROR_DUPLICATED_STRING_IDENTIFIER: + return "ERROR_DUPLICATED_STRING_IDENTIFIER"; + case ERROR_UNREFERENCED_STRING: + return "ERROR_UNREFERENCED_STRING"; + case ERROR_UNDEFINED_STRING: + return "ERROR_UNDEFINED_STRING"; + case ERROR_UNDEFINED_IDENTIFIER: + return "ERROR_UNDEFINED_IDENTIFIER"; + case ERROR_MISPLACED_ANONYMOUS_STRING: + return "ERROR_MISPLACED_ANONYMOUS_STRING"; + case ERROR_INCLUDES_CIRCULAR_REFERENCE: + return "ERROR_INCLUDES_CIRCULAR_REFERENCE"; + case ERROR_INCLUDE_DEPTH_EXCEEDED: + return "ERROR_INCLUDE_DEPTH_EXCEEDED"; + case ERROR_WRONG_TYPE: + return "ERROR_WRONG_TYPE"; + case ERROR_EXEC_STACK_OVERFLOW: + return "ERROR_EXEC_STACK_OVERFLOW"; + case ERROR_SCAN_TIMEOUT: + return "ERROR_SCAN_TIMEOUT"; + case ERROR_TOO_MANY_SCAN_THREADS: + return "ERROR_TOO_MANY_SCAN_THREADS"; + case ERROR_CALLBACK_ERROR: + return "ERROR_CALLBACK_ERROR"; + case ERROR_INVALID_ARGUMENT: + return "ERROR_INVALID_ARGUMENT"; + case ERROR_TOO_MANY_MATCHES: + return "ERROR_TOO_MANY_MATCHES"; + case ERROR_INTERNAL_FATAL_ERROR: + return "ERROR_INTERNAL_FATAL_ERROR"; + case ERROR_NESTED_FOR_OF_LOOP: + return "ERROR_NESTED_FOR_OF_LOOP"; + case ERROR_INVALID_FIELD_NAME: + return "ERROR_INVALID_FIELD_NAME"; + case ERROR_UNKNOWN_MODULE: + return "ERROR_UNKNOWN_MODULE"; + case ERROR_NOT_A_STRUCTURE: + return "ERROR_NOT_A_STRUCTURE"; + case ERROR_NOT_INDEXABLE: + return "ERROR_NOT_INDEXABLE"; + case ERROR_NOT_A_FUNCTION: + return "ERROR_NOT_A_FUNCTION"; + case ERROR_INVALID_FORMAT: + return "ERROR_INVALID_FORMAT"; + case ERROR_TOO_MANY_ARGUMENTS: + return "ERROR_TOO_MANY_ARGUMENTS"; + case ERROR_WRONG_ARGUMENTS: + return "ERROR_WRONG_ARGUMENTS"; + case ERROR_WRONG_RETURN_TYPE: + return "ERROR_WRONG_RETURN_TYPE"; + case ERROR_DUPLICATED_STRUCTURE_MEMBER: + return "ERROR_DUPLICATED_STRUCTURE_MEMBER"; + case ERROR_EMPTY_STRING: + return "ERROR_EMPTY_STRING"; + case ERROR_DIVISION_BY_ZERO: + return "ERROR_DIVISION_BY_ZERO"; + case ERROR_REGULAR_EXPRESSION_TOO_LARGE: + return "ERROR_REGULAR_EXPRESSION_TOO_LARGE"; + case ERROR_TOO_MANY_RE_FIBERS: + return "ERROR_TOO_MANY_RE_FIBERS"; + case ERROR_COULD_NOT_READ_PROCESS_MEMORY: + return "ERROR_COULD_NOT_READ_PROCESS_MEMORY"; + case ERROR_INVALID_EXTERNAL_VARIABLE_TYPE: + return "ERROR_INVALID_EXTERNAL_VARIABLE_TYPE"; + default: + return "UNKNOWN"; + } + } +} diff --git a/YaraSharp/Exceptions.h b/YaraSharp/Exceptions.h new file mode 100644 index 0000000..5481fbc --- /dev/null +++ b/YaraSharp/Exceptions.h @@ -0,0 +1,14 @@ +#pragma once + +namespace YaraSharp +{ + public ref class ErrorUtility abstract sealed + { + private: + static String^ NiceErrorCode(int error); + + public: + static void ThrowOnError(int error); + static void ThrowOnError(String^ error); + }; +} diff --git a/YaraSharp/Result.cpp b/YaraSharp/Result.cpp new file mode 100644 index 0000000..a365ddb --- /dev/null +++ b/YaraSharp/Result.cpp @@ -0,0 +1,61 @@ +#include "Stdafx.h" + +// CMatches +namespace YaraSharp +{ + CMatches::CMatches() + { + Rule = nullptr; + Matches = gcnew Dictionary^>(); + } + + CMatches::CMatches(YR_RULE * MatchingRule) + { + Rule = gcnew CRule(MatchingRule); + Matches = gcnew Dictionary^>(); + + YR_STRING* StringEntry; + YR_MATCH* MatchEntry; + + yr_rule_strings_foreach(MatchingRule, StringEntry) + { + auto identifier = marshal_as(StringEntry->identifier); + + yr_string_matches_foreach(StringEntry, MatchEntry) + { + if (!Matches->ContainsKey(identifier)) + Matches->Add(identifier, gcnew List()); + + Matches[identifier]->Add(gcnew CMatch(MatchEntry)); + } + } + } +} + +// CMatch +namespace YaraSharp +{ + CMatch::CMatch() + { + Base = 0; + Offset = 0; + Data = gcnew array(0); + } + + CMatch::CMatch(YR_MATCH* Match) + { + /* + int64_t base; // Base address for the match + int64_t offset; // Offset relative to base for the match + int32_t match_length; // Match length + int32_t data_length; + const uint8_t* data; + */ + + Base = Match->base; + Offset = Match->offset; + + Data = gcnew array(Match->match_length); + Marshal::Copy(IntPtr((void *)Match->data), Data, 0, Match->data_length); + } +} \ No newline at end of file diff --git a/YaraSharp/Result.h b/YaraSharp/Result.h new file mode 100644 index 0000000..b7d59c6 --- /dev/null +++ b/YaraSharp/Result.h @@ -0,0 +1,27 @@ +#pragma once + +namespace YaraSharp +{ + public ref class CMatch sealed + { + public: + + property uint64_t Base; + property uint64_t Offset; + property array^ Data; + + CMatch(); + CMatch(YR_MATCH* Match); + }; + + public ref class CMatches sealed + { + public: + + property CRule^ Rule; + property Dictionary^>^ Matches; + + CMatches(); + CMatches(YR_RULE* MatchingRule); + }; +} \ No newline at end of file diff --git a/YaraSharp/Rules.cpp b/YaraSharp/Rules.cpp new file mode 100644 index 0000000..3ed6e57 --- /dev/null +++ b/YaraSharp/Rules.cpp @@ -0,0 +1,83 @@ +#include "Stdafx.h" + +// CRules +namespace YaraSharp +{ + CRules::operator YR_RULES*() { return Rules; } + CRules::CRules(YR_RULES* rules) : Rules(rules) { } + CRules::~CRules() { if (Rules) yr_rules_destroy(Rules); } +} +// CRule +namespace YaraSharp +{ + CRule::CRule() + { + Namespace = nullptr; + Identifier = nullptr; + Tags = gcnew List(); + // Strings = gcnew List(); + Meta = gcnew Dictionary(); + } + CRule::CRule(YR_RULE* Rule) + { + Namespace = nullptr; + Tags = CRule::GetRuleTags(Rule); + Meta = CRule::GetRuleMeta(Rule); + // Strings = CRule::GetRuleStrings(Rule); + Identifier = gcnew String(Rule->identifier); + } + + List^ CRule::GetRuleTags(YR_RULE* Rule) + { + List^ Result = gcnew List(); + + const char* TagEntry; + yr_rule_tags_foreach(Rule, TagEntry) + Result->Add(gcnew String(TagEntry)); + + return Result; + } + List^ CRule::GetRuleStrings(YR_RULE* Rule) + { + List^ Result = gcnew List(); + + YR_STRING* StringEntry; + yr_rule_strings_foreach(Rule, StringEntry) + Result->Add(gcnew String(StringEntry->identifier)); + + return Result; + } + Dictionary^ CRule::GetRuleMeta(YR_RULE* Rule) + { + Dictionary^ Result = gcnew Dictionary(); + + YR_META* MetaEntry; + yr_rule_metas_foreach(Rule, MetaEntry) + { + if (MetaEntry->identifier == NULL) + throw gcnew NullReferenceException("(Meta) "); + + String^ MetaID = gcnew String(MetaEntry->identifier); + Object^ MetaValue = nullptr; + + switch (MetaEntry->type) + { + case META_TYPE_BOOLEAN: + MetaValue = (bool)(MetaEntry->integer == 1); + break; + case META_TYPE_INTEGER: + MetaValue = (Int32)MetaEntry->integer; + break; + case META_TYPE_STRING: + MetaValue = gcnew String(MetaEntry->string); + break; + } + + // + if (!Result->ContainsKey(MetaID)) + Result->Add(MetaID, MetaValue); + } + + return Result; + } +} \ No newline at end of file diff --git a/YaraSharp/Rules.h b/YaraSharp/Rules.h new file mode 100644 index 0000000..7520082 --- /dev/null +++ b/YaraSharp/Rules.h @@ -0,0 +1,35 @@ +#pragma once + +namespace YaraSharp +{ + public ref class CRules sealed + { + YR_RULES* Rules; + + public: + CRules(YR_RULES* rules); + operator YR_RULES*(); + ~CRules(); + }; + + + public ref class CRule sealed + { + public: + property String^ Namespace; + property String^ Identifier; + property List^ Tags; + property Dictionary^ Meta; + // property List^ Strings; + // , Match , + // + + CRule(); + CRule(YR_RULE* Rule); + + private: + List^ CRule::GetRuleTags(YR_RULE* Rule); + List^ CRule::GetRuleStrings(YR_RULE* Rule); + Dictionary^ CRule::GetRuleMeta(YR_RULE* Rule); + }; +} diff --git a/YaraSharp/Scanner.cpp b/YaraSharp/Scanner.cpp new file mode 100644 index 0000000..a67258f --- /dev/null +++ b/YaraSharp/Scanner.cpp @@ -0,0 +1,65 @@ +#include "Stdafx.h" + +// CScanner +namespace YaraSharp +{ + // + CScanner::CScanner(CRules^ rules, Dictionary^ ExternalVariables) + { + YR_SCANNER* TestScanner; + ErrorUtility::ThrowOnError(yr_scanner_create((YR_RULES*)rules, &TestScanner)); + Scanner = TestScanner; + + ScanCallback = gcnew YaraScanCallback(this, &CScanner::HandleScannerCallback); + auto funcPtr = Marshal::GetFunctionPointerForDelegate(ScanCallback).ToPointer(); + yr_scanner_set_callback(Scanner, static_cast(funcPtr), nullptr); + + SetScannerExternals(ExternalVariables); + } + // + CScanner::~CScanner() { if (Scanner) yr_scanner_destroy(Scanner); } + + // externals + void CScanner::SetScannerExternals(Dictionary^ ExternalVariables) + { + if (ExternalVariables) + { + marshal_context CTX; + + for each (auto ExternalVariable in ExternalVariables) + { + const char* VariablePointer = CTX.marshal_as(ExternalVariable.Key); + Type^ VariableType = ExternalVariable.Value->GetType(); + int ExternalError = ERROR_SUCCESS; + + if (VariableType == Boolean::typeid) + ExternalError = yr_scanner_define_boolean_variable(Scanner, VariablePointer, (bool)ExternalVariable.Value); + else if (VariableType == Double::typeid) + ExternalError = yr_scanner_define_float_variable(Scanner, VariablePointer, (double)ExternalVariable.Value); + else if (VariableType == Int64::typeid || VariableType == Int32::typeid) + ExternalError = yr_scanner_define_integer_variable(Scanner, VariablePointer, (Int64)ExternalVariable.Value); + else if (VariableType == String::typeid) + ExternalError = yr_scanner_define_string_variable(Scanner, VariablePointer, CTX.marshal_as((String^)ExternalVariable.Value)); + else + throw gcnew NotSupportedException(String::Format(" external variable: '{0}'", VariableType->Name)); + + if (ExternalError != ERROR_SUCCESS) + ErrorUtility::ThrowOnError("(Scanner) external variable"); + } + } + } + + // + int CScanner::HandleScannerCallback(int message, void* data, void* context) + { + if (message == CALLBACK_MSG_RULE_MATCHING) + { + auto resultsHandle = GCHandle::FromIntPtr(IntPtr(context)); + auto results = (List^)resultsHandle.Target; + + results->Add(gcnew CMatches((YR_RULE*)data)); + } + + return CALLBACK_CONTINUE; + } +} \ No newline at end of file diff --git a/YaraSharp/Scanner.h b/YaraSharp/Scanner.h new file mode 100644 index 0000000..b30dd4d --- /dev/null +++ b/YaraSharp/Scanner.h @@ -0,0 +1,21 @@ +#pragma once + +namespace YaraSharp +{ + [UnmanagedFunctionPointer(CallingConvention::Cdecl)] + delegate int YaraScanCallback(int Message, void* Data, void* Context); + + public ref class CScanner sealed + { + public: + YR_SCANNER * Scanner; + YaraScanCallback^ ScanCallback; + + CScanner(CRules^ rules, Dictionary^ ExternalVariables); + ~CScanner(); + + private: + void SetScannerExternals(Dictionary^ ExternalVariables); + int HandleScannerCallback(int Message, void* Data, void* Context); + }; +} \ No newline at end of file diff --git a/YaraSharp/Stdafx.cpp b/YaraSharp/Stdafx.cpp new file mode 100644 index 0000000..5ebf4a1 --- /dev/null +++ b/YaraSharp/Stdafx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : source file that includes just the standard includes +// YaraSharp.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/YaraSharp/Stdafx.h b/YaraSharp/Stdafx.h new file mode 100644 index 0000000..38490b5 --- /dev/null +++ b/YaraSharp/Stdafx.h @@ -0,0 +1,24 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#pragma once +#include +#include +#include + +using namespace System; +using namespace System::IO; +using namespace System::Text; +using namespace msclr::interop; +using namespace System::Collections::Generic; +using namespace System::Runtime::InteropServices; + +#include "yara.h" +#include "Exceptions.h" +#include "Context.h" +#include "Rules.h" +#include "Compiler.h" +#include "Result.h" +#include "Scanner.h" +#include "YaraSharp.h" \ No newline at end of file diff --git a/YaraSharp/YaraExternal.h b/YaraSharp/YaraExternal.h new file mode 100644 index 0000000..28292d6 --- /dev/null +++ b/YaraSharp/YaraExternal.h @@ -0,0 +1,7 @@ +#pragma once +public ref class YaraExternal +{ +public: + YaraExternal(); +}; + diff --git a/YaraSharp/YaraSharp.cpp b/YaraSharp/YaraSharp.cpp new file mode 100644 index 0000000..ee9a891 --- /dev/null +++ b/YaraSharp/YaraSharp.cpp @@ -0,0 +1,119 @@ +#include "Stdafx.h" + +// CMatches +namespace YaraSharp +{ + // + Dictionary^>^ CYaraSharp::CheckYaraRules([Out] List^ FilePathList, Dictionary^ ExternalVariables) + { + Dictionary^>^ CompilationErrors = + gcnew Dictionary^>(); + + // + for (int i = 0; i < FilePathList->Count; i++) + { + CCompiler^ TestCompiler = gcnew CCompiler(ExternalVariables); + + if (TestCompiler->AddFile(FilePathList[i])) + { + CompilationErrors->Add(FilePathList[i], TestCompiler->Errors); + FilePathList->Remove(FilePathList[i--]); + } + } + + // + bool SuccessFlag = false; + while (!SuccessFlag) + { + SuccessFlag = true; + CCompiler^ TestCompiler = gcnew CCompiler(ExternalVariables); + for each (auto FilePath in FilePathList) + { + if (TestCompiler->AddFile(FilePath)) + { + CompilationErrors->Add(FilePath, TestCompiler->Errors); + FilePathList->Remove(FilePath); + SuccessFlag = false; + + // + break; + } + } + } + + return CompilationErrors; + } + // + CRules^ CYaraSharp::CompileFromFiles(CCompiler^ Compiler, List^ FilePathList, Dictionary^ ExternalVariables, + [Out] Dictionary^>^% CompilationErrors) + { + // TODO: namespace + + // + CompilationErrors = CheckYaraRules(FilePathList, ExternalVariables); + + // + Compiler->AddFiles(FilePathList); + + // + return Compiler->GetRules(); + } + + // + List^ CYaraSharp::ScanFile(String^ Path, CRules^ Rules, Dictionary^ ExternalVariables, int Timeout) + { + CScanner^ FScanner = gcnew CScanner(Rules, ExternalVariables); + + if (!File::Exists(Path)) + throw gcnew FileNotFoundException(Path); + + auto results = gcnew List(); + auto nativePath = marshal_as(Path); + GCHandle resultsHandle = GCHandle::Alloc(results); + + ErrorUtility::ThrowOnError( + yr_rules_scan_file(Rules, nativePath.c_str(), 0, FScanner->Scanner->callback, + GCHandle::ToIntPtr(resultsHandle).ToPointer(), Timeout)); + + return results; + } + // + List^ CYaraSharp::ScanProcess(int PID, CRules^ Rules, int Timeout, Dictionary^ ExternalVariables) + { + CScanner^ PScanner = gcnew CScanner(Rules, ExternalVariables); + + auto results = gcnew List(); + GCHandle resultsHandle = GCHandle::Alloc(results); + + ErrorUtility::ThrowOnError( + yr_rules_scan_proc(Rules, PID, 0, PScanner->Scanner->callback, + GCHandle::ToIntPtr(resultsHandle).ToPointer(), Timeout)); + + return results; + } + // + List^ CYaraSharp::ScanMemory(array^ Buffer, CRules^ Rules, Dictionary^ ExternalVariables, int Timeout) + { + if (Buffer == nullptr || Buffer->Length == 0) + return gcnew List(); + else + { + pin_ptr BufferPointer = &Buffer[0]; + return ScanMemory(BufferPointer, Buffer->Length, Rules, ExternalVariables, Timeout); + } + } + // + List^ CYaraSharp::ScanMemory(uint8_t* Buffer, int Length, CRules^ Rules, Dictionary^ ExternalVariables, int Timeout) + { + CScanner^ MScanner = gcnew CScanner(Rules, ExternalVariables); + + auto results = gcnew List(); + GCHandle resultsHandle = GCHandle::Alloc(results); + + ErrorUtility::ThrowOnError( + yr_rules_scan_mem(Rules, Buffer, Length, 0, MScanner->Scanner->callback, + GCHandle::ToIntPtr(resultsHandle).ToPointer(), Timeout)); + + return results; + } +} \ No newline at end of file diff --git a/YaraSharp/YaraSharp.h b/YaraSharp/YaraSharp.h new file mode 100644 index 0000000..190eec2 --- /dev/null +++ b/YaraSharp/YaraSharp.h @@ -0,0 +1,24 @@ +#pragma once + +namespace YaraSharp +{ + public ref class CYaraSharp + { + private: + // + Dictionary^>^ CheckYaraRules(List^ FilePathList, Dictionary^ ExternalVariables); + + public: + // + CRules^ CompileFromFiles(CCompiler^ Compiler, + List^ FilePathList, + Dictionary^ ExternalVariables, + [Out] Dictionary^>^% CompilationErrors); + + // + List^ ScanFile(String^ Path, CRules^ Rules, Dictionary^ ExternalVariables, int Timeout); + List^ ScanProcess(int PID, CRules^ Rules, int Timeout, Dictionary^ ExternalVariables); + List^ ScanMemory(array^ Buffer, CRules^ Rules, Dictionary^ ExternalVariables, int Timeout); + List^ ScanMemory(uint8_t* Buffer, int Length, CRules^ Rules, Dictionary^ ExternalVariables, int Timeout); + }; +} \ No newline at end of file diff --git a/YaraSharp/YaraSharp.vcxproj b/YaraSharp/YaraSharp.vcxproj new file mode 100644 index 0000000..2fba30f --- /dev/null +++ b/YaraSharp/YaraSharp.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {C005E3B9-2474-4FEA-B5F4-7BB897111E8F} + v4.5 + ManagedCProj + YaraNET + 8.1 + + + + DynamicLibrary + true + v141 + true + Unicode + + + DynamicLibrary + true + v141 + true + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)Build\$(Configuration)\x86\ + $(MSBuildProjectDirectory)\Configuration\x86\ + + + true + $(SolutionDir)Build\$(Configuration)\$(Platform)\ + $(MSBuildProjectDirectory)\Configuration\$(Platform)\ + + + false + $(SolutionDir)Build\$(Configuration)\x86\ + $(MSBuildProjectDirectory)\Configuration\x86\ + + + false + $(SolutionDir)Build\$(Configuration)\$(Platform)\ + $(MSBuildProjectDirectory)\Configuration\$(Platform)\ + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + $(SolutionDir)yara-master\libyara\include + + + true + $(SolutionDir)yara-master\windows\vs2015\libyara\Debug;%(AdditionalLibraryDirectories) + libyara32.lib;%(AdditionalDependencies) + $(SolutionDir)Build\$(Configuration)\$(PlatformTarget)\$(TargetName)$(TargetExt) + + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + $(SolutionDir)yara-master\libyara\include + + + true + $(SolutionDir)Build\$(Configuration)\$(PlatformTarget)\$(TargetName)$(TargetExt) + $(SolutionDir)yara-master\windows\vs2015\libyara\Debug;%(AdditionalLibraryDirectories) + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + $(SolutionDir)yara-master\libyara\include + + + true + $(SolutionDir)Build\$(Configuration)\$(PlatformTarget)\$(TargetName)$(TargetExt) + $(SolutionDir)yara-master\windows\vs2015\libyara\Release;%(AdditionalLibraryDirectories) + libyara32.lib;%(AdditionalDependencies) + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + $(SolutionDir)yara-master\libyara\include + + + true + $(SolutionDir)Build\$(Configuration)\$(PlatformTarget)\$(TargetName)$(TargetExt) + $(SolutionDir)yara-master\windows\vs2015\libyara\Release;%(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + \ No newline at end of file diff --git a/YaraSharp/YaraSharp.vcxproj.filters b/YaraSharp/YaraSharp.vcxproj.filters new file mode 100644 index 0000000..21b4d0a --- /dev/null +++ b/YaraSharp/YaraSharp.vcxproj.filters @@ -0,0 +1,68 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/YaraSharp/packages.config b/YaraSharp/packages.config new file mode 100644 index 0000000..207005b --- /dev/null +++ b/YaraSharp/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/yara-master/.gitignore b/yara-master/.gitignore new file mode 100644 index 0000000..e105bea --- /dev/null +++ b/yara-master/.gitignore @@ -0,0 +1,84 @@ +# Generic auto-generated build files +*~ +*.a +*.la +*.lai +*.lo +*.Plo +*.Po +*.o +*.so +*.so.[0-9][0-9]* +*.so.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]* +*.Tpo +*.m4 +*.dSYM +.deps +.libs +INSTALL +Makefile +Makefile.in +stamp-h1 + +# Specific auto-generated build files +/ABOUT-NLS +/aclocal.m4 +/ar-lib +/autom4te.cache/ +/build-aux +/compile +/config.guess +/config.h +/config.h.in +/config.log +/config.rpath +/config.status +/config.sub +/configure +/depcomp +/install-sh +/libtool +/ltmain.sh +/missing +/test-driver +/ylwrap +/m4 +!/m4/acx_pthread.m4 + +# Project specific files +/yara +/yarac +/libyara/modules/.dirstamp + +# Linux and Mac files +*.swp +.DS_Store + +# Files generated by tests +test-alignment +test-alignment.log +test-alignment.trs +test-rules +test-rules.log +test-rules.trs +test-suite.log +test-pe +test-pe.log +test-pe.trs +test-macho +test-macho.log +test-macho.trs + +# Visual Studio files +Release/ +Debug/ +x64/ +*.obj +*.suo +*.sdf +*.opendb +*.opensdf +*.VC.db + +# NuGet +windows/*/packages/ diff --git a/yara-master/.travis.yml b/yara-master/.travis.yml new file mode 100644 index 0000000..50c69c4 --- /dev/null +++ b/yara-master/.travis.yml @@ -0,0 +1,80 @@ +language: c + +matrix: + include: + - os: linux + dist: trusty + sudo: required + env: CONFIGFLAGS="CFLAGS=-m64 --enable-cuckoo --enable-magic" + # The certificate for scan.coverity.com is too new and is not recognized by + # wget. This command adds the certificate to /etc/ssl/certs/ca-certificates.crt + # See: https://github.com/travis-ci/travis-ci/issues/6142 + before_install: echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-certificates.crt + install: | + sudo apt-get update + sudo apt-get install -y autoconf automake libtool libjansson-dev libmagic-dev libssl-dev + - os: linux + dist: trusty + sudo: required + env: CONFIGFLAGS="CFLAGS=-m32 --enable-cuckoo --enable-magic" + install: | + sudo dpkg --add-architecture i386 && sudo rm -rf /etc/apt/sources.list.d/ + sudo apt-get update + sudo apt-get remove postgresql-9.3 + sudo apt-get upgrade -y gcc + sudo apt-get install -y gcc-multilib autoconf automake libtool libjansson-dev:i386 libmagic-dev:i386 libssl-dev:i386 + - os: linux + dist: trusty + sudo: required + env: CONFIGFLAGS=--host=x86_64-w64-mingw32 + install: | + sudo apt-get update + sudo apt-get install -y gcc-mingw-w64 autoconf automake libtool + - os: linux + dist: trusty + sudo: required + env: CONFIGFLAGS=--host=i686-w64-mingw32 + install: | + sudo apt-get update + sudo apt-get install -y gcc-mingw-w64 autoconf automake libtool + - os: osx + osx_image: xcode7.3 + - os: osx + osx_image: xcode8.3 + - os: osx + osx_image: xcode9.2 + +before_script: ./bootstrap.sh + +script: | + rvm get head # Workaround for Travis CI issue https://github.com/travis-ci/travis-ci/issues/6307 + set -e + unset CC # A pre-set CC overrides --host settings. + ./configure $CONFIGFLAGS + make clean && make + case "$CONFIGFLAGS" in + *--host=*mingw*) ;; + *) make check ;; + esac + set +e + +after_failure: if [ -e test-suite.log ]; then cat test-suite.log; fi + +env: + global: + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "JWobvJ94pWt/xVciQURkNFS3I+gyu2IyZPKYEs6HDlHrpHs4BoVDZeRjmgx0s6aDeQjKJHowGDu17IlbnCkKzXrZErEJkA+Oc/d0SwgXKiUU9WYiaGBJjJUoYZw66QIEuGGKkF4uQ7EIcW/vN7wzrCDyAiPeOPUjVP4Tc2XRzmkSfakfmf9cE5nqT84DPUYiRegM7iepMrZi9kEaAoboBuETT+6eUKdERRadM0QNjZmCYMEMjtFj3lE51Ey2stGqZdKJvJN0FUmxGoaXCFFAsNmZPnFeDkqTf0a+MzxG2m4nnIXyNC/nT5XLItKHog4KROHb4tUpCZJ4iJhcw3loWMCtkZqB2fq2PaOkKk2zxPr3HLCn7ltmOzReBEDjEg68UqWydRW5534JGosbcA9IfshS1VqnZLgGwQHieXNeqhJUumt1DpON7AQEiEzbzAk0y2VcPlDPuCt9QS1k+zPMZLzbwgvs1ZOH39oFESW+iEDdzZjbhyC3J6azTHFcnA7r5SsYe1pzcSUaYtS1ehhb0lU/442JSHw2j00Nv9qFycYNvDrRNQNBxLziVustT0WJoVdFlkKy16iu1tUYOVXKgmMfqUDINfU6zRz3DskVuB9MZzq/4cMdK4jMRIDNZWvye1BzM7o/PiJoNaQc/6iav2RD+5YV46bBr60TqnYyjlM=" + +# Disable Coverity due to a problem with their certificate that makes it fail +# in Travis-CI. +# +#addons: +# coverity_scan: +# project: +# name: "plusvic/yara" +# description: "Build submitted via Travis CI" +# notification_email: plusvic@gmail.com +# build_command_prepend: "./configure; make clean" +# build_command: "make -j 4" +# branch_pattern: master diff --git a/yara-master/AUTHORS b/yara-master/AUTHORS new file mode 100644 index 0000000..4989970 --- /dev/null +++ b/yara-master/AUTHORS @@ -0,0 +1,16 @@ +# This is the official list of YARA authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. + +Google Inc. +Hilko Bengen +Joachim Metz +Stefan Buehlmann +Victor M. Alvarez ; +Wesley Shields diff --git a/yara-master/CONTRIBUTORS b/yara-master/CONTRIBUTORS new file mode 100644 index 0000000..19effbd --- /dev/null +++ b/yara-master/CONTRIBUTORS @@ -0,0 +1,38 @@ +# This is the official list of people who can contribute +# (and typically have contributed) code to the YARA repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# The submission process automatically checks to make sure +# that people submitting code are listed in this file (by email address). +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# http://code.google.com/legal/individual-cla-v1.0.html +# http://code.google.com/legal/corporate-cla-v1.0.html +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. + +# Names should be added to this file like so: +# Name + +# Please keep the list sorted. + +Anthony Desnos +Christian Blichmann +Hilko Bengen +Joachim Metz +Karl Hiramoto +Mike Wiacek +Shane Huntley +Stefan Buehlmann +Victor M. Alvarez ; +Wesley Shields diff --git a/yara-master/COPYING b/yara-master/COPYING new file mode 100644 index 0000000..81b0eed --- /dev/null +++ b/yara-master/COPYING @@ -0,0 +1,26 @@ +Copyright (c) 2007-2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. diff --git a/yara-master/Makefile.am b/yara-master/Makefile.am new file mode 100644 index 0000000..d4dc22e --- /dev/null +++ b/yara-master/Makefile.am @@ -0,0 +1,69 @@ +AM_CFLAGS=-std=gnu99 -Wall -I$(srcdir)/libyara/include + +if DEBUG +AM_CFLAGS+=-g +endif + +if OPTIMIZATION +AM_CFLAGS+=-O3 +else +AM_CFLAGS+=-O0 +endif + +if ADDRESS_SANITIZER +AM_CFLAGS+=-fsanitize=address +endif + +# Build the library in the hand subdirectory first. +SUBDIRS = libyara +DIST_SUBDIRS = libyara + +ACLOCAL_AMFLAGS=-I m4 + +bin_PROGRAMS = yara yarac + +yara_SOURCES = args.c args.h common.h threading.c threading.h yara.c +yara_LDADD = libyara/.libs/libyara.a + +yarac_SOURCES = args.c args.h common.h yarac.c +yarac_LDADD = libyara/.libs/libyara.a + +TESTS = $(check_PROGRAMS) +check_PROGRAMS = test-alignment test-api test-rules test-pe test-elf test-version + +# The -fsanitize=address option makes test-exception fail. Include the test +# only if the option is not enabled. + +if !ADDRESS_SANITIZER +check_PROGRAMS+=test-exception +endif + +test_alignment_SOURCES = tests/test-alignment.c +test_rules_SOURCES = tests/test-rules.c tests/util.c +test_rules_LDADD = libyara/.libs/libyara.a +test_pe_SOURCES = tests/test-pe.c tests/util.c +test_pe_LDADD = libyara/.libs/libyara.a +test_elf_SOURCES = tests/test-elf.c tests/util.c +test_elf_LDADD = libyara/.libs/libyara.a +test_exception_SOURCES = tests/test-exception.c tests/util.c +test_exception_LDADD = libyara/.libs/libyara.a +test_version_SOURCES = tests/test-version.c +test_api_LDADD = libyara/.libs/libyara.a +test_api_SOURCES = tests/test-api.c tests/util.c + +if MACHO_MODULE +check_PROGRAMS+=test-macho +test_macho_SOURCES = tests/test-macho.c tests/util.c +test_macho_LDADD = libyara/.libs/libyara.a +endif + +if DEX_MODULE +check_PROGRAMS+=test-dex +test_dex_SOURCES = tests/test-dex.c tests/util.c +test_dex_LDADD = libyara/.libs/libyara.a +endif + +# man pages +man1_MANS = yara.man yarac.man + +EXTRA_DIST = $(man1_MANS) README.md bootstrap.sh diff --git a/yara-master/README.md b/yara-master/README.md new file mode 100644 index 0000000..7660d0c --- /dev/null +++ b/yara-master/README.md @@ -0,0 +1,111 @@ +[![Join the chat at https://gitter.im/VirusTotal/yara](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/VirusTotal/yara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Travis build status](https://travis-ci.org/VirusTotal/yara.svg)](https://travis-ci.org/VirusTotal/yara) +[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/7glqg19w4oolm7pr?svg=true)](https://ci.appveyor.com/project/plusvic/yara) +[![Coverity status](https://scan.coverity.com/projects/9057/badge.svg?flat=1)](https://scan.coverity.com/projects/plusvic-yara) + + + +## YARA in a nutshell + +YARA is a tool aimed at (but not limited to) helping malware researchers to +identify and classify malware samples. With YARA you can create descriptions of +malware families (or whatever you want to describe) based on textual or binary +patterns. Each description, a.k.a rule, consists of a set of strings and a +boolean expression which determine its logic. Let's see an example: + +``` +rule silent_banker : banker +{ + meta: + description = "This is just an example" + threat_level = 3 + in_the_wild = true + + strings: + $a = {6A 40 68 00 30 00 00 6A 14 8D 91} + $b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9} + $c = "UVODFRYSIHLNWPEJXQZAKCBGMT" + + condition: + $a or $b or $c +} +``` + +The above rule is telling YARA that any file containing one of the three strings +must be reported as *silent_banker*. This is just a simple example, more +complex and powerful rules can be created by using wild-cards, case-insensitive +strings, regular expressions, special operators and many other features that +you'll find explained in [YARA's documentation](https://yara.readthedocs.org/). + +YARA is multi-platform, running on Windows, Linux and Mac OS X, and can be used +through its command-line interface or from your own Python scripts with the +yara-python extension. + +If you plan to use YARA to scan compressed files (.zip, .tar, etc) you should +take a look at [yextend](https://github.com/BayshoreNetworks/yextend), a very +helpful extension to YARA developed and open-sourced by Bayshore Networks. + +## Who's using YARA + +* [ActiveCanopy](https://activecanopy.com/) +* [Adlice](http://www.adlice.com/) +* [AlienVault](https://otx.alienvault.com/) +* [Avast](https://www.avast.com/) +* [BAE Systems](http://www.baesystems.com/home?r=ai) +* [Bayshore Networks, Inc.](http://www.bayshorenetworks.com) +* [BinaryAlert](https://github.com/airbnb/binaryalert) +* [Blue Coat](http://www.bluecoat.com/products/malware-analysis-appliance) +* [Blueliv](http://www.blueliv.com) +* [Conix](http://www.conix.fr) +* [CrowdStrike FMS](https://github.com/CrowdStrike/CrowdFMS) +* [Cuckoo Sandbox](https://github.com/cuckoosandbox/cuckoo) +* [ESET](https://www.eset.com) +* [ESTsecurity](https://www.estsecurity.com) +* [Fidelis XPS](http://www.fidelissecurity.com/network-security-appliance/Fidelis-XPS) +* [FireEye, Inc.](http://www.fireeye.com) +* [Fox-IT](https://www.fox-it.com) +* [FSF](https://github.com/EmersonElectricCo/fsf) +* [Guidance Software](http://www.guidancesoftware.com/endpointsecurity) +* [Heroku](https://heroku.com) +* [Hornetsecurity](https://www.hornetsecurity.com/en/) +* [InQuest](http://www.inquest.net/) +* [JASK](http://jask.io) +* [Joe Security](https://www.joesecurity.org) +* [jsunpack-n](http://jsunpack.jeek.org/) +* [Kaspersky Lab](http://www.kaspersky.com) +* [Koodous](https://koodous.com/) +* [Laika BOSS](https://github.com/lmco/laikaboss) +* [Lastline, Inc.](http://www.lastline.com) +* [McAfee Advanced Threat Defense](http://mcafee.com/atd) +* [Metaflows](http://www.metaflows.com) +* [NBS System](https://www.nbs-system.com/) +* [Nozomi Networks](http://www.nozominetworks.com) +* [osquery](http://www.osquery.io) +* [Payload Security](https://www.payload-security.com) +* [PhishMe](http://phishme.com/) +* [Picus Security](http://www.picussecurity.com/) +* [Radare2](http://rada.re) +* [Raytheon Cyber Products, Inc.](http://www.raytheoncyber.com/capabilities/products/sureview-threatprotection/) +* [RedSocks Security](https://redsocks.eu/) +* [ReversingLabs](http://reversinglabs.com) +* [root9B](https://www.root9b.com) +* [RSA ECAT](http://www.emc.com/security/rsa-ecat.htm) +* [SpamStopsHere](https://www.spamstopshere.com) +* [stoQ](http://stoq.punchcyber.com) +* [Symantec](http://www.symantec.com) +* [Tanium](http://www.tanium.com/) +* [Tenable Network Security](https://www.tenable.com/) +* [The DigiTrust Group](http://www.digitrustgroup.com/) +* [ThreatConnect](https://www.threatconnect.com/) +* [ThreatStream, Inc.](http://threatstream.com) +* [Thug](https://github.com/buffer/thug) +* [Trend Micro](http://www.trendmicro.com) +* [VirusTotal Intelligence](https://www.virustotal.com/intelligence/) +* [VMRay](https://www.vmray.com/) +* [We Watch Your Website](http://www.wewatchyourwebsite.com/) +* [Websense](http://www.websense.com) +* [x64dbg](http://x64dbg.com) +* [YALIH](https://github.com/Masood-M/YALIH) +* [Scanii](https://scanii.com) + +Are you using it? Want to see your site listed here? diff --git a/yara-master/appveyor.yml b/yara-master/appveyor.yml new file mode 100644 index 0000000..275fdaf --- /dev/null +++ b/yara-master/appveyor.yml @@ -0,0 +1,24 @@ +# AppVeyor CI for Windows + +version: 3.7.{build} + +pull_requests: + do_not_increment_build_number: true + +configuration: Release + +platform: +- x64 +- x86 + +before_build: +- ps: nuget restore windows/vs2015/yara.sln + +build: + project: windows/vs2015/yara.sln + verbosity: minimal + +artifacts: + - path: windows\**\*.exe + +test: off diff --git a/yara-master/args.c b/yara-master/args.c new file mode 100644 index 0000000..d9853ae --- /dev/null +++ b/yara-master/args.c @@ -0,0 +1,291 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include + +#include "args.h" + +#define args_is_long_arg(arg) \ + (arg[0] == '-' && arg[1] == '-' && arg[2] != '\0') + + +#define args_is_short_arg(arg) \ + (arg[0] == '-' && arg[1] != '-' && arg[1] != '\0') + + +args_option_t* args_get_short_option( + args_option_t *options, + const char opt) +{ + while (options->type != ARGS_OPT_END) + { + if (opt == options->short_name) + return options; + + options++; + } + + return NULL; +} + + +args_option_t* args_get_long_option( + args_option_t *options, + const char* arg) +{ + arg += 2; // skip starting -- + + while (options->type != ARGS_OPT_END) + { + if (options->long_name != NULL) + { + size_t l = strlen(options->long_name); + + if ((arg[l] == '\0' || arg[l] == '=') && + strstr(arg, options->long_name) == arg) + { + return options; + } + } + + options++; + } + + return NULL; +} + + +args_error_type_t args_parse_option( + args_option_t* opt, + const char* opt_arg, + int* opt_arg_was_used) +{ + char *endptr = NULL; + + if (opt_arg_was_used != NULL) + *opt_arg_was_used = 0; + + if (opt->count == opt->max_count) + return ARGS_ERROR_TOO_MANY; + + switch (opt->type) + { + case ARGS_OPT_BOOLEAN: + *(int*) opt->value = 1; + break; + + case ARGS_OPT_INTEGER: + + if (opt_arg == NULL) + return ARGS_ERROR_REQUIRED_INTEGER_ARG; + + *(int*) opt->value = strtol(opt_arg, &endptr, 0); + + if (*endptr != '\0') + return ARGS_ERROR_REQUIRED_INTEGER_ARG; + + if (opt_arg_was_used != NULL) + *opt_arg_was_used = 1; + + break; + + case ARGS_OPT_STRING: + + if (opt_arg == NULL) + return ARGS_ERROR_REQUIRED_STRING_ARG; + + if (opt->max_count > 1) + ((const char**)opt->value)[opt->count] = opt_arg; + else + *(const char**) opt->value = opt_arg; + + if (opt_arg_was_used != NULL) + *opt_arg_was_used = 1; + + break; + + default: + assert(0); + } + + opt->count++; + + return ARGS_ERROR_OK; +} + + +void args_print_error( + args_error_type_t error, + const char* option) +{ + switch(error) + { + case ARGS_ERROR_UNKNOWN_OPT: + fprintf(stderr, "unknown option `%s`\n", option); + break; + case ARGS_ERROR_TOO_MANY: + fprintf(stderr, "too many `%s` options\n", option); + break; + case ARGS_ERROR_REQUIRED_INTEGER_ARG: + fprintf(stderr, "option `%s` requires an integer argument\n", option); + break; + case ARGS_ERROR_REQUIRED_STRING_ARG: + fprintf(stderr, "option `%s` requires a string argument\n", option); + break; + case ARGS_ERROR_UNEXPECTED_ARG: + fprintf(stderr, "option `%s` doesn't expect an argument\n", option); + break; + default: + return; + } +} + + +int args_parse( + args_option_t *options, + int argc, + const char **argv) +{ + args_error_type_t error = ARGS_ERROR_OK; + + int i = 1; // start with i = 1, argv[0] is the program name + int o = 0; + + while (i < argc) + { + const char* arg = argv[i]; + + if (args_is_long_arg(arg)) + { + args_option_t* opt = args_get_long_option(options, arg); + + if (opt != NULL) + { + const char* equal = strchr(arg, '='); + + if (equal) + error = args_parse_option(opt, equal + 1, NULL); + else + error = args_parse_option(opt, NULL, NULL); + } + else + { + error = ARGS_ERROR_UNKNOWN_OPT; + } + } + else if (args_is_short_arg(arg)) + { + for (int j = 1; arg[j] != '\0'; j++) + { + args_option_t* opt = args_get_short_option(options, arg[j]); + + if (opt != NULL) + { + if (arg[j + 1] == '\0') + { + int arg_used; + + // short option followed by a space, argv[i + 1] could be + // an argument for the option (i.e: -a ) + error = args_parse_option(opt, argv[i + 1], &arg_used); + + // argv[i + 1] was actually an argument to the option, skip it. + if (arg_used) + i++; + } + else + { + // short option followed by another option (i.e: -ab), no + // argument for this option + error = args_parse_option(opt, NULL, NULL); + } + } + else + { + error = ARGS_ERROR_UNKNOWN_OPT; + } + + if (error != ARGS_ERROR_OK) + break; + } + } + else + { + argv[o++] = arg; + } + + if (error != ARGS_ERROR_OK) + { + args_print_error(error, arg); + exit(1); + } + + i++; + } + + return o; +} + + +void args_print_usage( + args_option_t *options, + int help_alignment) +{ + char buffer[128]; + + for (; options->type != ARGS_OPT_END; options++) + { + int len = sprintf(buffer, " "); + + if (options->short_name != '\0') + len += sprintf(buffer + len, "-%c", options->short_name); + else + len += sprintf(buffer + len, " "); + + if (options->short_name != '\0' && options->long_name != NULL) + len += sprintf(buffer + len, ", "); + + if (options->long_name != NULL) + len += sprintf(buffer + len, "--%s", options->long_name); + + if (options->type == ARGS_OPT_STRING || + options->type == ARGS_OPT_INTEGER) + { + len += sprintf( + buffer + len, + "%s%s", + (options->long_name != NULL) ? "=" : " ", + options->type_help); + } + + printf("%-*s%s\n", help_alignment, buffer, options->help); + } +} diff --git a/yara-master/args.h b/yara-master/args.h new file mode 100644 index 0000000..1f9d267 --- /dev/null +++ b/yara-master/args.h @@ -0,0 +1,105 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef ARGPARSE_H +#define ARGPARSE_H + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum _args_error_type { + ARGS_ERROR_OK, + ARGS_ERROR_UNKNOWN_OPT, + ARGS_ERROR_TOO_MANY, + ARGS_ERROR_REQUIRED_INTEGER_ARG, + ARGS_ERROR_REQUIRED_STRING_ARG, + ARGS_ERROR_UNEXPECTED_ARG, +} args_error_type_t; + + +typedef enum _args_option_type { + // special + ARGS_OPT_END, + ARGS_OPT_GROUP, + // options with no arguments + ARGS_OPT_BOOLEAN, + // options with arguments (optional or required) + ARGS_OPT_INTEGER, + ARGS_OPT_STRING, +} args_option_type_t; + + +typedef struct _args_option { + args_option_type_t type; + const char short_name; + const char *long_name; + void *value; + int max_count; + const char *help; + const char *type_help; + int count; +} args_option_t; + + +#define OPT_BOOLEAN(short_name, long_name, value, ...) \ + { ARGS_OPT_BOOLEAN, short_name, long_name, value, 1, __VA_ARGS__ } + +#define OPT_INTEGER(short_name, long_name, value, ...) \ + { ARGS_OPT_INTEGER, short_name, long_name, value, 1, __VA_ARGS__ } + +#define OPT_STRING_MULTI(short_name, long_name, value, max_count, ...) \ + { ARGS_OPT_STRING, short_name, long_name, value, max_count, __VA_ARGS__ } + +#define OPT_STRING(short_name, long_name, value, ...) \ + OPT_STRING_MULTI(short_name, long_name, value, 1, __VA_ARGS__) + +#define OPT_END() { ARGS_OPT_END, 0 } + + +int args_parse( + args_option_t *options, + int argc, + const char **argv); + + +void args_print_usage( + args_option_t *options, + int alignment); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/yara-master/bootstrap.sh b/yara-master/bootstrap.sh new file mode 100644 index 0000000..3f026c4 --- /dev/null +++ b/yara-master/bootstrap.sh @@ -0,0 +1,2 @@ +#!/bin/sh +autoreconf --force --install diff --git a/yara-master/build.sh b/yara-master/build.sh new file mode 100644 index 0000000..90bb778 --- /dev/null +++ b/yara-master/build.sh @@ -0,0 +1,4 @@ +#!/bin/sh +./bootstrap.sh +./configure +make \ No newline at end of file diff --git a/yara-master/common.h b/yara-master/common.h new file mode 100644 index 0000000..e1ac4fe --- /dev/null +++ b/yara-master/common.h @@ -0,0 +1,128 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + + +#ifndef COMMON_H +#define COMMON_H + +#define exit_with_code(code) { result = code; goto _exit; } + + +int compile_files( + YR_COMPILER* compiler, + int argc, + const char** argv) +{ + for (int i = 0; i < argc - 1; i++) + { + const char* ns; + const char* file_name; + char* colon = (char*) strchr(argv[i], ':'); + int errors; + + // Namespace delimiter must be a colon not followed by a slash or backslash + if (colon && *(colon + 1) != '\\' && *(colon + 1) != '/') + { + file_name = colon + 1; + *colon = '\0'; + ns = argv[i]; + } + else + { + file_name = argv[i]; + ns = NULL; + } + + FILE* rule_file = fopen(file_name, "r"); + + if (rule_file == NULL) + { + fprintf(stderr, "error: could not open file: %s\n", file_name); + return FALSE; + } + + errors = yr_compiler_add_file(compiler, rule_file, ns, file_name); + + fclose(rule_file); + + if (errors > 0) + return FALSE; + } + + return TRUE; +} + + +int is_integer(const char *str) +{ + if (*str == '-') + str++; + + while(*str) + { + if (!isdigit(*str)) + return FALSE; + str++; + } + + return TRUE; +} + + +int is_float(const char *str) +{ + int has_dot = FALSE; + + if (*str == '-') // skip the minus sign if present + str++; + + if (*str == '.') // float can't start with a dot + return FALSE; + + while(*str) + { + if (*str == '.') + { + if (has_dot) // two dots, not a float + return FALSE; + + has_dot = TRUE; + } + else if (!isdigit(*str)) + { + return FALSE; + } + + str++; + } + + return has_dot; // to be float must contain a dot +} + +#endif \ No newline at end of file diff --git a/yara-master/configure.ac b/yara-master/configure.ac new file mode 100644 index 0000000..8244a28 --- /dev/null +++ b/yara-master/configure.ac @@ -0,0 +1,308 @@ +AC_INIT([yara], [3.7.0], [vmalvarez@virustotal.com]) + +AM_SILENT_RULES([yes]) +AC_CONFIG_SRCDIR([yara.c]) + +AC_CONFIG_AUX_DIR([build-aux]) + +AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) + +AC_CONFIG_MACRO_DIR([m4]) + +# AC_PROG_CC sets CFLAGS to "-g -O2" if it wasn't previously set. Let's set +# an empty CFLAGS +: ${CFLAGS=""} + +no_std_allocator="-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free" + +# automake 1.12 seems to require AM_PROG_AR, but automake 1.11 doesn't +# recognize it +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) + +AC_PROG_CC +AM_PROG_CC_C_O +AM_PROG_LEX +AC_PROG_YACC +AC_SYS_LARGEFILE + +LT_INIT +AC_PROG_LIBTOOL + +AC_CANONICAL_HOST + +case $host_alias in + i?86-*-mingw*) CFLAGS="$CFLAGS -D__MINGW_USE_VC2005_COMPAT" ;; +esac + +case $host_os in + darwin*) CFLAGS="$CFLAGS -I/opt/local/include" + # Starting with Mac OS X 10.11 (El Capitan) the OpenSSL headers + # are in /usr/local/opt/openssl/include + CFLAGS="$CFLAGS -DUSE_MACH_PROC -I/usr/local/opt/openssl/include" + LDFLAGS="$LDFLAGS -L/usr/local/opt/openssl/lib" + mach=yes + proc_interface=mach + jemalloc_prefix=je_ ;; + mingw*) CFLAGS="$CFLAGS -DUSE_WINDOWS_PROC" + proc_interface=windows + jemalloc_prefix= ;; + linux*|netbsd*|dragonfly*|kfreebsd*) + CFLAGS="$CFLAGS -DUSE_LINUX_PROC" + proc_interface=linux + jemalloc_prefix= ;; + freebsd*) + CFLAGS="$CFLAGS -DUSE_FREEBSD_PROC" + proc_interface=freebsd + jemalloc_prefix= ;; + openbsd*) + CFLAGS="$CFLAGS -DUSE_OPENBSD_PROC" + proc_interface=openbsd + jemalloc_prefix= ;; + *) + CFLAGS="$CFLAGS -DUSE_NO_PROC" + proc_interface=none + jemalloc_prefix= ;; +esac + +AC_C_BIGENDIAN + +ACX_PTHREAD( + [LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + CC="$PTHREAD_CC"], + [AC_MSG_ERROR([pthread API support is required.])]) + +AC_CHECK_LIB(m, isnan) +AC_CHECK_LIB(m, log2) +AC_CHECK_FUNCS([strlcpy strlcat memmem timegm _mkgmtime]) + +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], [compiles with -g option])], + [if test x$enableval = xyes; then + debug=true + fi]) + +AC_ARG_ENABLE([optimization], + [AS_HELP_STRING([--disable-optimization], [disable compiler optimizations with -O0])], + [if test x$enableval = xyes; then + optimization=false + fi], + [optimization=true]) + +AC_ARG_ENABLE([address-sanitizer], + [AS_HELP_STRING([--enable-address-sanitizer], [compiles with -fsanitize=address])], + [if test x$enableval = xyes; then + address_sanitizer=true + fi]) + +AC_ARG_ENABLE([profiling], + [AS_HELP_STRING([--enable-profiling], [enable rules profiling support])], + [if test x$enableval = xyes; then + profiling_enabled=true + CFLAGS="$CFLAGS -DPROFILING_ENABLED" + fi]) + +AC_ARG_ENABLE([cuckoo], + [AS_HELP_STRING([--enable-cuckoo], [enable cuckoo module])], + [if test x$enableval = xyes; then + build_cuckoo_module=true + AC_CHECK_HEADERS([jansson.h],, + AC_MSG_ERROR([please install Jansson library])) + AC_CHECK_LIB(jansson, json_loadb,, + AC_MSG_ERROR([please install Jansson library])) + CFLAGS="$CFLAGS -DCUCKOO_MODULE" + PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE jansson" + fi]) + +AC_ARG_ENABLE([magic], + [AS_HELP_STRING([--enable-magic], [enable magic module])], + [if test x$enableval = xyes; then + build_magic_module=true + AC_CHECK_HEADERS([magic.h],, + AC_MSG_ERROR([please install libmagic library])) + AC_CHECK_LIB(magic, magic_open,, + AC_MSG_ERROR([please install libmagic library])) + CFLAGS="$CFLAGS -DMAGIC_MODULE" + PC_LIBS_PRIVATE="$PC_LIBS_PRIVATE -lmagic" + fi]) + +AC_ARG_ENABLE([dotnet], + [AS_HELP_STRING([--enable-dotnet], [enable dotnet module])], + [if test x$enableval = xyes; then + build_dotnet_module=true + CFLAGS="$CFLAGS -DDOTNET_MODULE" + fi]) + +AC_ARG_ENABLE([macho], + [AS_HELP_STRING([--enable-macho], [enable macho module])], + [if test x$enableval = xyes; then + build_macho_module=true + CFLAGS="$CFLAGS -DMACHO_MODULE" + fi]) + +AC_ARG_ENABLE([dex], + [AS_HELP_STRING([--enable-dex], [enable dex module])], + [if test x$enableval = xyes; then + build_dex_module=true + CFLAGS="$CFLAGS -DDEX_MODULE" + fi]) + +AC_ARG_ENABLE([debug-dex], + [AS_HELP_STRING([--enable-debug-dex], [enable dex module debugging])], + [if test x$enableval = xyes; then + debug_dex_module=true + CFLAGS="$CFLAGS -DDEBUG_DEX_MODULE" + fi]) + +AC_ARG_WITH([jemalloc], + [AS_HELP_STRING([--with-jemalloc], + [use jemalloc to debug heap-related issues])], + [if test x$withval = xyes; then + mallctl=mallctl + malloc_stats_print=malloc_stats_print + AC_CHECK_LIB(jemalloc, $jemalloc_prefix$mallctl,, + AC_MSG_ERROR([please install jemalloc library])) + CFLAGS="$CFLAGS -DJEMALLOC -Dmallctl=$jemalloc_prefix$mallctl -Dmalloc_stats_print=$jemalloc_prefix$malloc_stats_print $no_std_allocator" + fi]) + +AC_ARG_WITH([tcmalloc], + [AS_HELP_STRING([--with-tcmalloc], + [use tcmalloc as the default heap allocator])], + [if test x$withval = xyes; then + if test "x$with_jemalloc" = "xyes"; then + AC_MSG_ERROR([Cannot compile with both tcmalloc and jemalloc]) + fi + AC_CHECK_LIB(tcmalloc, tc_cfree,, + AC_MSG_ERROR([please install https://github.com/gperftools/gperftools])) + CFLAGS="$CFLAGS -DTCMALLOC $no_std_allocator" + fi]) + +AC_ARG_WITH([cpu-profiler], + [AS_HELP_STRING([--with-cpu-profiler], + [compile with CPU profiling support])], + [if test x$withval = xyes; then + AC_CHECK_LIB(profiler, ProfilerStart,, + AC_MSG_ERROR([please install https://github.com/gperftools/gperftools])) + fi]) + +AC_ARG_WITH([crypto], + AS_HELP_STRING([--without-crypto], + [ignore presence of OpenSSL and disable it])) + +AS_IF([test "x$with_crypto" != "xno"], + [ + AC_CHECK_HEADERS([openssl/md5.h],, [have_crypto=no]) + AC_CHECK_HEADERS([openssl/sha.h],, [have_crypto=no]) + AC_CHECK_HEADERS([openssl/asn1.h],, [have_crypto=no]) + AC_CHECK_HEADERS([openssl/crypto.h],, [have_crypto=no]) + AC_CHECK_HEADERS([openssl/bio.h],, [have_crypto=no]) + AC_CHECK_HEADERS([openssl/pkcs7.h],, [have_crypto=no]) + AC_CHECK_HEADERS([openssl/x509.h],, [have_crypto=no]) + AC_CHECK_HEADERS([openssl/safestack.h],, [have_crypto=no]) + AC_CHECK_LIB(crypto, MD5_Init,, [have_crypto=no]) + AC_CHECK_LIB(crypto, MD5_Update,, [have_crypto=no]) + AC_CHECK_LIB(crypto, MD5_Final,, [have_crypto=no]) + AC_CHECK_LIB(crypto, SHA256_Init,, [have_crypto=no]) + AC_CHECK_LIB(crypto, SHA256_Update,, [have_crypto=no]) + AC_CHECK_LIB(crypto, SHA256_Final,, [have_crypto=no]) + ], + [ + have_crypto=no + ]) + + +AS_IF([test "x$have_crypto" = "xno"], + [ + AS_IF([test "x$with_crypto" = "xyes"], + [ + AC_MSG_ERROR([please install OpenSSL library]) + ], + [ + AC_MSG_WARN([ + +***************************************************************** + Could not find OpenSSL library. Some features in "pe" module + have been disabled. If you want to enable all features please + install OpenSSL and run this script again. +***************************************************************** +]) + AC_MSG_CHECKING([for Microsoft Crypto API]) + AC_CHECK_HEADERS([wincrypt.h], + [ + AC_MSG_RESULT([The "hash" module functions will be provided through the Microsoft Crypto API]) + # FIXME: Add PC_LIBS_PRIVATE entries? + build_hash_module=true + ], + [], + [#include ]) + AC_MSG_CHECKING([for MacOSX Common Crypto API]) + AC_CHECK_HEADERS([CommonCrypto/CommonCrypto.h], + [ + AC_MSG_RESULT([ +***************************************************************** + As an alternative to OpenSSL the "hash" module functions will + be provided through the MacOSX Common Crypto API. +***************************************************************** +]) + # FIXME: Add PC_LIBS_PRIVATE entries? + build_hash_module=true + ]) + AS_IF([test x$build_hash_module = xtrue], + [ + build_hash_module=true + CFLAGS="$CFLAGS -DHASH_MODULE" + ], + [ + AC_MSG_WARN([ + +***************************************************************** + Could not find alternative APIs for hash functions. The "hash" + module has been disabled. +***************************************************************** + ]) + ]) + ]) + ], + [ + build_hash_module=true + CFLAGS="$CFLAGS -DHASH_MODULE" + PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE libcrypto" + ]) + +AS_IF([test "x$mach" != "xyes"], + [ + AC_CHECK_FUNCS([clock_gettime],, + AC_MSG_ERROR([clock_gettime not supported in your OS.])) + ],) + +AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) +AM_CONDITIONAL([PROFILING_ENABLED], [test x$profiling_enabled = xtrue]) +AM_CONDITIONAL([OPTIMIZATION], [test x$optimization = xtrue]) +AM_CONDITIONAL([ADDRESS_SANITIZER], [test x$address_sanitizer = xtrue]) +AM_CONDITIONAL([CUCKOO_MODULE], [test x$build_cuckoo_module = xtrue]) +AM_CONDITIONAL([MAGIC_MODULE], [test x$build_magic_module = xtrue]) +AM_CONDITIONAL([HASH_MODULE], [test x$build_hash_module = xtrue]) +AM_CONDITIONAL([DOTNET_MODULE], [test x$build_dotnet_module = xtrue]) +AM_CONDITIONAL([MACHO_MODULE], [test x$build_macho_module = xtrue]) +AM_CONDITIONAL([GCC], [test "x$GCC" = xyes]) +AM_CONDITIONAL([DEX_MODULE], [test x$build_dex_module = xtrue]) +AM_CONDITIONAL([DEBUG_DEX_MODULE], [test x$debug_dex_module = xtrue]) + +AM_CONDITIONAL([USE_WINDOWS_PROC], [test x$proc_interface = xwindows ]) +AM_CONDITIONAL([USE_LINUX_PROC], [test x$proc_interface = xlinux ]) +AM_CONDITIONAL([USE_FREEBSD_PROC], [test x$proc_interface = xfreebsd ]) +AM_CONDITIONAL([USE_OPENBSD_PROC], [test x$proc_interface = xopenbsd ]) +AM_CONDITIONAL([USE_MACH_PROC], [test x$proc_interface = xmach ]) +AM_CONDITIONAL([USE_NO_PROC], [test x$proc_interface = xnone ]) +AS_IF( + [test x$proc_interface != xnone],[AC_DEFINE([HAVE_SCAN_PROC_IMPL],[1])], + [test x$proc_interface = xnone],[AC_DEFINE([HAVE_SCAN_PROC_IMPL],[0])]) + +AC_SUBST([PC_REQUIRES_PRIVATE]) +AC_SUBST([PC_LIBS_PRIVATE]) + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([libyara/Makefile]) +AC_CONFIG_FILES([libyara/yara.pc]) + +AC_OUTPUT diff --git a/yara-master/dist/yara-python.spec b/yara-master/dist/yara-python.spec new file mode 100644 index 0000000..999eb55 --- /dev/null +++ b/yara-master/dist/yara-python.spec @@ -0,0 +1,35 @@ +%define name yara-python +%define version 3.2.0 +%define unmangled_version 3.2.0 +%define release 1 + +Summary: Python bindings for YARA malware research tool +Name: %{name} +Version: %{version} +Release: %{release} +Source0: %{name}-%{unmangled_version}.tar.gz +License: Apache License 2.0 +Group: Development/Libraries +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot +Prefix: %{_prefix} +Vendor: Victor M. Alvarez +BuildRequires: gcc python-devel +BuildRequires: libyara-devel + +%description +YARA is a tool aimed at (but not limited to) helpingmalware researchers to identify and classify malwaresamples. With YARA you can create descriptions of malware families (or whatever you want to describe)based on textual or binary patterns. + +%prep +%setup -n %{name}-%{unmangled_version} + +%build +env CFLAGS="$RPM_OPT_FLAGS" python setup.py build + +%install +python setup.py install -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES + +%clean +rm -rf $RPM_BUILD_ROOT + +%files -f INSTALLED_FILES +%defattr(-,root,root) diff --git a/yara-master/dist/yara.spec b/yara-master/dist/yara.spec new file mode 100644 index 0000000..bb8c89d --- /dev/null +++ b/yara-master/dist/yara.spec @@ -0,0 +1,85 @@ +## +## Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved. +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## http://www.apache.org/licenses/LICENSE-2.0 +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +Name: yara +Version: 3.2.0 +Release: 1 +License: Apache License 2.0 +Summary: A malware identification and classification tool +Url: http://plusvic.github.io/yara/ +Group: System/Filesystems +Source: yara-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-build +BuildRequires: autoconf automake libtool + +%description +YARA is a tool aimed at helping malware researchers to identify and classify +malware samples. With YARA you can create descriptions of malware families +based on textual or binary patterns contained on samples of those families. + +%package -n libyara +Summary: Library to support the yara malware identification tool +Group: System/Libraries + +%description -n libyara +YARA is a tool aimed at helping malware researchers to identify and classify +malware samples. With YARA you can create descriptions of malware families +based on textual or binary patterns contained on samples of those families. + +%package -n yara-devel +Summary: Development files to support the yara malware identification tool +Group: Development/Libraries/C and C++ +Requires: libyara = %{version}-%{release} + +%description -n yara-devel +YARA is a tool aimed at helping malware researchers to identify and classify +malware samples. With YARA you can create descriptions of malware families +based on textual or binary patterns contained on samples of those families. + +%prep +%setup -q + +%build +./bootstrap.sh +./configure +make + +%install +make install DESTDIR=%{buildroot} bindir=%{_bindir} libdir=%{_libdir} includedir=%{_includedir} mandir=%{_mandir} INSTALL="install -p" + +%post -n libyara -p /sbin/ldconfig + +%postun -n libyara -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%{_bindir}/yara +%{_bindir}/yarac +%{_mandir}/man1/* + +%files -n libyara +%defattr(-,root,root) +%{_libdir}/libyara.so* +%{_libdir}/pkgconfig/yara.pc + +%files -n yara-devel +%defattr(-,root,root) +%{_includedir}/yara.h +%{_includedir}/yara/* +%{_libdir}/libyara.a +%{_libdir}/libyara.la + + +%changelog +* Sat Jan 25 2015 Domingo Kiser 3.2.0-1 + Initial Creation. diff --git a/yara-master/docs/capi.rst b/yara-master/docs/capi.rst new file mode 100644 index 0000000..2938dd4 --- /dev/null +++ b/yara-master/docs/capi.rst @@ -0,0 +1,784 @@ +********* +The C API +********* + +You can integrate YARA into your C/C++ project by using the API provided by the +*libyara* library. This API gives you access to every YARA feature and it's the +same API used by the command-line tools ``yara`` and ``yarac``. + +Initializing and finalizing *libyara* +===================================== + +The first thing your program must do when using *libyara* is initializing the +library. This is done by calling the :c:func:`yr_initialize` function. This +function allocates any resources needed by the library and initializes internal +data structures. Its counterpart is :c:func:`yr_finalize`, which must be called +when you are finished using the library. + +In a multi-threaded program only the main thread must call +:c:func:`yr_initialize` and :c:func:`yr_finalize`, but any additional thread +using the library must call :c:func:`yr_finalize_thread` before exiting. + + +Compiling rules +=============== + +Before using your rules to scan any data you need to compile them into binary +form. For that purpose you'll need a YARA compiler, which can be created with +:c:func:`yr_compiler_create`. After being used, the compiler must be destroyed +with :c:func:`yr_compiler_destroy`. + +You can use :c:func:`yr_compiler_add_file`, :c:func:`yr_compiler_add_fd`, or +:c:func:`yr_compiler_add_string` to add one or more input sources to be +compiled. Both of these functions receive an optional namespace. Rules added +under the same namespace behave as if they were contained within the same +source file or string, so, rule identifiers must be unique among all the sources +sharing a namespace. If the namespace argument is ``NULL`` the rules are put +in the *default* namespace. + +The :c:func:`yr_compiler_add_file`, :c:func:`yr_compiler_add_fd`, and +:c:func:`yr_compiler_add_string` functions return +the number of errors found in the source code. If the rules are correct they +will return 0. If any of these functions return an error the compiler can't used +anymore, neither for adding more rules nor getting the compiled rules. + +For obtaining detailed error information you must set a callback +function by using :c:func:`yr_compiler_set_callback` before calling +any of the compiling functions. The callback function has the following +prototype: + +.. code-block:: c + + void callback_function( + int error_level, + const char* file_name, + int line_number, + const char* message, + void* user_data) + +.. versionchanged:: 3.3.0 + +Possible values for ``error_level`` are ``YARA_ERROR_LEVEL_ERROR`` and +``YARA_ERROR_LEVEL_WARNING``. The arguments ``file_name`` and ``line_number`` +contains the file name and line number where the error or warning occurs. +``file_name`` is the one passed to :c:func:`yr_compiler_add_file` or +:c:func:`yr_compiler_add_fd`. It can be ``NULL`` if you passed ``NULL`` or if +you're using :c:func:`yr_compiler_add_string`. The ``user_data`` pointer is the +same you passed to :c:func:`yr_compiler_set_callback`. + +By default, for rules containing references to other files +(``include "filename.yara"``), yara will try to find those files on disk. +However, if you want to fetch the imported rules from another source (eg: from a +database or remote service), a callback function can be set with +:c:func:`yr_compiler_set_include_callback`. +The callback receives the following parameters: + * ``include_name``: name of the requested file. + * ``calling_rule_filename``: the requesting file name (NULL if not a file). + * ``calling_rule_namespace``: namespace (NULL if undefined). + * ``user_data`` pointer is the same you passed to :c:func:`yr_compiler_set_include_callback`. +It should return the requested file's content as a null-terminated string. The +memory for this string should be allocated by the callback function. Once it is +safe to free the memory used to return the callback's result, the include_free +function passed to :c:func:`yr_compiler_set_include_callback` will be called. +If the memory does not need to be freed, NULL can be passed as include_free +instead. You can completely disable support for includes by setting a NULL +callback function with :c:func:`yr_compiler_set_include_callback`. + +The callback function has the following prototype: + +.. code-block:: c + + const char* include_callback( + const char* include_name, + const char* calling_rule_filename, + const char* calling_rule_namespace, + void* user_data); + +The free function has the following prototype: + +.. code-block:: c + + void include_free( + const char* callback_result_ptr, + void* user_data); + +After you successfully added some sources you can get the compiled rules +using the :c:func:`yr_compiler_get_rules` function. You'll get a pointer to +a :c:type:`YR_RULES` structure which can be used to scan your data as +described in :ref:`scanning-data`. Once :c:func:`yr_compiler_get_rules` is +invoked you can not add more sources to the compiler, but you can get multiple +instances of the compiled rules by calling :c:func:`yr_compiler_get_rules` +multiple times. + +Each instance of :c:type:`YR_RULES` must be destroyed with +:c:func:`yr_rules_destroy`. + + +Saving and retrieving compiled rules +==================================== + +Compiled rules can be saved to a file and retrieved later by using +:c:func:`yr_rules_save` and :c:func:`yr_rules_load`. Rules compiled and saved +in one machine can be loaded in another machine as long as they have the same +endianness, no matter the operating system or if they are 32-bit or 64-bit +systems. However files saved with older versions of YARA may not work with +newer versions due to changes in the file layout. + +You can also save and retrieve your rules to and from generic data streams by +using functions :c:func:`yr_rules_save_stream` and +:c:func:`yr_rules_load_stream`. These functions receive a pointer to a +:c:type:`YR_STREAM` structure, defined as: + +.. code-block:: c + + typedef struct _YR_STREAM + { + void* user_data; + + YR_STREAM_READ_FUNC read; + YR_STREAM_WRITE_FUNC write; + + } YR_STREAM; + +You must provide your own implementation for ``read`` and ``write`` functions. +The ``read`` function is used by :c:func:`yr_rules_load_stream` to read data +from your stream and the ``write`` function is used by +:c:func:`yr_rules_save_stream` to write data into your stream. + +Your ``read`` and ``write`` functions must respond to these prototypes: + +.. code-block:: c + + size_t read( + void* ptr, + size_t size, + size_t count, + void* user_data); + + size_t write( + const void* ptr, + size_t size, + size_t count, + void* user_data); + +The ``ptr`` argument is a pointer to the buffer where the ``read`` function +should put the read data, or where the ``write`` function will find the data +that needs to be written to the stream. In both cases ``size`` is the size of +each element being read or written and ``count`` the number of elements. The +total size of the data being read or written is ``size`` * ``count``. Both +functions must return the total number of elements read or written. + +The ``user_data`` pointer is the same you specified in the +:c:type:`YR_STREAM` structure. You can use it to pass arbitrary data to your +``read`` and ``write`` functions. + + +.. _scanning-data: + +Scanning data +============= + +Once you have an instance of :c:type:`YR_RULES` you can use it with either +:c:func:`yr_rules_scan_file`, :c:func:`yr_rules_scan_fd` or +:c:func:`yr_rules_scan_mem`. The results from the scan are returned to your +program via a callback function. The callback has the following prototype: + +.. code-block:: c + + int callback_function( + int message, + void* message_data, + void* user_data); + +Possible values for ``message`` are:: + + CALLBACK_MSG_RULE_MATCHING + CALLBACK_MSG_RULE_NOT_MATCHING + CALLBACK_MSG_SCAN_FINISHED + CALLBACK_MSG_IMPORT_MODULE + CALLBACK_MSG_MODULE_IMPORTED + +Your callback function will be called once for each rule with either +a ``CALLBACK_MSG_RULE_MATCHING`` or ``CALLBACK_MSG_RULE_NOT_MATCHING`` message, +depending if the rule is matching or not. In both cases a pointer to the +:c:type:`YR_RULE` structure associated with the rule is passed in the +``message_data`` argument. You just need to perform a typecast from +``void*`` to ``YR_RULE*`` to access the structure. + +This callback is also called with the ``CALLBACK_MSG_IMPORT_MODULE`` message. +All modules referenced by an ``import`` statement in the rules are imported +once for every file being scanned. In this case ``message_data`` points to a +:c:type:`YR_MODULE_IMPORT` structure. This structure contains a ``module_name`` +field pointing to a null terminated string with the name of the module being +imported and two other fields ``module_data`` and ``module_data_size``. These +fields are initially set to ``NULL`` and ``0``, but your program can assign a +pointer to some arbitrary data to ``module_data`` while setting +``module_data_size`` to the size of the data. This way you can pass additional +data to those modules requiring it, like the :ref:`Cuckoo-module` for example. + +Once a module is imported the callback is called again with the +CALLBACK_MSG_MODULE_IMPORTED. When this happens ``message_data`` points to a +:c:type:`YR_OBJECT_STRUCTURE` structure. This structure contains all the +information provided by the module about the currently scanned file. + +Lastly, the callback function is also called with the +``CALLBACK_MSG_SCAN_FINISHED`` message when the scan is finished. In this case +``message_data`` is ``NULL``. + +Your callback function must return one of the following values:: + + CALLBACK_CONTINUE + CALLBACK_ABORT + CALLBACK_ERROR + +If it returns ``CALLBACK_CONTINUE`` YARA will continue normally, +``CALLBACK_ABORT`` will abort the scan but the result from the +``yr_rules_scan_XXXX`` function will be ``ERROR_SUCCESS``. On the other hand +``CALLBACK_ERROR`` will abort the scanning too, but the result from +``yr_rules_scan_XXXX`` will be ``ERROR_CALLBACK_ERROR``. + + +The ``user_data`` argument passed to your callback function is the same you +passed ``yr_rules_scan_XXXX``. This pointer is not touched by YARA, it's just a +way for your program to pass arbitrary data to the callback function. + +All ``yr_rules_scan_XXXX`` functions receive a ``flags`` argument and a +``timeout`` argument. The only flag defined at this time is +``SCAN_FLAGS_FAST_MODE``, so you must pass either this flag or a zero value. +The ``timeout`` argument forces the function to return after the specified +number of seconds approximately, with a zero meaning no timeout at all. + +The ``SCAN_FLAGS_FAST_MODE`` flag makes the scanning a little faster by avoiding +multiple matches of the same string when not necessary. Once the string was +found in the file it's subsequently ignored, implying that you'll have a +single match for the string, even if it appears multiple times in the scanned +data. This flag has the same effect of the ``-f`` command-line option described +in :ref:`command-line`. + + +API reference +============= + +Data structures +--------------- + +.. c:type:: YR_COMPILER + + Data structure representing a YARA compiler. + +.. c:type:: YR_MATCH + + Data structure representing a string match. + + .. c:member:: int64_t base + + Base offset/address for the match. While scanning a file this field is + usually zero, while scanning a process memory space this field is the + virtual address of the memory block where the match was found. + + .. c:member:: int64_t offset + + Offset of the match relative to *base*. + + .. c:member:: int32_t match_length + + Length of the matching string + + .. c:member:: const uint8_t* data + + Pointer to a buffer containing a portion of the matching string. + + .. c:member:: int32_t data_length + + Length of ``data`` buffer. ``data_length`` is the minimum of + ``match_length`` and ``MAX_MATCH_DATA``. + + .. versionchanged:: 3.5.0 + +.. c:type:: YR_META + + Data structure representing a metadata value. + + .. c:member:: const char* identifier + + Meta identifier. + + .. c:member:: int32_t type + + One of the following metadata types: + + ``META_TYPE_NULL`` + ``META_TYPE_INTEGER`` + ``META_TYPE_STRING`` + ``META_TYPE_BOOLEAN`` + +.. c:type:: YR_MODULE_IMPORT + + .. c:member:: const char* module_name + + Name of the module being imported. + + .. c:member:: void* module_data + + Pointer to additional data passed to the module. Initially set to + ``NULL``, your program is responsible for setting this pointer while + handling the CALLBACK_MSG_IMPORT_MODULE message. + + .. c:member:: size_t module_data_size + + Size of additional data passed to module. Your program must set the + appropriate value if ``module_data`` is modified. + +.. c:type:: YR_RULE + + Data structure representing a single rule. + + .. c:member:: const char* identifier + + Rule identifier. + + .. c:member:: const char* tags + + Pointer to a sequence of null terminated strings with tag names. An + additional null character marks the end of the sequence. Example: + ``tag1\0tag2\0tag3\0\0``. To iterate over the tags you can use + :c:func:`yr_rule_tags_foreach`. + + .. c:member:: YR_META* metas + + Pointer to a sequence of :c:type:`YR_META` structures. To iterate over the + structures use :c:func:`yr_rule_metas_foreach`. + + .. c:member:: YR_STRING* strings + + Pointer to a sequence of :c:type:`YR_STRING` structures. To iterate over the + structures use :c:func:`yr_rule_strings_foreach`. + + .. c:member:: YR_NAMESPACE* ns + + Pointer to a :c:type:`YR_NAMESPACE` structure. + +.. c:type:: YR_RULES + + Data structure representing a set of compiled rules. + +.. c:type:: YR_STREAM + + .. versionadded:: 3.4.0 + + Data structure representing a stream used with functions + :c:func:`yr_rules_load_stream` and :c:func:`yr_rules_save_stream`. + + .. c:member:: void* user_data + + A user-defined pointer. + + .. c:member:: YR_STREAM_READ_FUNC read + + A pointer to the stream's read function provided by the user. + + .. c:member:: YR_STREAM_WRITE_FUNC write + + A pointer to the stream's write function provided by the user. + +.. c:type:: YR_STRING + + Data structure representing a string declared in a rule. + + .. c:member:: const char* identifier + + String identifier. + +.. c:type:: YR_NAMESPACE + + Data structure representing a rule namespace. + + .. c:member:: const char* name + + Rule namespace. + +Functions +--------- + +.. c:function:: int yr_initialize(void) + + Initialize the library. Must be called by the main thread before using any + other function. Return :c:macro:`ERROR_SUCCESS` on success another error + code in case of error. The list of possible return codes vary according + to the modules compiled into YARA. + +.. c:function:: int yr_finalize(void) + + Finalize the library. Must be called by the main free to release any + resource allocated by the library. Return :c:macro:`ERROR_SUCCESS` on + success another error code in case of error. The list of possible return + codes vary according to the modules compiled into YARA. + +.. c:function:: void yr_finalize_thread(void) + + Any thread using the library, except the main thread, must call this + function when it finishes using the library. + +.. c:function:: int yr_compiler_create(YR_COMPILER** compiler) + + Create a YARA compiler. You must pass the address of a pointer to a + :c:type:`YR_COMPILER`, the function will set the pointer to the newly + allocated compiler. Returns one of the following error codes: + + :c:macro:`ERROR_SUCCESS` + + :c:macro:`ERROR_INSUFFICIENT_MEMORY` + +.. c:function:: void yr_compiler_destroy(YR_COMPILER* compiler) + + Destroy a YARA compiler. + +.. c:function:: void yr_compiler_set_callback(YR_COMPILER* compiler, YR_COMPILER_CALLBACK_FUNC callback, void* user_data) + + .. versionchanged:: 3.3.0 + + Set a callback for receiving error and warning information. The *user_data* + pointer is passed to the callback function. + + +.. c:function:: void yr_compiler_set_include_callback(YR_COMPILER* compiler, YR_COMPILER_INCLUDE_CALLBACK_FUNC callback, YR_COMPILER_INCLUDE_FREE_FUNC include_free, void* user_data) + + .. versionadded:: 3.7.0 + + Set a callback to provide rules from a custom source when ``include`` + directive is invoked. The *user_data* pointer is untouched and passed back to + the callback function and to the free function. Once the callback's result + is no longer needed, the include_free function will be called. If the memory + does not need to be freed, include_free can be set to NULL. If *callback* is + set to ``NULL`` support for include directives is disabled. + + +.. c:function:: int yr_compiler_add_file(YR_COMPILER* compiler, FILE* file, const char* namespace, const char* file_name) + + Compile rules from a *file*. Rules are put into the specified *namespace*, + if *namespace* is ``NULL`` they will be put into the default namespace. + *file_name* is the name of the file for error reporting purposes and can be + set to ``NULL``. Returns the number of errors found during compilation. + + +.. c:function:: int yr_compiler_add_fd(YR_COMPILER* compiler, YR_FILE_DESCRIPTOR rules_fd, const char* namespace, const char* file_name) + + .. versionadded:: 3.6.0 + + Compile rules from a *file descriptor*. Rules are put into the specified *namespace*, + if *namespace* is ``NULL`` they will be put into the default namespace. + *file_name* is the name of the file for error reporting purposes and can be + set to ``NULL``. Returns the number of errors found during compilation. + + +.. c:function:: int yr_compiler_add_string(YR_COMPILER* compiler, const char* string, const char* namespace_) + + Compile rules from a *string*. Rules are put into the specified *namespace*, + if *namespace* is ``NULL`` they will be put into the default namespace. + Returns the number of errors found during compilation. + +.. c:function:: int yr_compiler_get_rules(YR_COMPILER* compiler, YR_RULES** rules) + + Get the compiled rules from the compiler. Returns one of the following error + codes: + + :c:macro:`ERROR_SUCCESS` + + :c:macro:`ERROR_INSUFFICIENT_MEMORY` + +.. c:function:: int yr_compiler_define_integer_variable(YR_COMPILER* compiler, const char* identifier, int64_t value) + + Defines an integer external variable. + +.. c:function:: int yr_compiler_define_float_variable(YR_COMPILER* compiler, const char* identifier, double value) + + Defines a float external variable. + +.. c:function:: int yr_compiler_define_boolean_variable(YR_COMPILER* compiler, const char* identifier, int value) + + Defines a boolean external variable. + +.. c:function:: int yr_compiler_define_string_variable(YR_COMPILER* compiler, const char* identifier, const char* value) + + Defines a string external variable. + +.. c:function:: void yr_rules_destroy(YR_RULES* rules) + + Destroy compiled rules. + +.. c:function:: int yr_rules_save(YR_RULES* rules, const char* filename) + + Save compiled *rules* into the file specified by *filename*. Only rules + obtained from :c:func:`yr_compiler_get_rules` can be saved. Those obtained + from :c:func:`yr_rules_load` or :c:func:`yr_rules_load_stream` can not be + saved. Returns one of the following error codes: + + :c:macro:`ERROR_SUCCESS` + + :c:macro:`ERROR_COULD_NOT_OPEN_FILE` + +.. c:function:: int yr_rules_save_stream(YR_RULES* rules, YR_STREAM* stream) + + .. versionadded:: 3.4.0 + + Save compiled *rules* into *stream*. Only rules obtained from + :c:func:`yr_compiler_get_rules` can be saved. Those obtained from + :c:func:`yr_rules_load` or :c:func:`yr_rules_load_stream` can not be saved. + Returns one of the following error codes: + + :c:macro:`ERROR_SUCCESS` + +.. c:function:: int yr_rules_load(const char* filename, YR_RULES** rules) + + Load compiled rules from the file specified by *filename*. Returns one of the + following error codes: + + :c:macro:`ERROR_SUCCESS` + + :c:macro:`ERROR_INSUFFICIENT_MEMORY` + + :c:macro:`ERROR_COULD_NOT_OPEN_FILE` + + :c:macro:`ERROR_INVALID_FILE` + + :c:macro:`ERROR_CORRUPT_FILE` + + :c:macro:`ERROR_UNSUPPORTED_FILE_VERSION` + +.. c:function:: int yr_rules_load_stream(YR_STREAM* stream, YR_RULES** rules) + + .. versionadded:: 3.4.0 + + Load compiled rules from *stream*. Rules loaded this way can not be saved + back using :c:func:`yr_rules_save_stream`. Returns one of the following error + codes: + + :c:macro:`ERROR_SUCCESS` + + :c:macro:`ERROR_INSUFFICIENT_MEMORY` + + :c:macro:`ERROR_INVALID_FILE` + + :c:macro:`ERROR_CORRUPT_FILE` + + :c:macro:`ERROR_UNSUPPORTED_FILE_VERSION` + +.. c:function:: int yr_rules_scan_mem(YR_RULES* rules, const uint8_t* buffer, size_t buffer_size, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) + + Scan a memory buffer. Returns one of the following error codes: + + :c:macro:`ERROR_SUCCESS` + + :c:macro:`ERROR_INSUFFICIENT_MEMORY` + + :c:macro:`ERROR_TOO_MANY_SCAN_THREADS` + + :c:macro:`ERROR_SCAN_TIMEOUT` + + :c:macro:`ERROR_CALLBACK_ERROR` + + :c:macro:`ERROR_TOO_MANY_MATCHES` + + +.. c:function:: int yr_rules_scan_file(YR_RULES* rules, const char* filename, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) + + Scan a file. Returns one of the following error codes: + + :c:macro:`ERROR_SUCCESS` + + :c:macro:`ERROR_INSUFFICIENT_MEMORY` + + :c:macro:`ERROR_COULD_NOT_MAP_FILE` + + :c:macro:`ERROR_ZERO_LENGTH_FILE` + + :c:macro:`ERROR_TOO_MANY_SCAN_THREADS` + + :c:macro:`ERROR_SCAN_TIMEOUT` + + :c:macro:`ERROR_CALLBACK_ERROR` + + :c:macro:`ERROR_TOO_MANY_MATCHES` + +.. c:function:: int yr_rules_scan_fd(YR_RULES* rules, YR_FILE_DESCRIPTOR fd, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) + + Scan a file descriptor. In POSIX systems ``YR_FILE_DESCRIPTOR`` is an ``int``, + as returned by the `open()` function. In Windows ``YR_FILE_DESCRIPTOR`` is a + ``HANDLE`` as returned by `CreateFile()`. + + + Returns one of the following error codes: + + :c:macro:`ERROR_SUCCESS` + + :c:macro:`ERROR_INSUFFICIENT_MEMORY` + + :c:macro:`ERROR_COULD_NOT_MAP_FILE` + + :c:macro:`ERROR_ZERO_LENGTH_FILE` + + :c:macro:`ERROR_TOO_MANY_SCAN_THREADS` + + :c:macro:`ERROR_SCAN_TIMEOUT` + + :c:macro:`ERROR_CALLBACK_ERROR` + + :c:macro:`ERROR_TOO_MANY_MATCHES` + +.. c:function:: yr_rule_tags_foreach(rule, tag) + + Iterate over the tags of a given rule running the block of code that follows + each time with a different value for *tag* of type ``const char*``. Example: + + .. code-block:: c + + const char* tag; + + /* rule is a YR_RULE object */ + + yr_rule_tags_foreach(rule, tag) + { + ..do something with tag + } + +.. c:function:: yr_rule_metas_foreach(rule, meta) + + Iterate over the :c:type:`YR_META` structures associated with a given rule + running the block of code that follows each time with a different value for + *meta*. Example: + + .. code-block:: c + + YR_META* meta; + + /* rule is a YR_RULE object */ + + yr_rule_metas_foreach(rule, meta) + { + ..do something with meta + } + +.. c:function:: yr_rule_strings_foreach(rule, string) + + Iterate over the :c:type:`YR_STRING` structures associated with a given rule + running the block of code that follows each time with a different value for + *string*. Example: + + .. code-block:: c + + YR_STRING* string; + + /* rule is a YR_RULE object */ + + yr_rule_strings_foreach(rule, string) + { + ..do something with string + } + +.. c:function:: yr_string_matches_foreach(string, match) + + Iterate over the :c:type:`YR_MATCH` structures associated with a given string + running the block of code that follows each time with a different value for + *match*. Example: + + .. code-block:: c + + YR_MATCH* match; + + /* string is a YR_STRING object */ + + yr_string_matches_foreach(string, match) + { + ..do something with match + } + +.. c:function:: yr_rules_foreach(rules, rule) + + Iterate over each :c:type:`YR_RULE` in a :c:type:`YR_RULES` object running + the block of code that follows each time with a different value for + *rule*. Example: + + .. code-block:: c + + YR_RULE* rule; + + /* rules is a YR_RULES object */ + + yr_rules_foreach(rules, rule) + { + ..do something with rule + } + +.. c:function:: yr_rule_disable(rule) + + .. versionadded:: 3.7.0 + + Disable the specified rule. Disabled rules are completely ignored during + the scanning process and they won't match. If the disabled rule is used in + the condition of some other rule the value for the disabled rule is neither + true nor false but undefined. For more information about undefined values + see :ref:`undefined-values`. + +.. c:function:: yr_rule_enable(rule) + + .. versionadded:: 3.7.0 + + Enables the specified rule. After being disabled with :c:func:`yr_rule_disable` + a rule can be enabled again by using this function. + + +Error codes +----------- + +.. c:macro:: ERROR_SUCCESS + + Everything went fine. + +.. c:macro:: ERROR_INSUFFICIENT_MEMORY + + Insufficient memory to complete the operation. + +.. c:macro:: ERROR_COULD_NOT_OPEN_FILE + + File could not be opened. + +.. c:macro:: ERROR_COULD_NOT_MAP_FILE + + File could not be mapped into memory. + +.. c:macro:: ERROR_ZERO_LENGTH_FILE + + File length is zero. + +.. c:macro:: ERROR_INVALID_FILE + + File is not a valid rules file. + +.. c:macro:: ERROR_CORRUPT_FILE + + Rules file is corrupt. + +.. c:macro:: ERROR_UNSUPPORTED_FILE_VERSION + + File was generated by a different YARA and can't be loaded by this version. + +.. c:macro:: ERROR_TOO_MANY_SCAN_THREADS + + Too many threads trying to use the same :c:type:`YR_RULES` object + simultaneously. The limit is defined by ``MAX_THREADS`` in + *./include/yara/limits.h* + +.. c:macro:: ERROR_SCAN_TIMEOUT + + Scan timed out. + +.. c:macro:: ERROR_CALLBACK_ERROR + + Callback returned an error. + +.. c:macro:: ERROR_TOO_MANY_MATCHES + + Too many matches for some string in your rules. This usually happens when + your rules contains very short or very common strings like ``01 02`` or + ``FF FF FF FF``. The limit is defined by ``MAX_STRING_MATCHES`` in + *./include/yara/limits.h* diff --git a/yara-master/docs/commandline.rst b/yara-master/docs/commandline.rst new file mode 100644 index 0000000..f944486 --- /dev/null +++ b/yara-master/docs/commandline.rst @@ -0,0 +1,166 @@ +.. _command-line: + +********************************** +Running YARA from the command-line +********************************** + +In order to invoke YARA you’ll need two things: a file with the rules you want +to use (either in source code or compiled form) and the target to be scanned. +The target can be a file, a folder, or a process. :: + + yara [OPTIONS] RULES_FILE TARGET + + +``RULES_FILE`` can be passed directly in source code form, or can be previously +compiled with the ``yarac`` tool. You may prefer to use your rules in compiled +form if you are going to invoke YARA multiple times with the same rules. This +way you’ll save time, because for YARA it is faster to load compiled rules than +compiling the same rules over and over again. + +You can also pass multiple source files to `yara` like in the following example:: + + yara [OPTIONS] RULES_FILE_1 RULES_FILE_2 RULES_FILE_3 TARGET + +Notice however that this only works for rules in source form. When invoking YARA +with compiled rules a single file is accepted. + +In the example above all rules share the same "default" namespace, which means +that rule identifiers must be unique among all files. However you can specify a +namespace for individual files. For example :: + + yara [OPTIONS] namespace1:RULES_FILE_1 RULES_FILE_2 RULES_FILE_3 TARGET + +In this case ``RULE_FILE_1`` uses ``namespace1`` while ``RULES_FILE_2`` and +``RULES_FILE_3`` share the default namespace. + +In all cases rules will be applied to the target specified as the last argument +to YARA, if it’s a path to a directory all the files contained in it will be +scanned. By default YARA does not attempt to scan directories recursively, but +you can use the ``-r`` option for that. + +Available options are: + +.. program:: yara + +.. option:: -t --tag= + + Print rules tagged as and ignore the rest. + +.. option:: -i --identifier= + + Print rules named and ignore the rest. + +.. option:: -c --count + + Print only number of matches. + +.. option:: -n + + Print not satisfied rules only (negate). + +.. option:: -D --print-module-data + + Print module data. + +.. option:: -g --print-tags + + Print tags. + +.. option:: -m --print-meta + + Print metadata. + +.. option:: -s --print-strings + + Print matching strings. + +.. option:: -L --print-string-length + + Print length of matching strings. + +.. option:: -e --print-namespace + + Print rules' namespace. + +.. option:: -p --threads= + + Use the specified of threads to scan a directory. + +.. option:: -l --max-rules= + + Abort scanning after matching a number of rules. + +.. option:: -a --timeout= + + Abort scanning after a number of seconds has elapsed. + +.. option:: -k --stack-size= + + Allocate a stack size of "slots" number of slots. Default: 16384. This + will allow you to use larger rules, albeit with more memory overhead. + + .. versionadded:: 3.5.0 + +.. option:: --max-strings-per-rule= + + Set maximum number of strings per rule (default=10000). If a rule has more + then the specified number of strings an error will occur. + + .. versionadded:: 3.7.0 + +.. option:: -d = + + Define external variable. + +.. option:: -x = + + Pass file's content as extra data to module. + +.. option:: -r --recursive + + Recursively search for directories. + +.. option:: -f --fast-scan + + Fast matching mode. + +.. option:: -w --no-warnings + + Disable warnings. + +.. option:: --fail-on-warnings + + Treat warnings as errors. Has no effect if used with --no-warnings. + +.. option:: -v --version + + Show version information. + +.. option:: -h --help + + Show help. + +Here you have some examples: + +* Apply rule in */foo/bar/rules* to all files in the current directory. + Subdirectories are not scanned:: + + yara /foo/bar/rules . + +* Apply rules in */foo/bar/rules* to *bazfile*. Only reports rules tagged as + *Packer* or *Compiler*:: + + yara -t Packer -t Compiler /foo/bar/rules bazfile + +* Scan all files in the */foo* directory and its subdirectories:: + + yara -r /foo + +* Defines three external variables *mybool*, *myint* and *mystring*:: + + yara -d mybool=true -d myint=5 -d mystring="my string" /foo/bar/rules bazfile + +* Apply rules in */foo/bar/rules* to *bazfile* while passing the content of + *cuckoo_json_report* to the cuckoo module:: + + yara -x cuckoo=cuckoo_json_report /foo/bar/rules bazfile diff --git a/yara-master/docs/conf.py b/yara-master/docs/conf.py new file mode 100644 index 0000000..c876d50 --- /dev/null +++ b/yara-master/docs/conf.py @@ -0,0 +1,267 @@ +# -*- coding: utf-8 -*- +# +# yara documentation build configuration file, created by +# sphinx-quickstart on Tue Jul 8 11:04:03 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'yara' +copyright = u'2014-2017, VirusTotal' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '3.7' +# The full version, including alpha/beta/rc tags. +release = '3.7.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + + + + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +try: + import sphinx_rtd_theme + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +except: + html_theme = "default" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'yaradoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'yara.tex', u'yara Documentation', + u'Victor M. Alvarez', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'yara', u'yara Documentation', + [u'Victor M. Alvarez'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'yara', u'yara Documentation', + u'Victor M. Alvarez', 'yara', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/yara-master/docs/gettingstarted.rst b/yara-master/docs/gettingstarted.rst new file mode 100644 index 0000000..884db7b --- /dev/null +++ b/yara-master/docs/gettingstarted.rst @@ -0,0 +1,140 @@ +*************** +Getting started +*************** + +YARA is a multi-platform program running on Windows, Linux and Mac OS X. You can +find the latest release at https://github.com/VirusTotal/yara/releases. + +.. _compiling-yara: + +Compiling and installing YARA +============================= + +Download the source tarball and get prepared for compiling it:: + + tar -zxf yara-3.7.0.tar.gz + cd yara-3.7.0 + ./bootstrap.sh + +Make sure you have ``automake``, ``libtool``, ``make`` and ``gcc`` installed +in your system. Ubuntu and Debian users can use:: + + sudo apt-get install automake libtool make gcc + +If you plan to modify YARA's source code you may also need ``flex`` and +``bison`` for generating lexers and parsers:: + + sudo apt-get install flex bison + +Compile and install YARA in the standard way:: + + ./configure + make + sudo make install + +Run the test cases to make sure that everything is fine:: + + make check + +Some of YARA's features depend on the OpenSSL library. Those features are +enabled only if you have the OpenSSL library installed in your system. If not, +YARA is going to work fine but you won't be able to use the disabled features. +The ``configure`` script will automatically detect if OpenSSL is installed or +not. If you want to enforce the OpenSSL-dependent features you must pass +``--with-crypto`` to the ``configure`` script. Ubuntu and Debian users can use +``sudo apt-get install libssl-dev`` to install the OpenSSL library. + +The following modules are not compiled into YARA by default: + +* cuckoo +* magic +* dotnet + +If you plan to use them you must pass the corresponding ``--enable-`` arguments to the ``configure`` script. + +For example:: + + ./configure --enable-cuckoo + ./configure --enable-magic + ./configure --enable-dotnet + ./configure --enable-cuckoo --enable-magic --enable-dotnet + +Modules usually depend on external libraries, depending on the modules you +choose to install you'll need the following libraries: + +* cuckoo: + Depends on `Jansson `_ for parsing JSON. + Some Ubuntu and Debian versions already include a package named + ``libjansson-dev``, if ``sudo apt-get install libjansson-dev`` doesn't + work for you then get the source code from + `its repository `_. + + +* magic: + Depends on *libmagic*, a library used by the Unix standard program + `file `_. + Ubuntu, Debian and CentOS include a package + ``libmagic-dev``. The source code can be found + `here `_. + + +Installing on Windows +--------------------- + +Compiled binaries for Windows in both 32 and 64 bit flavors can be found in the +link below. Just download the version you want, unzip the archive, and put the +``yara.exe`` and ``yarac.exe`` binaries anywhere in your disk. + +To install the ``yara-python`` extension download and execute the installer +corresponding to the version of Python you're using. + +`Download Windows binaries `_ + + +Installing on Mac OS X with Homebrew +------------------------------------ + +To install YARA using `Homebrew `_, simply type +``brew install yara``. + + +Installing yara-python +---------------------- + +If you plan to use YARA from your Python scripts you need to install the +``yara-python`` extension. Please refer to https://github.com/VirusTotal/yara-python +for instructions on how to install it. + + +Running YARA for the first time +=============================== + +Now that you have installed YARA you can write a very simple rule and use the +command-line tool to scan some file:: + + echo "rule dummy { condition: true }" > my_first_rule + yara my_first_rule my_first_rule + +Don't get confused by the repeated ``my_first_rule`` in the arguments to +``yara``, I'm just passing the same file as both the rules and the file to +be scanned. You can pass any file you want to be scanned (second argument). + +If everything goes fine you should get the following output:: + + dummy my_first_rule + +Which means that the file ``my_first_rule`` is matching the rule named ``dummy``. + +If you get an error like this:: + + yara: error while loading shared libraries: libyara.so.2: cannot open shared + object file: No such file or directory + +It means that the loader is not finding the ``libyara`` library which is +located in ``/usr/local/lib``. In some Linux flavors the loader doesn't look for +libraries in this path by default, we must instruct it to do so by adding +``/usr/local/lib`` to the loader configuration file ``/etc/ld.so.conf``:: + + sudo echo "/usr/local/lib" >> /etc/ld.so.conf + sudo ldconfig diff --git a/yara-master/docs/index.rst b/yara-master/docs/index.rst new file mode 100644 index 0000000..3dbc04b --- /dev/null +++ b/yara-master/docs/index.rst @@ -0,0 +1,45 @@ +.. yara documentation master file, created by + sphinx-quickstart on Tue Jul 8 11:04:03 2014. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to YARA's documentation! +================================ + +YARA is a tool aimed at (but not limited to) helping malware researchers to +identify and classify malware samples. With YARA you can create descriptions of malware families (or whatever you want to describe) based on textual or binary patterns. Each description, a.k.a rule, consists of a set of strings and a +boolean expression which determine its logic. Let's see an example:: + + rule silent_banker : banker + { + meta: + description = "This is just an example" + thread_level = 3 + in_the_wild = true + strings: + $a = {6A 40 68 00 30 00 00 6A 14 8D 91} + $b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9} + $c = "UVODFRYSIHLNWPEJXQZAKCBGMT" + condition: + $a or $b or $c + } + +The above rule is telling YARA that any file containing one of the three strings +must be reported as silent_banker. This is just a simple example, more complex +and powerful rules can be created by using wild-cards, case-insensitive strings, regular expressions, special operators and many other features that you'll find explained in this documentation. + +Contents: + +.. toctree:: + :maxdepth: 3 + + gettingstarted + writingrules + modules + writingmodules + commandline + yarapython + capi + + + diff --git a/yara-master/docs/make.bat b/yara-master/docs/make.bat new file mode 100644 index 0000000..2ae9d62 --- /dev/null +++ b/yara-master/docs/make.bat @@ -0,0 +1,242 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\yara.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\yara.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/yara-master/docs/modules.rst b/yara-master/docs/modules.rst new file mode 100644 index 0000000..2bedcca --- /dev/null +++ b/yara-master/docs/modules.rst @@ -0,0 +1,25 @@ +******* +Modules +******* + +Modules are the method YARA provides for extending its features. They allow you +to define data structures and functions which can be used in your rules to +express more complex conditions. Here you'll find described some modules +officially distributed with YARA, but you can also learn how to write your own +modules in the :ref:`writing-modules` section. + + +.. toctree:: + :maxdepth: 3 + + PE + ELF + Cuckoo + Magic + Hash + Math + Dotnet + Time + + + diff --git a/yara-master/docs/modules/cuckoo.rst b/yara-master/docs/modules/cuckoo.rst new file mode 100644 index 0000000..4ecd8d8 --- /dev/null +++ b/yara-master/docs/modules/cuckoo.rst @@ -0,0 +1,149 @@ +.. _cuckoo-module: + +############# +Cuckoo module +############# + +The Cuckoo module enables you to create YARA rules based on behavioral +information generated by `Cuckoo sandbox `_. +While scanning a PE file with YARA, you can pass additional information about +its behavior to the ``cuckoo`` module and create rules based not only on what +it *contains*, but also on what it *does*. + +.. important:: + This module is not built into YARA by default, to learn how to include it + refer to :ref:`compiling-yara`. Good news for Windows users: this module + is already included in the official Windows binaries. + +Suppose that you're interested in executable files sending a HTTP request to +http://someone.doingevil.com. In previous versions of YARA you had to settle +with:: + + rule evil_doer + { + strings: + $evil_domain = "http://someone.doingevil.com" + + condition: + $evil_domain + } + + +The problem with this rule is that the domain name could be contained in the +file for perfectly valid reasons not related with sending HTTP requests to +http://someone.doingevil.com. Furthermore, the malicious executable could +contain the domain name ciphered or obfuscated, in which case your rule +would be completely useless. + +But now with the ``cuckoo`` module you can take the behavior report generated +for the executable file by your Cuckoo sandbox, pass it alongside the +executable file to YARA, and write a rule like this:: + + import "cuckoo" + + rule evil_doer + { + condition: + cuckoo.network.http_request(/http:\/\/someone\.doingevil\.com/) + } + +Of course you can mix your behavior-related conditions with good old +string-based conditions:: + + import "cuckoo" + + rule evil_doer + { + strings: + $some_string = { 01 02 03 04 05 06 } + + condition: + $some_string and + cuckoo.network.http_request(/http:\/\/someone\.doingevil\.com/) + } + + +But how do we pass the behavior information to the ``cuckoo`` module? Well, in +the case of the command-line tool you must use the ``-x`` option in this way:: + + $yara -x cuckoo=behavior_report_file rules_file pe_file + + +``behavior_report_file`` is the path to a file containing the behavior file +generated by the Cuckoo sandbox in JSON format. + +If you are using ``yara-python`` then you must pass the behavior report in the +``modules_data`` argument for the ``match`` method: + +.. code-block:: python + + import yara + rules = yara.compile('./rules_file') + report_file = open('./behavior_report_file') + report_data = report_file.read() + rules.match(pe_file, modules_data={'cuckoo': bytes(report_data)}) + + +Reference +--------- + +.. default-domain:: c + +.. type:: network + + .. function:: http_request(regexp) + + Function returning true if the program sent a HTTP request to a URL + matching the provided regular expression. + + *Example: cuckoo.network.http_request(/evil\\.com/)* + + .. function:: http_get(regexp) + + Similar to :func:`http_request`, but only takes into account GET + requests. + + .. function:: http_post(regexp) + + Similar to :func:`http_request`, but only takes into account POST + requests. + + .. function:: dns_lookup(regexp) + + Function returning true if the program sent a domain name resolution + request for a domain matching the provided regular expression. + + *Example: cuckoo.network.dns_lookup(/evil\\.com/)* + +.. type:: registry + + .. function:: key_access(regexp) + + Function returning true if the program accessed a registry entry + matching the provided regular expression. + + *Example: cuckoo.registry.key_access(/\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run/)* + +.. type:: filesystem + + .. function:: file_access(regexp) + + Function returning true if the program accessed a file matching the + provided regular expression. + + *Example: cuckoo.filesystem.file_access(/autoexec\\.bat/)* + +.. type:: sync + + .. function:: mutex(regexp) + + Function returning true if the program opens or creates a mutex matching + the provided regular expression. + + *Example: cuckoo.sync.mutex(/EvilMutexName/)* + + + + + + diff --git a/yara-master/docs/modules/dotnet.rst b/yara-master/docs/modules/dotnet.rst new file mode 100644 index 0000000..2411e4c --- /dev/null +++ b/yara-master/docs/modules/dotnet.rst @@ -0,0 +1,176 @@ + +.. _dotnet-module: + +############# +dotnet module +############# + +.. versionadded:: 3.6.0 + +The dotnet module allows you to create more fine-grained rules for .NET files by +using attributes and features of the .NET file format. Let's see some examples:: + + import "dotnet" + + rule not_exactly_five_streams + { + condition: + dotnet.number_of_streams != 5 + } + + rule blop_stream + { + condition: + for any i in (0..dotnet.number_of_streams - 1): + (dotnet.streams[i].name == "#Blop") + } + +Reference +--------- + +.. c:type:: version + + The version string contained in the metadata root. + + *Example: dotnet.version == "v2.0.50727"* + +.. c:type:: module_name + + The name of the module. + + *Example: dotnet.module_name == "axs"* + +.. c:type:: number_of_streams + + The number of streams in the file. + +.. c:type:: streams + + A zero-based array of stream objects, one for each stream contained in the + file. Individual streams can be accessed by using the [] operator. Each + stream object has the following attributes: + + .. c:member:: name + + Stream name. + + .. c:member:: offset + + Stream offset. + + .. c:member:: size + + Stream size. + + *Example: dotnet.streams[0].name == "#~"* + +.. c:type:: number_of_guids + + The number of GUIDs in the guids array. + +.. c:type:: guids + + A zero-based array of strings, one for each GUID. Individual guids can be + accessed by using the [] operator. + + *Example: dotnet.guids[0] == "99c08ffd-f378-a891-10ab-c02fe11be6ef"* + +.. c:type:: number_of_resources + + The number of resources in the .NET file. These are different from normal PE + resources. + +.. c:type:: resources + + A zero-based array of resource objects, one for each resource the .NET file + has. Individual resources can be accessed by using the [] operator. Each + resource object has the following attributes: + + .. c:member:: offset + + Offset for the resource data. + + .. c:member:: length + + Length of the resource data. + + .. c:member:: name + + Name of the resource (string). + + *Example: uint16be(dotnet.resources[0].offset) == 0x4d5a* + +.. c:type:: assembly + + Object for .NET assembly information. + + .. c:member:: version + + An object with integer values representing version information for this + assembly. Attributes are: + + ``major`` + ``minor`` + ``build_number`` + ``revision_number`` + + .. c:member:: name + + String containing the assembly name. + + .. c:member:: culture + + String containing the culture (language/country/region) for this + assembly. + + *Example: dotnet.assembly.name == "Keylogger"* + + *Example: dotnet.assembly.version.major == 7 and dotnet.assembly.version.minor == 0* + +.. c:type:: number_of_modulerefs + + The number of module references in the .NET file. + +.. c:type:: modulerefs + + A zero-based array of strings, one for each module reference the .NET file + has. Individual module references can be accessed by using the [] + operator. + + *Example: dotnet.modulerefs[0] == "kernel32"* + +.. c:type:: typelib + + The typelib of the file. + +.. c:type:: assembly_refs + + Object for .NET assembly reference information. + + .. c:member:: version + + An object with integer values representing version information for this + assembly. Attributes are: + + ``major`` + ``minor`` + ``build_number`` + ``revision_number`` + + .. c:member:: name + + String containing the assembly name. + + .. c:member:: public_key_or_token + + String containing the public key or token which identifies the author of + this assembly. + +.. c:type:: number_of_user_strings + + The number of user strings in the file. + +.. c:type:: user_strings + + An zero-based array of user strings, one for each stream contained in the + file. Individual strings can be accessed by using the [] operator. diff --git a/yara-master/docs/modules/elf.rst b/yara-master/docs/modules/elf.rst new file mode 100644 index 0000000..1206f20 --- /dev/null +++ b/yara-master/docs/modules/elf.rst @@ -0,0 +1,377 @@ + +.. _elf-module: + +########## +ELF module +########## + +.. versionadded:: 3.2.0 + +The ELF module is very similar to the :ref:`pe-module`, but for ELF files. This +module exposes most of the fields present in an ELF header. Let's see some +examples:: + + import "elf" + + rule single_section + { + condition: + elf.number_of_sections == 1 + } + + rule elf_64 + { + condition: + elf.machine == elf.EM_X86_64 + } + +Reference +--------- + +.. c:type:: type + + Integer with one of the following values: + + .. c:type:: ET_NONE + + No file type. + + .. c:type:: ET_REL + + Relocatable file. + + .. c:type:: ET_EXEC + + Executable file. + + .. c:type:: ET_DYN + + Shared object file. + + .. c:type:: ET_CORE + + Core file. + + *Example: elf.type == elf.ET_EXEC* + +.. c:type:: machine + + Integer with one of the following values: + + .. c:type:: EM_M32 + .. c:type:: EM_SPARC + .. c:type:: EM_386 + .. c:type:: EM_68K + .. c:type:: EM_88K + .. c:type:: EM_860 + .. c:type:: EM_MIPS + .. c:type:: EM_MIPS_RS3_LE + .. c:type:: EM_PPC + .. c:type:: EM_PPC64 + .. c:type:: EM_ARM + .. c:type:: EM_X86_64 + .. c:type:: EM_AARCH64 + + *Example: elf.machine == elf.EM_X86_64* + +.. c:type:: entry_point + + Entry point raw offset or virtual address depending on whether YARA is + scanning a file or process memory respectively. This is equivalent to the + deprecated ``entrypoint`` keyword. + +.. c:type:: number_of_sections + + Number of sections in the ELF file. + +.. c:type:: sections + + A zero-based array of section objects, one for each section the ELF has. + Individual sections can be accessed by using the [] operator. Each section + object has the following attributes: + + .. c:member:: name + + Section's name. + + *Example: elf.sections[3].name == ".bss"* + + .. c:member:: size + + Section's size in bytes. Unless the section type is SHT_NOBITS, the + section occupies sh_size bytes in the file. A section of + :c:type:`SHT_NOBITS` may have a non-zero size, but it occupies no space + in the file. + + .. c:member:: offset + + Offset from the beginning of the file to the first byte in the section. + One section type, :c:type:`SHT_NOBITS` described below, occupies no + space in the file, and its :c:member:`offset` member locates the + conceptual placement in the file. + + .. c:member:: type + + Integer with one of the following values: + + .. c:type:: SHT_NULL + + This value marks the section as inactive; it does not have + an associated section. Other members of the section header have + undefined values. + + .. c:type:: SHT_PROGBITS + + The section holds information defined by the program, whose format + and meaning are determined solely by the program. + + .. c:type:: SHT_SYMTAB + + The section holds a symbol table. + + .. c:type:: SHT_STRTAB + + The section holds a string table. An object file may have multiple + string table sections. + + .. c:type:: SHT_RELA + + The section holds relocation entries. + + .. c:type:: SHT_HASH + + The section holds a symbol hash table. + + .. c:type:: SHT_DYNAMIC + + The section holds information for dynamic linking. + + .. c:type:: SHT_NOTE + + The section holds information that marks the file in some way. + + .. c:type:: SHT_NOBITS + + A section of this type occupies no space in the file but otherwise resembles :c:type:`SHT_PROGBITS`. + + .. c:type:: SHT_REL + + The section holds relocation entries. + + .. c:type:: SHT_SHLIB + + This section type is reserved but has unspecified semantics. + + .. c:type:: SHT_DYNSYM + + This section holds dynamic linking symbols. + + .. c:member:: flags + + Integer with section's flags as defined below: + + .. c:type:: SHF_WRITE + + The section contains data that should be writable during process + execution. + + .. c:type:: SHF_ALLOC + + The section occupies memory during process execution. Some control sections do not reside in the memory image of an object file; this attribute is off for those sections. + + .. c:type:: SHF_EXECINSTR + + The section contains executable machine instructions. + + *Example: elf.sections[2].flags & elf.SHF_WRITE* + + .. c:member:: address + + .. versionadded:: 3.6.0 + + The virtual address the section starts at. + + +.. c:type:: number_of_segments + + .. versionadded:: 3.4.0 + + Number of segments in the ELF file. + +.. c:type:: segments + + .. versionadded:: 3.4.0 + + A zero-based array of segment objects, one for each segment the ELF has. + Individual segments can be accessed by using the [] operator. Each segment + object has the following attributes: + + .. c:member:: alignment + + Value to which the segments are aligned in memory and in the file. + + .. c:member:: file_size + + Number of bytes in the file image of the segment. It may be zero. + + .. c:member:: flags + + A combination of the following segment flags: + + .. c:type:: PF_R + + The segment is readable. + + .. c:type:: PF_W + + The segment is writable. + + .. c:type:: PF_X + + The segment is executable. + + .. c:member:: memory_size + + In-memory segment size. + + .. c:member:: offset + + Offset from the beginning of the file where the segment resides. + + .. c:member:: physical_address + + On systems for which physical addressing is relevant, contains the + segment's physical address. + + .. c:member:: type + + Type of segment indicated by one of the following values: + + .. c:type:: PT_NULL + .. c:type:: PT_LOAD + .. c:type:: PT_DYNAMIC + .. c:type:: PT_INTERP + .. c:type:: PT_NOTE + .. c:type:: PT_SHLIB + .. c:type:: PT_PHDR + .. c:type:: PT_LOPROC + .. c:type:: PT_HIPROC + .. c:type:: PT_GNU_STACK + + .. c:member:: virtual_address + + Virtual address at which the segment resides in memory. + +.. c:type:: dynamic_section_entries + + .. versionadded:: 3.6.0 + + Number of entries in the dynamic section in the ELF file. + +.. c:type:: dynamic + + .. versionadded:: 3.6.0 + + A zero-based array of dynamic objects, one for each entry in found in the + ELF's dynamic section. Individual dynamic objects can be accessed by using + the [] operator. Each dynamic object has the following attributes: + + .. c:member:: type + + Value that describes the type of dynamic section. Builtin values are: + + .. c:type:: DT_NULL + .. c:type:: DT_NEEDED + .. c:type:: DT_PLTRELSZ + .. c:type:: DT_PLTGOT + .. c:type:: DT_HASH + .. c:type:: DT_STRTAB + .. c:type:: DT_SYMTAB + .. c:type:: DT_RELA + .. c:type:: DT_RELASZ + .. c:type:: DT_RELAENT + .. c:type:: DT_STRSZ + .. c:type:: DT_SYMENT + .. c:type:: DT_INIT + .. c:type:: DT_FINI + .. c:type:: DT_SONAME + .. c:type:: DT_RPATH + .. c:type:: DT_SYMBOLIC + .. c:type:: DT_REL + .. c:type:: DT_RELSZ + .. c:type:: DT_RELENT + .. c:type:: DT_PLTREL + .. c:type:: DT_DEBUG + .. c:type:: DT_TEXTREL + .. c:type:: DT_JMPREL + .. c:type:: DT_BIND_NOW + .. c:type:: DT_INIT_ARRAY + .. c:type:: DT_FINI_ARRAY + .. c:type:: DT_INIT_ARRAYSZ + .. c:type:: DT_FINI_ARRAYSZ + .. c:type:: DT_RUNPATH + .. c:type:: DT_FLAGS + .. c:type:: DT_ENCODING + + .. c:member:: value + + A value associated with the given type. The type of value (address, + size, etc.) is dependant on the type of dynamic entry. + +.. c:type:: symtab_entries + + .. versionadded:: 3.6.0 + + Number of entries in the symbol table found in the ELF file. + +.. c:type:: symtab + + .. versionadded:: 3.6.0 + + A zero-based array of symbol objects, one for each entry in found in the + ELF's SYMBTAB. Individual symbol objects can be accessed by using the [] + operator. Each symbol object has the following attributes: + + .. c:member:: name + + The symbol's name. + + .. c:member:: value + + A value associated with the symbol. Generally a virtual address. + + .. c:member:: size + + The symbol's size. + + .. c:member:: type + + The type of symbol. Built values are: + + .. c:type:: STT_NOTYPE + .. c:type:: STT_OBJECT + .. c:type:: STT_FUNC + .. c:type:: STT_SECTION + .. c:type:: STT_FILE + .. c:type:: STT_COMMON + .. c:type:: STT_TLS + + .. c:member:: bind + + The binding of the symbol. Builtin values are: + + .. c:type:: STB_LOCAL + .. c:type:: STB_GLOBAL + .. c:type:: STB_WEAK + + .. c:member:: shndx + + The section index which the symbol is associated with. + + + + + + + + diff --git a/yara-master/docs/modules/hash.rst b/yara-master/docs/modules/hash.rst new file mode 100644 index 0000000..2a4da4b --- /dev/null +++ b/yara-master/docs/modules/hash.rst @@ -0,0 +1,66 @@ + +.. _hash-module: + +########### +Hash module +########### + +.. versionadded:: 3.2.0 + +The Hash module allows you to calculate hashes (MD5, SHA1, SHA256) from portions +of your file and create signatures based on those hashes. + +.. important:: + This module depends on the OpenSSL library. Please refer to + :ref:`compiling-yara` for information about how to build OpenSSL-dependant + features into YARA. + + Good news for Windows users: this module is already included in the official + Windows binaries. + +.. c:function:: md5(offset, size) + + Returns the MD5 hash for *size* bytes starting at *offset*. When scanning a + running process the *offset* argument should be a virtual address within + the process address space. The returned string is always in lowercase. + + *Example: hash.md5(0, filesize) == "feba6c919e3797e7778e8f2e85fa033d"* + +.. c:function:: md5(string) + + Returns the MD5 hash for the given string. + + *Example: hash.md5("dummy") == "275876e34cf609db118f3d84b799a790"* + +.. c:function:: sha1(offset, size) + + Returns the SHA1 hash for the *size* bytes starting at *offset*. When + scanning a running process the *offset* argument should be a virtual address + within the process address space. The returned string is always in + lowercase. + +.. c:function:: sha1(string) + + Returns the SHA1 hash for the given string. + +.. c:function:: sha256(offset, size) + + Returns the SHA256 hash for the *size* bytes starting at *offset*. When + scanning a running process the *offset* argument should be a virtual address + within the process address space. The returned string is always in + lowercase. + +.. c:function:: sha256(string) + + Returns the SHA256 hash for the given string. + +.. c:function:: checksum32(offset, size) + + Returns a 32-bit checksum for the *size* bytes starting at *offset*. The + checksum is just the sum of all the bytes (unsigned). + +.. c:function:: checksum32(string) + + Returns a 32-bit checksum for the given string. The checksum is just the + sum of all the bytes in the string (unsigned). + diff --git a/yara-master/docs/modules/magic.rst b/yara-master/docs/modules/magic.rst new file mode 100644 index 0000000..ccec20a --- /dev/null +++ b/yara-master/docs/modules/magic.rst @@ -0,0 +1,58 @@ + +.. _magic-module: + +############ +Magic module +############ + +.. versionadded:: 3.1.0 + +The Magic module allows you to identify the type of the file based on the +output of `file `_, the standard +Unix command. + +.. important:: + This module is not built into YARA by default, to learn how to include it + refer to :ref:`compiling-yara`. Bad news for Windows users: **this module is + not supported on Windows**. + +There are two functions in this module: :c:func:`type` and :c:func:`mime_type`. +The first one returns the descriptive string returned by *file*, for example, +if you run *file* against some PDF document you'll get something like this:: + + $file some.pdf + some.pdf: PDF document, version 1.5 + +The :c:func:`type` function would return *"PDF document, version 1.5"* in this +case. Using the :c:func:`mime_type` function is similar to passing the +``--mime`` argument to *file*.:: + + $file --mime some.pdf + some.pdf: application/pdf; charset=binary + + +:c:func:`mime_type` would return *"application/pdf"*, without the charset part. + +By experimenting a little with the *file* command you can learn which output to +expect for different file types. These are a few examples: + + * JPEG image data, JFIF standard 1.01 + * PE32 executable for MS Windows (GUI) Intel 80386 32-bit + * PNG image data, 1240 x 1753, 8-bit/color RGBA, non-interlaced + * ASCII text, with no line terminators + * Zip archive data, at least v2.0 to extract + + + +.. c:function:: type() + + Function returning a string with the type of the file. + + *Example: magic.type() contains "PDF"* + + +.. c:function:: mime_type() + + Function returning a string with the MIME type of the file. + + *Example: magic.mime_type() == "application/pdf"* diff --git a/yara-master/docs/modules/math.rst b/yara-master/docs/modules/math.rst new file mode 100644 index 0000000..64910f8 --- /dev/null +++ b/yara-master/docs/modules/math.rst @@ -0,0 +1,100 @@ + +.. _math-module: + +########### +Math module +########### + +.. versionadded:: 3.3.0 + +The Math module allows you to calculate certain values from portions of your +file and create signatures based on those results. + +.. important:: + Where noted these functions return floating point numbers. YARA is able to + convert integers to floating point numbers during most operations. For + example this will convert 7 to 7.0 automatically, because the return type + of the entropy function is a floating point value: + + *math.entropy(0, filesize) >= 7* + + The one exception to this is when a function requires a floating point + number as an argument. For example, this will cause a syntax error because + the arguments must be floating point numbers: + + *math.in_range(2, 1, 3)* + +.. c:function:: entropy(offset, size) + + Returns the entropy for *size* bytes starting at *offset*. When scanning a + running process the *offset* argument should be a virtual address within + the process address space. The returned value is a float. + + *Example: math.entropy(0, filesize) >= 7* + +.. c:function:: entropy(string) + + Returns the entropy for the given string. + + *Example: math.entropy("dummy") > 7* + +.. c:function:: monte_carlo_pi(offset, size) + + Returns the percentage away from Pi for the *size* bytes starting at + *offset* when run through the Monte Carlo from Pi test. When scanning a + running process the *offset* argument should be a virtual address within + the process address space. The returned value is a float. + + *Example: math.monte_carlo_pi(0, filesize) < 0.07* + +.. c:function:: monte_carlo_pi(string) + + Return the percentage away from Pi for the given string. + +.. c:function:: serial_correlation(offset, size) + + Returns the serial correlation for the *size* bytes starting at *offset*. + When scanning a running process the *offset* argument should be a virtual + address within the process address space. The returned value is a float + between 0.0 and 1.0. + + *Example: math.serial_correlation(0, filesize) < 0.2* + +.. c:function:: serial_correlation(string) + + Return the serial correlation for the given string. + +.. c:function:: mean(offset, size) + + Returns the mean for the *size* bytes starting at *offset*. When scanning + a running process the *offset* argument should be a virtual address within + the process address space. The returned value is a float. + + *Example: math.mean(0, filesize) < 72.0* + +.. c:function:: mean(string) + + Return the mean for the given string. + +.. c:function:: deviation(offset, size, mean) + + Returns the deviation from the mean for the *size* bytes starting at + *offset*. When scanning a running process the *offset* argument should be + a virtual address within the process address space. The returned value is + a float. + + The mean of an equally distributed random sample of bytes is 127.5, which + is available as the constant math.MEAN_BYTES. + + *Example: math.deviation(0, filesize, math.MEAN_BYTES) == 64.0* + +.. c:function:: deviation(string, mean) + + Return the deviation from the mean for the given string. + +.. c:function:: in_range(test, lower, upper) + + Returns true if the *test* value is between *lower* and *upper* values. The + comparisons are inclusive. + + *Example: math.in_range(math.deviation(0, filesize, math.MEAN_BYTES), 63.9, 64,1)* diff --git a/yara-master/docs/modules/pe.rst b/yara-master/docs/modules/pe.rst new file mode 100644 index 0000000..a3f414f --- /dev/null +++ b/yara-master/docs/modules/pe.rst @@ -0,0 +1,661 @@ + +.. _pe-module: + +######### +PE module +######### + +The PE module allows you to create more fine-grained rules for PE files by +using attributes and features of the PE file format. This module exposes most of +the fields present in a PE header and provides functions which can be used to +write more expressive and targeted rules. Let's see some examples:: + + import "pe" + + rule single_section + { + condition: + pe.number_of_sections == 1 + } + + rule control_panel_applet + { + condition: + pe.exports("CPlApplet") + } + + rule is_dll + { + condition: + pe.characteristics & pe.DLL + } + +Reference +--------- + +.. c:type:: machine + + .. versionchanged:: 3.3.0 + + Integer with one of the following values: + + .. c:type:: MACHINE_UNKNOWN + .. c:type:: MACHINE_AM33 + .. c:type:: MACHINE_AMD64 + .. c:type:: MACHINE_ARM + .. c:type:: MACHINE_ARMNT + .. c:type:: MACHINE_ARM64 + .. c:type:: MACHINE_EBC + .. c:type:: MACHINE_I386 + .. c:type:: MACHINE_IA64 + .. c:type:: MACHINE_M32R + .. c:type:: MACHINE_MIPS16 + .. c:type:: MACHINE_MIPSFPU + .. c:type:: MACHINE_MIPSFPU16 + .. c:type:: MACHINE_POWERPC + .. c:type:: MACHINE_POWERPCFP + .. c:type:: MACHINE_R4000 + .. c:type:: MACHINE_SH3 + .. c:type:: MACHINE_SH3DSP + .. c:type:: MACHINE_SH4 + .. c:type:: MACHINE_SH5 + .. c:type:: MACHINE_THUMB + .. c:type:: MACHINE_WCEMIPSV2 + + *Example: pe.machine == pe.MACHINE_AMD64* + +.. c:type:: checksum + + .. versionadded:: 3.6.0 + + Integer with the "PE checksum" as stored in the OptionalHeader + +.. c:type:: calculate_checksum + + .. versionadded:: 3.6.0 + + Function that calculates the "PE checksum" + + *Example: pe.checksum == pe.calculate_checksum()* + +.. c:type:: subsystem + + Integer with one of the following values: + + .. c:type:: SUBSYSTEM_UNKNOWN + .. c:type:: SUBSYSTEM_NATIVE + .. c:type:: SUBSYSTEM_WINDOWS_GUI + .. c:type:: SUBSYSTEM_WINDOWS_CUI + .. c:type:: SUBSYSTEM_OS2_CUI + .. c:type:: SUBSYSTEM_POSIX_CUI + .. c:type:: SUBSYSTEM_NATIVE_WINDOWS + .. c:type:: SUBSYSTEM_WINDOWS_CE_GUI + .. c:type:: SUBSYSTEM_EFI_APPLICATION + .. c:type:: SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER + .. c:type:: SUBSYSTEM_EFI_RUNTIME_DRIVER + .. c:type:: SUBSYSTEM_XBOX + .. c:type:: SUBSYSTEM_WINDOWS_BOOT_APPLICATION + + *Example: pe.subsystem == pe.SUBSYSTEM_NATIVE* + +.. c:type:: timestamp + + PE timestamp. + +.. c:type:: entry_point + + Entry point raw offset or virtual address depending on whether YARA is + scanning a file or process memory respectively. This is equivalent to the + deprecated ``entrypoint`` keyword. + +.. c:type:: image_base + + Image base relative virtual address. + +.. c:type:: characteristics + + Bitmap with PE FileHeader characteristics. Individual characteristics + can be inspected by performing a bitwise AND operation with the + following constants: + + .. c:type:: RELOCS_STRIPPED + .. c:type:: EXECUTABLE_IMAGE + .. c:type:: LINE_NUMS_STRIPPED + .. c:type:: LOCAL_SYMS_STRIPPED + .. c:type:: AGGRESIVE_WS_TRIM + .. c:type:: LARGE_ADDRESS_AWARE + .. c:type:: BYTES_REVERSED_LO + .. c:type:: MACHINE_32BIT + .. c:type:: DEBUG_STRIPPED + .. c:type:: REMOVABLE_RUN_FROM_SWAP + .. c:type:: NET_RUN_FROM_SWAP + .. c:type:: SYSTEM + .. c:type:: DLL + .. c:type:: UP_SYSTEM_ONLY + .. c:type:: BYTES_REVERSED_HI + + *Example: pe.characteristics & pe.DLL* + +.. c:type:: linker_version + + An object with two integer attributes, one for each major and minor linker + version. + + .. c:member:: major + + Major linker version. + + .. c:member:: minor + + Minor linker version. + +.. c:type:: os_version + + An object with two integer attributes, one for each major and minor OS + version. + + .. c:member:: major + + Major OS version. + + .. c:member:: minor + + Minor OS version. + +.. c:type:: image_version + + An object with two integer attributes, one for each major and minor image + version. + + .. c:member:: major + + Major image version. + + .. c:member:: minor + + Minor image version. + +.. c:type:: subsystem_version + + An object with two integer attributes, one for each major and minor subsystem + version. + + .. c:member:: major + + Major subsystem version. + + .. c:member:: minor + + Minor subsystem version. + +.. c:type:: dll_characteristics + + Bitmap with PE OptionalHeader DllCharacteristics. Do not confuse these + flags with the PE FileHeader Characteristics. Individual + characteristics can be inspected by performing a bitwise AND + operation with the following constants: + + .. c:type:: DYNAMIC_BASE + + File can be relocated - also marks the file as ASLR compatible + + .. c:type:: FORCE_INTEGRITY + .. c:type:: NX_COMPAT + + Marks the file as DEP compatible + + .. c:type:: NO_ISOLATION + .. c:type:: NO_SEH + + The file does not contain structured exception handlers, this must be + set to use SafeSEH + + .. c:type:: NO_BIND + .. c:type:: WDM_DRIVER + + Marks the file as a Windows Driver Model (WDM) device driver. + + .. c:type:: TERMINAL_SERVER_AWARE + + Marks the file as terminal server compatible + +.. c:type:: number_of_sections + + Number of sections in the PE. + +.. c:type:: sections + + .. versionadded:: 3.3.0 + + A zero-based array of section objects, one for each section the PE has. + Individual sections can be accessed by using the [] operator. Each section + object has the following attributes: + + .. c:member:: name + + Section name. + + .. c:member:: characteristics + + Section characteristics. + + .. c:member:: virtual_address + + Section virtual address. + + .. c:member:: virtual_size + + Section virtual size. + + .. c:member:: raw_data_offset + + Section raw offset. + + .. c:member:: raw_data_size + + Section raw size. + + *Example: pe.sections[0].name == ".text"* + + Individual section characteristics can be inspected using a bitwise AND + operation with the following constants: + + .. c:type:: SECTION_CNT_CODE + .. c:type:: SECTION_CNT_INITIALIZED_DATA + .. c:type:: SECTION_CNT_UNINITIALIZED_DATA + .. c:type:: SECTION_GPREL + .. c:type:: SECTION_MEM_16BIT + .. c:type:: SECTION_LNK_NRELOC_OVFL + .. c:type:: SECTION_MEM_DISCARDABLE + .. c:type:: SECTION_MEM_NOT_CACHED + .. c:type:: SECTION_MEM_NOT_PAGED + .. c:type:: SECTION_MEM_SHARED + .. c:type:: SECTION_MEM_EXECUTE + .. c:type:: SECTION_MEM_READ + .. c:type:: SECTION_MEM_WRITE + + *Example: pe.sections[1].characteristics & SECTION_CNT_CODE* + +.. c:type:: overlay + + .. versionadded:: 3.6.0 + + A structure containing the following integer members: + + .. c:member:: offset + + Overlay section offset. + + .. c:member:: size + + Overlay section size. + + *Example: uint8(0x0d) at pe.overlay.offset and pe.overlay.size > 1024* + +.. c:type:: number_of_resources + + Number of resources in the PE. + +.. c:type:: resource_timestamp + + Resource timestamp. This is stored as an integer. + +.. c:type:: resource_version + + An object with two integer attributes, major and minor versions. + + .. c:member:: major + + Major resource version. + + .. c:member:: minor + + Minor resource version. + +.. c:type:: resources + + .. versionchanged:: 3.3.0 + + A zero-based array of resource objects, one for each resource the PE has. + Individual resources can be accessed by using the [] operator. Each + resource object has the following attributes: + + .. c:member:: offset + + Offset for the resource data. + + .. c:member:: length + + Length of the resource data. + + .. c:member:: type + + Type of the resource (integer). + + .. c:member:: id + + ID of the resource (integer). + + .. c:member:: language + + Language of the resource (integer). + + .. c:member:: type_string + + Type of the resource as a string, if specified. + + .. c:member:: name_string + + Name of the resource as a string, if specified. + + .. c:member:: language_string + + Language of the resource as a string, if specified. + + All resources must have a type, id (name), and language specified. They can + be either an integer or string, but never both, for any given level. + + *Example: pe.resources[0].type == pe.RESOURCE_TYPE_RCDATA* + + *Example: pe.resources[0].name_string == "F\\x00I\\x00L\\x00E\\x00"* + + Resource types can be inspected using the following constants: + + .. c:type:: RESOURCE_TYPE_CURSOR + .. c:type:: RESOURCE_TYPE_BITMAP + .. c:type:: RESOURCE_TYPE_ICON + .. c:type:: RESOURCE_TYPE_MENU + .. c:type:: RESOURCE_TYPE_DIALOG + .. c:type:: RESOURCE_TYPE_STRING + .. c:type:: RESOURCE_TYPE_FONTDIR + .. c:type:: RESOURCE_TYPE_FONT + .. c:type:: RESOURCE_TYPE_ACCELERATOR + .. c:type:: RESOURCE_TYPE_RCDATA + .. c:type:: RESOURCE_TYPE_MESSAGETABLE + .. c:type:: RESOURCE_TYPE_GROUP_CURSOR + .. c:type:: RESOURCE_TYPE_GROUP_ICON + .. c:type:: RESOURCE_TYPE_VERSION + .. c:type:: RESOURCE_TYPE_DLGINCLUDE + .. c:type:: RESOURCE_TYPE_PLUGPLAY + .. c:type:: RESOURCE_TYPE_VXD + .. c:type:: RESOURCE_TYPE_ANICURSOR + .. c:type:: RESOURCE_TYPE_ANIICON + .. c:type:: RESOURCE_TYPE_HTML + .. c:type:: RESOURCE_TYPE_MANIFEST + + For more information refer to: + + http://msdn.microsoft.com/en-us/library/ms648009(v=vs.85).aspx + +.. c:type:: version_info + + .. versionadded:: 3.2.0 + + Dictionary containing the PE's version information. Typical keys are: + + ``Comments`` + ``CompanyName`` + ``FileDescription`` + ``FileVersion`` + ``InternalName`` + ``LegalCopyright`` + ``LegalTrademarks`` + ``OriginalFilename`` + ``ProductName`` + ``ProductVersion`` + + For more information refer to: + + http://msdn.microsoft.com/en-us/library/windows/desktop/ms646987(v=vs.85).aspx + + *Example: pe.version_info["CompanyName"] contains "Microsoft"* + +.. c:type:: number_of_signatures + + Number of authenticode signatures in the PE. + +.. c:type:: signatures + + A zero-based array of signature objects, one for each authenticode + signature in the PE file. Usually PE files have a single signature. + + .. c:member:: issuer + + A string containing information about the issuer. These are some + examples:: + + "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Code Signing PCA" + + "/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Code Signing 2010 CA" + + "/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Code Signing CA 2" + + .. c:member:: subject + + A string containing information about the subject. + + .. c:member:: version + + Version number. + + .. c:member:: algorithm + + Algorithm used for this signature. Usually "sha1WithRSAEncryption". + + .. c:member:: serial + + A string containing the serial number. This is an example:: + + "52:00:e5:aa:25:56:fc:1a:86:ed:96:c9:d4:4b:33:c7" + + .. c:member:: not_before + + Unix timestamp on which the validity period for this signature begins. + + .. c:member:: not_after + + Unix timestamp on which the validity period for this signature ends. + + .. c:member:: valid_on(timestamp) + + Function returning true if the signature was valid on the date + indicated by *timestamp*. The following sentence:: + + pe.signatures[n].valid_on(timestamp) + + Is equivalent to:: + + timestamp >= pe.signatures[n].not_before and timestamp <= pe.signatures[n].not_after + +.. c:type:: rich_signature + + Structure containing information about the PE's rich signature as + documented `here `_. + + .. c:member:: offset + + Offset where the rich signature starts. It will be undefined if the + file doesn't have a rich signature. + + .. c:member:: length + + Length of the rich signature, not including the final "Rich" marker. + + .. c:member:: key + + Key used to encrypt the data with XOR. + + .. c:member:: raw_data + + Raw data as it appears in the file. + + .. c:member:: clear_data + + Data after being decrypted by XORing it with the key. + + .. c:function:: version(version, [toolid]) + + .. versionadded:: 3.5.0 + + Function returning true if the PE has the specified *version* in the PE's rich + signature. Provide the optional *toolid* argument to only match when both match + for one entry. More information can be found here: + + http://www.ntcore.com/files/richsign.htm + + *Example: pe.rich_signature.version(21005)* + + .. c:function:: toolid(toolid, [version]) + + .. versionadded:: 3.5.0 + + Function returning true if the PE has the specified *id* in the PE's rich + signature. Provide the optional *version* argument to only match when both + match for one entry. More information can be found here: + + http://www.ntcore.com/files/richsign.htm + + *Example: pe.rich_signature.toolid(222)* + +.. c:function:: exports(function_name) + + Function returning true if the PE exports *function_name* or + false otherwise. + + *Example: pe.exports("CPlApplet")* + +.. c:function:: exports(ordinal) + + .. versionadded:: 3.6.0 + + Function returning true if the PE exports *ordinal* or + false otherwise. + + *Example: pe.exports(72)* + +.. c:function:: exports(/regular_expression/) + + .. versionadded:: 3.7.1 + + Function returning true if the PE exports *regular_expression* or + false otherwise. + + *Example: pe.exports(/^AXS@@/)* + +.. c:type:: number_of_exports + + .. versionadded:: 3.6.0 + + Number of exports in the PE. + +.. c:type:: number_of_imports + + .. versionadded:: 3.6.0 + + Number of imports in the PE. + +.. c:function:: imports(dll_name, function_name) + + Function returning true if the PE imports *function_name* from *dll_name*, + or false otherwise. *dll_name* is case insensitive. + + *Example: pe.imports("kernel32.dll", "WriteProcessMemory")* + +.. c:function:: imports(dll_name) + + .. versionadded:: 3.5.0 + + Function returning true if the PE imports anything from *dll_name*, + or false otherwise. *dll_name* is case insensitive. + + *Example: pe.imports("kernel32.dll")* + +.. c:function:: imports(dll_name, ordinal) + + .. versionadded:: 3.5.0 + + Function returning true if the PE imports *ordinal* from *dll_name*, + or false otherwise. *dll_name* is case insensitive. + + *Example: pe.imports("WS2_32.DLL", 3)* + +.. c:function:: locale(locale_identifier) + + .. versionadded:: 3.2.0 + + Function returning true if the PE has a resource with the specified locale + identifier. Locale identifiers are 16-bit integers and can be found here: + + http://msdn.microsoft.com/en-us/library/windows/desktop/dd318693(v=vs.85).aspx + + *Example: pe.locale(0x0419) // Russian (RU)* + +.. c:function:: language(language_identifier) + + .. versionadded:: 3.2.0 + + Function returning true if the PE has a resource with the specified language + identifier. Language identifiers are 8-bit integers and can be found here: + + http://msdn.microsoft.com/en-us/library/windows/desktop/dd318693(v=vs.85).aspx + + *Example: pe.language(0x0A) // Spanish* + +.. c:function:: imphash() + + .. versionadded:: 3.2.0 + + Function returning the import hash or imphash for the PE. The imphash is + a MD5 hash of the PE's import table after some normalization. The imphash + for a PE can be also computed with `pefile `_ and you can find more information in + `Mandiant's blog `_. + + *Example: pe.imphash() == "b8bb385806b89680e13fc0cf24f4431e"* + +.. c:function:: section_index(name) + + Function returning the index into the sections array for the section that has + *name*. *name* is case sensitive. + + *Example: pe.section_index(".TEXT")* + +.. c:function:: section_index(addr) + + .. versionadded:: 3.3.0 + + Function returning the index into the sections array for the section that has + *addr*. *addr* can be an offset into the file or a memory address. + + *Example: pe.section_index(pe.entry_point)* + +.. c:function:: is_dll() + + .. versionadded:: 3.5.0 + + Function returning true if the PE is a DLL. + + *Example: pe.is_dll()* + +.. c:function:: is_32bit() + + .. versionadded:: 3.5.0 + + Function returning true if the PE is 32bits. + + *Example: pe.is_32bit()* + +.. c:function:: is_64bit() + + .. versionadded:: 3.5.0 + + Function returning true if the PE is 64bits. + + *Example: pe.is_64bit()* + +.. c:function:: rva_to_offset(addr) + + .. versionadded:: 3.6.0 + + Function returning the file offset for RVA *addr*. + + *Example: pe.rva_to_offset(pe.entry_point)* diff --git a/yara-master/docs/modules/time.rst b/yara-master/docs/modules/time.rst new file mode 100644 index 0000000..3368453 --- /dev/null +++ b/yara-master/docs/modules/time.rst @@ -0,0 +1,17 @@ + +.. _time-module: + +############ +Time module +############ + +.. versionadded:: 3.7.0 + +The Time module allows you to use temporal conditions in your YARA rules. + +.. c:function:: now() + + Function returning an integer which is the number of seconds since January + 1, 1970. + + *Example: pe.timestamp > time.now()* diff --git a/yara-master/docs/writingmodules.rst b/yara-master/docs/writingmodules.rst new file mode 100644 index 0000000..b3fab50 --- /dev/null +++ b/yara-master/docs/writingmodules.rst @@ -0,0 +1,1020 @@ +.. _writing-modules: + +************************ +Writing your own modules +************************ + +For the first time ever, in YARA 3.0 you can extend its features to express +more complex and refined conditions. YARA 3.0 does this by employing +modules, which you can use to define data structures and functions, which +can be later used from within your rules. You can see some examples of +what a module can do in the :ref:`using-modules` section. + +The purpose of the following sections is to teach you how to create your +own modules for giving YARA that cool feature you always dreamed of. + + +The "Hello World!" module +========================= + +Modules are written in C and built into YARA as part of the compiling process. +In order to create your own modules you must be familiar with the C +programming language and how to configure and build YARA from source code. You +don't need to understand how YARA does its magic; YARA exposes a simple API for +modules, which is all you need to know. + +The source code for your module must reside in the *libyara/modules* directory +of the source tree. It's recommended to use the module name as the file name for +the source file, if your module's name is *foo* its source file should be +*foo.c*. + +In the *libyara/modules* directory you'll find a *demo.c* file we'll use +as our starting point. The file looks like this: + +.. code-block:: c + + #include + + #define MODULE_NAME demo + + begin_declarations; + + declare_string("greeting"); + + end_declarations; + + int module_initialize( + YR_MODULE* module) + { + return ERROR_SUCCESS; + } + + int module_finalize( + YR_MODULE* module) + { + return ERROR_SUCCESS; + } + + int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) + { + set_string("Hello World!", module_object, "greeting"); + return ERROR_SUCCESS; + } + + int module_unload( + YR_OBJECT* module_object) + { + return ERROR_SUCCESS; + } + + #undef MODULE_NAME + +Let's start dissecting the source code so you can understand every detail. The +first line in the code is: + +.. code-block:: c + + #include + +The *modules.h* header file is where the definitions for YARA's module API +reside, therefore this include directive is required in all your modules. The +second line is: + +.. code-block:: c + + #define MODULE_NAME demo + +This is how you define the name of your module and is also required. Every +module must define its name at the start of the source code. Module names must +be unique among the modules built into YARA. + +Then follows the declaration section: + +.. code-block:: c + + begin_declarations; + + declare_string("greeting"); + + end_declarations; + +Here is where the module declares the functions and data structures that will +be available for your YARA rules. In this case we are declaring just a +string variable named *greeting*. We are going to discuss these concepts in +greater detail in the :ref:`declaration-section`. + +After the declaration section you'll find a pair of functions: + +.. code-block:: c + + int module_initialize( + YR_MODULE* module) + { + return ERROR_SUCCESS; + } + + int module_finalize( + YR_MODULE* module) + { + return ERROR_SUCCESS; + } + +The ``module_initialize`` function is called during YARA's initialization while +its counterpart ``module_finalize`` is called while finalizing YARA. These +functions allow you to initialize and finalize any global data structure you +may need to use in your module. + +Then comes the ``module_load`` function: + +.. code-block:: c + + int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) + { + set_string("Hello World!", module_object, "greeting"); + return ERROR_SUCCESS; + } + + +This function is invoked once for each scanned file, but only if the module is +imported by some rule with the ``import`` directive. The ``module_load`` +function is where your module has the opportunity to inspect the file being +scanned, parse or analyze it in the way preferred, and then populate the +data structures defined in the declarations section. + +In this example the ``module_load`` function doesn't inspect the file content +at all, it just assigns the string, "Hello World!" to the variable *greeting* +declared before. + +And finally, we have the ``module_unload`` function: + +.. code-block:: c + + int module_unload( + YR_OBJECT* module_object) + { + return ERROR_SUCCESS; + } + +For each call to ``module_load`` there is a corresponding call to +``module_unload``. This function allows your module to free any resource +allocated during ``module_load``. There's nothing to free in this case, so +the function just returns ``ERROR_SUCCESS``. Both ``module_load`` and +``module_unload`` should return ``ERROR_SUCCESS`` to indicate that everything +went fine. If a different value is returned the scanning will be aborted and an +error reported to the user. + +Building our "Hello World!" +--------------------------- + +Modules are not magically built into YARA just by dropping their source code +into the *libyara/modules* directory, you must follow two further steps in order +to get them to work. The first step is adding your module to the *module_list* +file also found in the *libyara/modules* directory. + +The *module_list* file looks like this:: + + MODULE(tests) + MODULE(pe) + + #ifdef CUCKOO_MODULE + MODULE(cuckoo) + #endif + +You must add a line *MODULE()* with the name of your module to this file. +In our case the resulting *module_list* is:: + + MODULE(tests) + MODULE(pe) + + #ifdef CUCKOO_MODULE + MODULE(cuckoo) + #endif + + MODULE(demo) + +The second step is modifying the *Makefile.am* to tell the *make* program that +the source code for your module must be compiled and linked into YARA. At the +very beginning of *libyara/Makefile.am* you'll find this:: + + MODULES = modules/tests.c + MODULES += modules/pe.c + + if CUCKOO_MODULE + MODULES += modules/cuckoo.c + endif + + +Just add a new line for your module:: + + MODULES = modules/tests.c + MODULES += modules/pe.c + + if CUCKOO_MODULE + MODULES += modules/cuckoo.c + endif + + MODULES += modules/demo.c + +And that's all! Now you're ready to build YARA with your brand-new module +included. Just go to the source tree root directory and type as always:: + + make + sudo make install + + +Now you should be able to create a rule like this:: + + import "demo" + + rule HelloWorld + { + condition: + demo.greeting == "Hello World!" + } + +Any file scanned with this rule will match the ``HelloWord`` because +``demo.greeting == "Hello World!"`` is always true. + +.. _declaration-section: + +The declaration section +======================= + +The declaration section is where you declare the variables, structures and +functions that will be available for your YARA rules. Every module must contain +a declaration section like this:: + + begin_declarations; + + + + end_declarations; + +Basic types +----------- + +Within the declaration section you can use ``declare_string()``, +``declare_integer()`` and ``declare_float()`` to +declare string, integer, or float variables respectively. For example:: + + begin_declarations; + + declare_integer("foo"); + declare_string("bar"); + declare_float("baz"); + + end_declarations; + +.. note:: + Floating-point variables require YARA version 3.3.0 or later. + + +Variable names can't contain characters other than letters, numbers and +underscores. These variables can be used later in your rules at any place where +an integer or string is expected. Supposing your module name is "mymodule", they +can be used like this:: + + mymodule.foo > 5 + + mymodule.bar matches /someregexp/ + + +Structures +---------- + +Your declarations can be organized in a more structured way:: + + begin_declarations; + + declare_integer("foo"); + declare_string("bar"); + declare_float("baz"); + + begin_struct("some_structure"); + + declare_integer("foo"); + + begin_struct("nested_structure"); + + declare_integer("bar"); + + end_struct("nested_structure"); + + end_struct("some_structure"); + + begin_struct("another_structure"); + + declare_integer("foo"); + declare_string("bar"); + declare_string("baz"); + declare_float("tux"); + + end_struct("another_structure"); + + end_declarations; + +In this example we're using ``begin_struct()`` and +``end_struct()`` to delimit two structures named +*some_structure* and *another_structure*. Within the structure delimiters you +can put any other declarations you want, including another structure +declaration. Also notice that members of different structures can have the same +name, but members within the same structure must have unique names. + +When referring to these variables from your rules it would be like this:: + + mymodule.foo + mymodule.some_structure.foo + mymodule.some_structure.nested_structure.bar + mymodule.another_structure.baz + + +Arrays +------ + +In the same way you declare individual strings, integers, floats or structures, +you can declare arrays of them:: + + begin_declarations; + + declare_integer_array("foo"); + declare_string_array("bar"); + declare_float_array("baz"); + + begin_struct_array("struct_array"); + + declare_integer("foo"); + declare_string("bar"); + + end_struct_array("struct_array"); + + end_declarations; + + +Individual values in the array are referenced like in most programming +languages:: + + foo[0] + bar[1] + baz[3] + struct_array[4].foo + struct_array[1].bar + +Arrays are zero-based and don't have a fixed size, they will grow as needed +when you start initializing its values. + + +Dictionaries +------------ + +.. versionadded:: 3.2.0 + +You can also declare dictionaries of integers, floats, strings, or structures:: + + begin_declarations; + + declare_integer_dictionary("foo"); + declare_string_dictionary("bar"); + declare_float_dictionary("baz") + + begin_struct_dictionary("struct_dict"); + + declare_integer("foo"); + declare_string("bar"); + + end_struct_dictionary("struct_dict"); + + end_declarations; + +Individual values in the dictionary are accessed by using a string key:: + + foo["somekey"] + bar["anotherkey"] + baz["yetanotherkey"] + struct_dict["k1"].foo + struct_dict["k1"].bar + +.. _declaring-functions: + +Functions +--------- + +One of the more powerful features of YARA modules is the possibility of +declaring functions that can be later invoked from your rules. Functions +must appear in the declaration section in this way:: + + declare_function(, , , ); + +** is the name that will be used in your YARA rules to invoke +the function. + +** is a string containing one character per +function argument, where the character indicates the type of the argument. +Functions can receive four different types of arguments: string, integer, float +and regular expression, denoted by characters: **s**, **i**, **f** and **r** +respectively. If your function receives two integers ** must be +*"ii"*, if it receives an integer as the first argument and a string as the +second one ** must be *"is"*, if it receives three strings and +a float ** must be "*sssf*". + +** is a string with a single character indicating the return type. +Possible return types are string (*"s"*) integer (*"i"*) and float (*"f"*). + +** is the identifier for the actual implementation of your function. + +Here you have a full example: + +.. code-block:: c + + define_function(isum) + { + int64_t a = integer_argument(1); + int64_t b = integer_argument(2); + + return_integer(a + b); + } + + define_function(fsum) + { + double a = float_argument(1); + double b = float_argument(2); + + return_integer(a + b); + } + + begin_declarations; + + declare_function("sum", "ii", "i", sum); + + end_declarations; + +As you can see in the example above, your function code must be defined before +the declaration section, like this:: + + define_function() + { + ...your code here + } + +Functions can be overloaded as in C++ and other programming languages. You can +declare two functions with the same name as long as they differ in the type or +number of arguments. One example of overloaded functions can be found in the +:ref:`hash-module`, it has two functions for calculating MD5 hashes, one +receiving an offset and length within the file and another one receiving a +string:: + + begin_declarations; + + declare_function("md5", "ii", "s", data_md5); + declare_function("md5", "s", "s", string_md5); + + end_declarations; + +We are going to discuss function implementation more in depth in the +:ref:`implementing-functions` section. + +Initialization and finalization +=============================== + +Every module must implement two functions for initialization and finalization: +``module_initialize`` and ``module_finalize``. The former is called during +YARA's initialization by :c:func:`yr_initialize` while the latter is called +during finalization by :c:func:`yr_finalize`. Both functions are invoked +whether or not the module is being imported by some rule. + +These functions give your module an opportunity to initialize any global data +structure it may need, but most of the time they are just empty functions: + +.. code-block:: c + + int module_initialize( + YR_MODULE* module) + { + return ERROR_SUCCESS; + } + + int module_finalize( + YR_MODULE* module) + { + return ERROR_SUCCESS; + } + +Any returned value different from ``ERROR_SUCCESS`` will abort YARA's execution. + +Implementing the module's logic +=============================== + +Besides ``module_initialize`` and ``module_finalize`` every module must +implement two other functions which are called by YARA during the +scanning of a file or process memory space: ``module_load`` and +``module_unload``. Both functions are called once for each scanned file or +process, but only if the module was imported by means of the ``import`` +directive. If the module is not imported by some rule neither ``module_load`` +nor ``module_unload`` will be called. + +The ``module_load`` function has the following prototype: + +.. code-block:: c + + int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) + +The ``context`` argument contains information relative to the current scan, +including the data being scanned. The ``module_object`` argument is a pointer +to a ``YR_OBJECT`` structure associated with the module. Each structure, +variable or function declared in a YARA module is represented by a +``YR_OBJECT`` structure. These structures form a tree whose root is the +module's ``YR_OBJECT`` structure. If you have the following declarations in a +module named *mymodule*:: + + begin_declarations; + + declare_integer("foo"); + + begin_struct("bar"); + + declare_string("baz"); + + end_struct("bar"); + + end_declarations; + +Then the tree will look like this:: + + YR_OBJECT(type=OBJECT_TYPE_STRUCT, name="mymodule") + | + |_ YR_OBJECT(type=OBJECT_TYPE_INTEGER, name="foo") + | + |_ YR_OBJECT(type=OBJECT_TYPE_STRUCT, name="bar") + | + |_ YR_OBJECT(type=OBJECT_TYPE_STRING, name="baz") + +Notice that both *bar* and *mymodule* are of the same type +``OBJECT_TYPE_STRUCT``, which means that the ``YR_OBJECT`` associated with the +module is just another structure like *bar*. In fact, when you write in your +rules something like ``mymodule.foo`` you're performing a field lookup in a +structure in the same way that ``bar.baz`` does. + +In summary, the ``module_object`` argument allows you to access every variable, +structure or function declared by the module by providing a pointer to the +root of the objects tree. + +The ``module_data`` argument is a pointer to any additional data passed to the +module, and ``module_data_size`` is the size of that data. Not all modules +require additional data, most of them rely on the data being scanned alone, but +a few of them require more information as input. The :ref:`cuckoo-module` is a +good example of this, it receives a behavior report associated with PE files +being scanned which is passed in the ``module_data`` and ``module_data_size`` +arguments. + +For more information on how to pass additional data to your module take a look +at the ``-x`` argument in :ref:`command-line`. + +.. _accessing-scanned-data: + +Accessing the scanned data +-------------------------- + +Most YARA modules need to access the file or process memory being scanned to +extract information from it. The data being scanned is sent to the module in the +``YR_SCAN_CONTEXT`` structure passed to the ``module_load`` function. The data +is sometimes sliced in blocks, therefore your module needs to iterate over the +blocks by using the ``foreach_memory_block`` macro: + +.. code-block:: c + + int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) + { + YR_MEMORY_BLOCK* block; + + foreach_memory_block(context, block) + { + ..do something with the current memory block + } + } + +Each memory block is represented by a ``YR_MEMORY_BLOCK`` structure with the +following attributes: + +.. c:type:: YR_MEMORY_BLOCK_FETCH_DATA_FUNC fetch_data + + Pointer to a function returning a pointer to the block's data. + +.. c:type:: size_t size + + Size of the data block. + +.. c:type:: size_t base + + Base offset/address for this block. If a file is being scanned this field + contains the offset within the file where the block begins, if a process + memory space is being scanned this contains the virtual address where + the block begins. + +The blocks are always iterated in the same order as they appear in the file +or process memory. In the case of files the first block will contain the +beginning of the file. Actually, a single block will contain the whole file's +content in most cases, but you can't rely on that while writing your code. For +very big files YARA could eventually split the file into two or more blocks, +and your module should be prepared to handle that. + +The story is very different for processes. While scanning a process memory +space your module will definitely receive a large number of blocks, one for each +committed memory region in the process address space. + +However, there are some cases where you don't actually need to iterate over the +blocks. If your module just parses the header of some file format you can safely +assume that the whole header is contained within the first block (put some +checks in your code nevertheless). In those cases you can use the +``first_memory_block`` macro: + +.. code-block:: c + + int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) + { + YR_MEMORY_BLOCK* block; + const uint8_t* block_data; + + block = first_memory_block(context); + block_data = block->fetch_data(block) + + if (block_data != NULL) + { + ..do something with the memory block + } + } + +In the previous example you can also see how to use the ``fetch_data`` function. +This function, which is a member of the ``YR_MEMORY_BLOCK`` structure, receives +a pointer to the same block (as a ``self`` or ``this`` pointer) and returns a +pointer to the block's data. Your module doesn't own the memory pointed to by +this pointer, freeing that memory is not your responsibility. However keep in +mind that the pointer is valid only until you ask for the next memory block. As +long as you use the pointer within the scope of a ``foreach_memory_block`` you +are on the safe side. Also take into account that ``fetch_data`` can return a +NULL pointer, your code must be prepared for that case. + +.. code-block:: c + + const uint8_t* block_data; + + foreach_memory_block(context, block) + { + block_data = block->fetch_data(block); + + if (block_data != NULL) + { + // using block_data is safe here. + } + } + + // the memory pointed to by block_data can be already freed here. + + +Setting variable's values +------------------------- + +The ``module_load`` function is where you assign values to the variables +declared in the declarations section, once you've parsed or analyzed the scanned +data and/or any additional module's data. This is done by using the +``set_integer`` and ``set_string`` functions: + +.. c:function:: void set_integer(int64_t value, YR_OBJECT* object, const char* field, ...) + +.. c:function:: void set_string(const char* value, YR_OBJECT* object, const char* field, ...) + +Both functions receive a value to be assigned to the variable, a pointer to a +``YR_OBJECT`` representing the variable itself or some ancestor of +that variable, a field descriptor, and additional arguments as defined by the +field descriptor. + +If we are assigning the value to the variable represented by ``object`` itself, +then the field descriptor must be ``NULL``. For example, assuming that ``object`` +points to a ``YR_OBJECT`` structure corresponding to some integer variable, we +can set the value for that integer variable with: + +.. code-block:: c + + set_integer(, object, NULL); + +The field descriptor is used when you want to assign the value to some +descendant of ``object``. For example, consider the following declarations:: + + begin_declarations; + + begin_struct("foo"); + + declare_string("bar"); + + begin_struct("baz"); + + declare_integer("qux"); + + end_struct("baz"); + + end_struct("foo"); + + end_declarations; + +If ``object`` points to the ``YR_OBJECT`` associated with the ``foo`` structure +you can set the value for the ``bar`` string like this: + +.. code-block:: c + + set_string(, object, "bar"); + +And the value for ``qux`` like this: + +.. code-block:: c + + set_integer(, object, "baz.qux"); + + +Do you remember that the ``module_object`` argument for ``module_load`` was a +pointer to a ``YR_OBJECT``? Do you remember that this ``YR_OBJECT`` is a +structure just like ``bar`` is? Well, you could also set the values for ``bar`` +and ``qux`` like this: + +.. code-block:: c + + set_string(, module_object, "foo.bar"); + set_integer(, module_object, "foo.baz.qux"); + +But what happens with arrays? How can I set the value for array items? If +you have the following declarations:: + + begin_declarations; + + declare_integer_array("foo"); + + begin_struct_array("bar") + + declare_string("baz"); + declare_integer_array("qux"); + + end_struct_array("bar"); + + end_declarations; + +Then the following statements are all valid: + +.. code-block:: c + + set_integer(, module, "foo[0]"); + set_integer(, module, "foo[%i]", 2); + set_string(, module, "bar[%i].baz", 5); + set_string(, module, "bar[0].qux[0]"); + set_string(, module, "bar[0].qux[%i]", 0); + set_string(, module, "bar[%i].qux[%i]", 100, 200); + +Those ``%i`` in the field descriptor are replaced by the additional +integer arguments passed to the function. This works in the same way as +``printf`` in C programs, but the only format specifiers accepted are ``%i`` +and ``%s``, for integer and string arguments respectively. + +The ``%s`` format specifier is used for assigning values to a certain key +in a dictionary: + +.. code-block:: c + + set_integer(, module, "foo[\"key\"]"); + set_integer(, module, "foo[%s]", "key"); + set_string(, module, "bar[%s].baz", "another_key"); + +If you don't explicitly assign a value to a declared variable, array or +dictionary item it will remain in an undefined state. That's not a problem at +all, and is even useful in many cases. For example, if your module parses files +from a certain format and it receives one from a different format, you can +safely leave all your variables undefined instead of assigning them bogus +values that don't make sense. YARA will handle undefined values in rule +conditions as described in :ref:`using-modules`. + +In addition to ``set_integer`` and ``set_string`` functions you have their +``get_integer`` and ``get_string`` counterparts. As the names suggest they +are used for getting the value of a variable, which can be useful in the +implementation of your functions to retrieve values previously stored by +``module_load``. + + +.. c:function:: int64_t get_integer(YR_OBJECT* object, const char* field, ...) + +.. c:function:: char* get_string(YR_OBJECT* object, const char* field, ...) + +There's also a function to get any ``YR_OBJECT`` in the objects tree: + +.. c:function:: YR_OBJECT* get_object(YR_OBJECT* object, const char* field, ...) + +Here is a little exam... + +Are the following two lines equivalent? Why? + +.. code-block:: c + + set_integer(1, get_object(module_object, "foo.bar"), NULL); + set_integer(1, module_object, "foo.bar"); + +.. _storing-data-for-later-use: + +Storing data for later use +-------------------------- + +Sometimes the information stored directly in your variables by means of +``set_integer`` and ``set_string`` is not enough. You may need to store more +complex data structures or information that doesn't need to be exposed to YARA +rules. + +Storing information is essential when your module exports functions +to be used in YARA rules. The implementation of these functions usually require +to access information generated by ``module_load`` which must kept somewhere. +You may be tempted to define global variables to store the required +information, but this would make your code non-thread-safe. The correct +approach is using the ``data`` field of the ``YR_OBJECT`` structures. + +Each ``YR_OBJECT`` has a ``void* data`` field which can be safely used +by your code to store a pointer to any data you may need. A typical pattern +is using the ``data`` field of the module's ``YR_OBJECT``, like in the +following example: + +.. code-block:: c + + typedef struct _MY_DATA + { + int some_integer; + + } MY_DATA; + + int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) + { + module->data = yr_malloc(sizeof(MY_DATA)); + ((MY_DATA*) module_object->data)->some_integer = 0; + + return ERROR_SUCCESS; + } + +Don't forget to release the allocated memory in the ``module_unload`` function: + +.. code-block:: cpp + + int module_unload( + YR_OBJECT* module_object) + { + yr_free(module_object->data); + + return ERROR_SUCCESS; + } + +.. warning:: Don't use global variables for storing data. Functions in a + module can be invoked from different threads at the same time and data + corruption or misbehavior can occur. + +.. _implementing-functions: + +More about functions +==================== + +We already showed how to declare a function in +:ref:`The declaration section `. Here we are going to +discuss how to provide an implementation for them. + +Function arguments +------------------ + +Within the function's code you get its arguments by using +``integer_argument(n)``, ``float_argument(n)``, ``regexp_argument(n)``, +``string_argument(n)`` or ``sized_string_argument(n)`` depending on the type of +the argument, where *n* is the 1-based argument's number. + +``string_argument(n)`` can be used when your function expects to receive a +NULL-terminated C string, if your function can receive arbitrary binary data +possibly containing NULL characters you must use ``sized_string_argument(n)``. + +Here you have some examples: + +.. code-block:: c + + int64_t arg_1 = integer_argument(1); + RE* arg_2 = regexp_argument(2); + char* arg_3 = string_argument(3); + SIZED_STRING* arg_4 = sized_string_argument(4); + double arg_5 = float_argument(1); + +The C type for integer arguments is ``int64_t``, for float arguments is +``double``, for regular expressions is ``RE*``, for NULL-terminated strings +is ``char*`` and for strings possibly containing NULL characters is +``SIZED_STRING*``. ``SIZED_STRING`` structures have the +following attributes: + +.. c:type:: SIZED_STRING + + .. c:member:: length + + String's length. + + .. c:member:: c_string + + ``char*`` pointing to the string content. + +Return values +------------- + +Functions can return three types of values: strings, integers and floats. +Instead of using the C *return* statement you must use ``return_string(x)``, +``return_integer(x)`` or ``return_float(x)`` to return from a function, +depending on the function's return type. In all cases *x* is a constant, +variable, or expression evaluating to ``char*``, ``int64_t`` or ``double`` +respectively. + +You can use ``return_string(UNDEFINED)``, ``return_float(UNDEFINED)`` and +``return_integer(UNDEFINED)`` to return undefined values from the function. +This is useful in many situations, for example if the arguments passed to the +functions don't make sense, or if your module expects a particular file format +and the scanned file is from another format, or in any other case where your +function can't a return a valid value. + + +.. warning:: Don't use the C *return* statement for returning from a function. + The returned value will be interpreted as an error code. + +Accessing objects +----------------- + +While writing a function we sometimes need to access values previously assigned +to the module's variables, or additional data stored in the ``data`` field of +``YR_OBJECT`` structures as discussed earlier in +:ref:`storing-data-for-later-use`. But for that we need a way to get access to +the corresponding ``YR_OBJECT`` first. There are two functions to do that: +``module()`` and ``parent()``. The ``module()`` function returns a pointer to +the top-level ``YR_OBJECT`` corresponding to the module, the same one passed +to the ``module_load`` function. The ``parent()`` function returns a pointer to +the ``YR_OBJECT`` corresponding to the structure where the function is +contained. For example, consider the following code snippet: + +.. code-block:: c + + define_function(f1) + { + YR_OBJECT* module = module(); + YR_OBJECT* parent = parent(); + + // parent == module; + } + + define_function(f2) + { + YR_OBJECT* module = module(); + YR_OBJECT* parent = parent(); + + // parent != module; + } + + begin_declarations; + + declare_function("f1", "i", "i", f1); + + begin_struct("foo"); + + declare_function("f2", "i", "i", f2); + + end_struct("foo"); + + end_declarations; + +In ``f1`` the ``module`` variable points to the top-level ``YR_OBJECT`` as well +as the ``parent`` variable, because the parent for ``f1`` is the module itself. +In ``f2`` however the ``parent`` variable points to the ``YR_OBJECT`` +corresponding to the ``foo`` structure while ``module`` points to the top-level +``YR_OBJECT`` as before. + +Scan context +------------ + +From within a function you can also access the ``YR_SCAN_CONTEXT`` structure +discussed earlier in :ref:`accessing-scanned-data`. This is useful for functions +which needs to inspect the file or process memory being scanned. This is how +you get a pointer to the ``YR_SCAN_CONTEXT`` structure: + +.. code-block:: c + + YR_SCAN_CONTEXT* context = scan_context(); diff --git a/yara-master/docs/writingrules.rst b/yara-master/docs/writingrules.rst new file mode 100644 index 0000000..8ce0522 --- /dev/null +++ b/yara-master/docs/writingrules.rst @@ -0,0 +1,1232 @@ +******************* +Writing YARA rules +******************* + +YARA rules are easy to write and understand, and they have a syntax that +resembles the C language. Here is the simplest rule that you can write for +YARA, which does absolutely nothing:: + + rule dummy + { + condition: + false + } + +Each rule in YARA starts with the keyword ``rule`` followed by a rule +identifier. Identifiers must follow the same lexical conventions of the C +programming language, they can contain any alphanumeric character and the +underscore character, but the first character can not be a digit. Rule +identifiers are case sensitive and cannot exceed 128 characters. The following +keywords are reserved and cannot be used as an identifier: + + +.. list-table:: YARA keywords + :widths: 10 10 10 10 10 10 10 + + * - all + - and + - any + - ascii + - at + - condition + - contains + * - entrypoint + - false + - filesize + - fullword + - for + - global + - in + * - import + - include + - int8 + - int16 + - int32 + - int8be + - int16be + * - int32be + - matches + - meta + - nocase + - not + - or + - of + * - private + - rule + - strings + - them + - true + - uint8 + - uint16 + * - uint32 + - uint8be + - uint16be + - uint32be + - wide + - xor + - + +Rules are generally composed of two sections: strings definition and condition. +The strings definition section can be omitted if the rule doesn't rely on any +string, but the condition section is always required. The strings definition +section is where the strings that will be part of the rule are defined. Each +string has an identifier consisting of a $ character followed by a sequence of +alphanumeric characters and underscores, these identifiers can be used in the +condition section to refer to the corresponding string. Strings can be defined +in text or hexadecimal form, as shown in the following example:: + + rule ExampleRule + { + strings: + $my_text_string = "text here" + $my_hex_string = { E2 34 A1 C8 23 FB } + + condition: + $my_text_string or $my_hex_string + } + +Text strings are enclosed in double quotes just like in the C language. Hex +strings are enclosed by curly brackets, and they are composed by a sequence of +hexadecimal numbers that can appear contiguously or separated by spaces. Decimal +numbers are not allowed in hex strings. + +The condition section is where the logic of the rule resides. This section must +contain a boolean expression telling under which circumstances a file or process +satisfies the rule or not. Generally, the condition will refer to previously +defined strings by using their identifiers. In this context the string +identifier acts as a boolean variable which evaluate to true if the string was +found in the file or process memory, or false if otherwise. + +Comments +======== + +You can add comments to your YARA rules just as if it was a C source file, both +single-line and multi-line C-style comments are supported. :: + + /* + This is a multi-line comment ... + */ + + rule CommentExample // ... and this is single-line comment + { + condition: + false // just a dummy rule, don't do this + } + +Strings +======= + +There are three types of strings in YARA: hexadecimal strings, text strings and +regular expressions. Hexadecimal strings are used for defining raw sequences of +bytes, while text strings and regular expressions are useful for defining +portions of legible text. However text strings and regular expressions can be +also used for representing raw bytes by mean of escape sequences as will be +shown below. + +Hexadecimal strings +------------------- + +Hexadecimal strings allow three special constructions that make them more +flexible: wild-cards, jumps, and alternatives. Wild-cards are just placeholders +that you can put into the string indicating that some bytes are unknown and they +should match anything. The placeholder character is the question mark (?). Here +you have an example of a hexadecimal string with wild-cards:: + + rule WildcardExample + { + strings: + $hex_string = { E2 34 ?? C8 A? FB } + + condition: + $hex_string + } + +As shown in the example the wild-cards are nibble-wise, which means that you can +define just one nibble of the byte and leave the other unknown. + +Wild-cards are useful when defining strings whose content can vary but you know +the length of the variable chunks, however, this is not always the case. In some +circumstances you may need to define strings with chunks of variable content and +length. In those situations you can use jumps instead of wild-cards:: + + rule JumpExample + { + strings: + $hex_string = { F4 23 [4-6] 62 B4 } + + condition: + $hex_string + } + +In the example above we have a pair of numbers enclosed in square brackets and +separated by a hyphen, that's a jump. This jump is indicating that any arbitrary +sequence from 4 to 6 bytes can occupy the position of the jump. Any of the +following strings will match the pattern:: + + F4 23 01 02 03 04 62 B4 + F4 23 00 00 00 00 00 62 B4 + F4 23 15 82 A3 04 45 22 62 B4 + +Any jump [X-Y] must meet the condition 0 <= X <= Y. In previous versions of +YARA both X and Y must be lower than 256, but starting with YARA 2.0 there is +no limit for X and Y. + +These are valid jumps:: + + FE 39 45 [0-8] 89 00 + FE 39 45 [23-45] 89 00 + FE 39 45 [1000-2000] 89 00 + +This is invalid:: + + FE 39 45 [10-7] 89 00 + +If the lower and higher bounds are equal you can write a single number enclosed +in brackets, like this:: + + FE 39 45 [6] 89 00 + +The above string is equivalent to both of these:: + + FE 39 45 [6-6] 89 00 + FE 39 45 ?? ?? ?? ?? ?? ?? 89 00 + +Starting with YARA 2.0 you can also use unbounded jumps:: + + FE 39 45 [10-] 89 00 + FE 39 45 [-] 89 00 + +The first one means ``[10-infinite]``, the second one means ``[0-infinite]``. + +There are also situations in which you may want to provide different +alternatives for a given fragment of your hex string. In those situations you +can use a syntax which resembles a regular expression:: + + rule AlternativesExample1 + { + strings: + $hex_string = { F4 23 ( 62 B4 | 56 ) 45 } + + condition: + $hex_string + } + +This rule will match any file containing ``F42362B445`` or ``F4235645``. + +But more than two alternatives can be also expressed. In fact, there are no +limits to the amount of alternative sequences you can provide, and neither to +their lengths. :: + + rule AlternativesExample2 + { + strings: + $hex_string = { F4 23 ( 62 B4 | 56 | 45 ?? 67 ) 45 } + + condition: + $hex_string + } + +As can be seen also in the above example, strings containing wild-cards are +allowed as part of alternative sequences. + +Text strings +------------ + +As shown in previous sections, text strings are generally defined like this:: + + rule TextExample + { + strings: + $text_string = "foobar" + + condition: + $text_string + } + +This is the simplest case: an ASCII-encoded, case-sensitive string. However, +text strings can be accompanied by some useful modifiers that alter the way in +which the string will be interpreted. Those modifiers are appended at the end of +the string definition separated by spaces, as will be discussed below. + +Text strings can also contain the following subset of the escape sequences +available in the C language: + +.. list-table:: + :widths: 3 10 + + * - ``\"`` + - Double quote + * - ``\\`` + - Backslash + * - ``\t`` + - Horizontal tab + * - ``\n`` + - New line + * - ``\xdd`` + - Any byte in hexadecimal notation + +Case-insensitive strings +^^^^^^^^^^^^^^^^^^^^^^^^ + +Text strings in YARA are case-sensitive by default, however you can turn your +string into case-insensitive mode by appending the modifier nocase at the end +of the string definition, in the same line:: + + rule CaseInsensitiveTextExample + { + strings: + $text_string = "foobar" nocase + + condition: + $text_string + } + +With the ``nocase`` modifier the string *foobar* will match *Foobar*, *FOOBAR*, +and *fOoBaR*. This modifier can be used in conjunction with any other modifier. + +Wide-character strings +^^^^^^^^^^^^^^^^^^^^^^ + +The ``wide`` modifier can be used to search for strings encoded with two bytes +per character, something typical in many executable binaries. + + + + +In the above figure, the string "Borland" appears encoded as two bytes per +character, therefore the following rule will match:: + + rule WideCharTextExample1 + { + strings: + $wide_string = "Borland" wide + + condition: + $wide_string + } + +However, keep in mind that this modifier just interleaves the ASCII codes of +the characters in the string with zeroes, it does not support truly UTF-16 +strings containing non-English characters. If you want to search for strings +in both ASCII and wide form, you can use the ``ascii`` modifier in conjunction +with ``wide`` , no matter the order in which they appear. :: + + rule WideCharTextExample2 + { + strings: + $wide_and_ascii_string = "Borland" wide ascii + + condition: + $wide_and_ascii_string + } + +The ``ascii`` modifier can appear alone, without an accompanying ``wide`` +modifier, but it's not necessary to write it because in absence of ``wide`` the +string is assumed to be ASCII by default. + +XOR strings +^^^^^^^^^^^ + +The ``xor`` modifier can be used to search for strings with a single byte xor +applied to them. + +The following rule will search for every single byte xor applied to the string +"This program cannot":: + + rule XorExample1 + { + strings: + $xor_string = "This program cannot" xor + + condition: + $xor_string + } + +The above rule is logically equivalent to:: + + rule XorExample2 + { + strings: + $xor_string_00 = "This program cannot" + $xor_string_01 = "Uihr!qsnfs`l!b`oonu" + $xor_string_02 = "Vjkq\"rpmepco\"acllmv" + // Repeat for every single byte xor + condition: + any of them + } + +You can also combine the ``xor`` modifier with ``wide``, ``ascii`` and +``nocase`` modifiers. For example, to search for the ``wide`` and ``ascii`` +versions of a string after every single byte xor has been applied you would +use:: + + rule XorExample3 + { + strings: + $xor_string = "This program cannot" xor wide ascii + condition: + $xor_string + } + +The ``xor`` modifier is applied after every other modifier. This means that +using the ``xor`` and ``wide`` together results in the xor applying to the +interleaved zero bytes. For example, the following two rules are logically +equivalent:: + + rule XorExample3 + { + strings: + $xor_string = "This program cannot" xor wide + condition: + $xor_string + } + + rule XorExample4 + { + strings: + $xor_string_00 = "T\x00h\x00i\x00s\x00 \x00p\x00r\x00o\x00g\x00r\x00a\x00m\x00 \x00c\x00a\x00n\x00n\x00o\x00t\x00" + $xor_string_01 = "U\x01i\x01h\x01r\x01!\x01q\x01s\x01n\x01f\x01s\x01`\x01l\x01!\x01b\x01`\x01o\x01o\x01n\x01u\x01" + $xor_string_02 = "V\x02j\x02k\x02q\x02\"\x02r\x02p\x02m\x02e\x02p\x02c\x02o\x02\"\x02a\x02c\x02l\x02l\x02m\x02v\x02" + // Repeat for every single byte xor operation. + condition: + any of them + } + +Searching for full words +^^^^^^^^^^^^^^^^^^^^^^^^ + +Another modifier that can be applied to text strings is ``fullword``. This +modifier guarantees that the string will match only if it appears in the file +delimited by non-alphanumeric characters. For example the string *domain*, if +defined as ``fullword``, doesn't match *www.mydomain.com* but it matches +*www.my-domain.com* and *www.domain.com*. + +Regular expressions +------------------- + +Regular expressions are one of the most powerful features of YARA. They are +defined in the same way as text strings, but enclosed in forward slashes instead +of double-quotes, like in the Perl programming language. :: + + rule RegExpExample1 + { + strings: + $re1 = /md5: [0-9a-fA-F]{32}/ + $re2 = /state: (on|off)/ + + condition: + $re1 and $re2 + } + +Regular expressions can be also followed by ``nocase``, ``ascii``, ``wide``, +and ``fullword`` modifiers just like in text strings. The semantics of these +modifiers are the same in both cases. + +In previous versions of YARA, external libraries like PCRE and RE2 were used +to perform regular expression matching, but starting with version 2.0 YARA uses +its own regular expression engine. This new engine implements most features +found in PCRE, except a few of them like capture groups, POSIX character +classes and backreferences. + +YARA’s regular expressions recognise the following metacharacters: + +.. list-table:: + :widths: 3 10 + + * - ``\`` + - Quote the next metacharacter + * - ``^`` + - Match the beginning of the file + * - ``$`` + - Match the end of the file + * - ``|`` + - Alternation + * - ``()`` + - Grouping + * - ``[]`` + - Bracketed character class + +The following quantifiers are recognised as well: + +.. list-table:: + :widths: 3 10 + + * - ``*`` + - Match 0 or more times + * - ``+`` + - Match 1 or more times + * - ``?`` + - Match 0 or 1 times + * - ``{n}`` + - Match exactly n times + * - ``{n,}`` + - Match at least n times + * - ``{,m}`` + - Match at most m times + * - ``{n,m}`` + - Match n to m times + +All these quantifiers have a non-greedy variant, followed by a question +mark (?): + +.. list-table:: + :widths: 3 10 + + * - ``*?`` + - Match 0 or more times, non-greedy + * - ``+?`` + - Match 1 or more times, non-greedy + * - ``??`` + - Match 0 or 1 times, non-greedy + * - ``{n}?`` + - Match exactly n times, non-greedy + * - ``{n,}?`` + - Match at least n times, non-greedy + * - ``{,m}?`` + - Match at most m times, non-greedy + * - ``{n,m}?`` + - Match n to m times, non-greedy + +The following escape sequences are recognised: + +.. list-table:: + :widths: 3 10 + + * - ``\t`` + - Tab (HT, TAB) + * - ``\n`` + - New line (LF, NL) + * - ``\r`` + - Return (CR) + * - ``\f`` + - Form feed (FF) + * - ``\a`` + - Alarm bell + * - ``\xNN`` + - Character whose ordinal number is the given hexadecimal number + + +These are the recognised character classes: + +.. list-table:: + :widths: 3 10 + + * - ``\w`` + - Match a *word* character (alphanumeric plus “_”) + * - ``\W`` + - Match a *non-word* character + * - ``\s`` + - Match a whitespace character + * - ``\S`` + - Match a non-whitespace character + * - ``\d`` + - Match a decimal digit character + * - ``\D`` + - Match a non-digit character + + +Starting with version 3.3.0 these zero-width assertions are also recognized: + +.. list-table:: + :widths: 3 10 + + * - ``\b`` + - Match a word boundary + * - ``\B`` + - Match except at a word boundary + + +Conditions +========== + +Conditions are nothing more than Boolean expressions as those that can be found +in all programming languages, for example in an *if* statement. They can contain +the typical Boolean operators ``and``, ``or``, and ``not``, and relational operators +>=, <=, <, >, == and !=. Also, the arithmetic operators (\+, \-, \*, \\, \%) +and bitwise operators (\&, \|, <<, >>, \~, \^) can be used on numerical +expressions. + +String identifiers can be also used within a condition, acting as Boolean +variables whose value depends on the presence or not of the associated string +in the file. :: + + rule Example + { + strings: + $a = "text1" + $b = "text2" + $c = "text3" + $d = "text4" + + condition: + ($a or $b) and ($c or $d) + } + +Counting strings +---------------- + +Sometimes we need to know not only if a certain string is present or not, +but how many times the string appears in the file or process memory. The number +of occurrences of each string is represented by a variable whose name is the +string identifier but with a # character in place of the $ character. +For example:: + + rule CountExample + { + strings: + $a = "dummy1" + $b = "dummy2" + + condition: + #a == 6 and #b > 10 + } + + +This rule matches any file or process containing the string $a exactly six times, +and more than ten occurrences of string $b. + +.. _string-offsets: + +String offsets or virtual addresses +----------------------------------- + +In the majority of cases, when a string identifier is used in a condition, we +are willing to know if the associated string is anywhere within the file or +process memory, but sometimes we need to know if the string is at some specific +offset on the file or at some virtual address within the process address space. +In such situations the operator ``at`` is what we need. This operator is used as +shown in the following example:: + + rule AtExample + { + strings: + $a = "dummy1" + $b = "dummy2" + + condition: + $a at 100 and $b at 200 + } + +The expression ``$a at 100`` in the above example is true only if string $a is +found at offset 100 within the file (or at virtual address 100 if applied to +a running process). The string $b should appear at offset 200. Please note +that both offsets are decimal, however hexadecimal numbers can be written by +adding the prefix 0x before the number as in the C language, which comes very +handy when writing virtual addresses. Also note the higher precedence of the +operator ``at`` over the ``and``. + +While the ``at`` operator allows to search for a string at some fixed offset in +the file or virtual address in a process memory space, the ``in`` operator +allows to search for the string within a range of offsets or addresses. :: + + rule InExample + { + strings: + $a = "dummy1" + $b = "dummy2" + + condition: + $a in (0..100) and $b in (100..filesize) + } + +In the example above the string $a must be found at an offset between 0 and +100, while string $b must be at an offset between 100 and the end of the file. +Again, numbers are decimal by default. + +You can also get the offset or virtual address of the i-th occurrence of string +$a by using @a[i]. The indexes are one-based, so the first occurrence would be +@a[1] the second one @a[2] and so on. If you provide an index greater then the +number of occurrences of the string, the result will be a NaN (Not A Number) +value. + + +Match length +------------ + +For many regular expressions and hex strings containing jumps, the length of +the match is variable. If you have the regular expression /fo*/ the strings +"fo", "foo" and "fooo" can be matches, all of them with a different length. + +You can use the length of the matches as part of your condition by using the +character ! in front of the string identifier, in a similar way you use the @ +character for the offset. !a[1] is the length for the first match of $a, !a[2] +is the length for the second match, and so on. !a is a abbreviated form of +!a[1]. + + +File size +--------- + +String identifiers are not the only variables that can appear in a condition +(in fact, rules can be defined without any string definition as will be shown +below), there are other special variables that can be used as well. One of +these special variables is ``filesize``, which holds, as its name indicates, +the size of the file being scanned. The size is expressed in bytes. :: + + rule FileSizeExample + { + condition: + filesize > 200KB + } + +The previous example also demonstrates the use of the ``KB`` postfix. This +postfix, when attached to a numerical constant, automatically multiplies the +value of the constant by 1024. The ``MB`` postfix can be used to multiply the +value by 2^20. Both postfixes can be used only with decimal constants. + +The use of ``filesize`` only makes sense when the rule is applied to a file. If +the rule is applied to a running process it won’t ever match because +``filesize`` doesn’t make sense in this context. + +Executable entry point +---------------------- + +Another special variable than can be used in a rule is ``entrypoint``. If the +file is a Portable Executable (PE) or Executable and Linkable Format (ELF), +this variable holds the raw offset of the executable’s entry point in case we +are scanning a file. If we are scanning a running process, the entrypoint will +hold the virtual address of the main executable’s entry point. A typical use of +this variable is to look for some pattern at the entry point to detect packers +or simple file infectors. :: + + rule EntryPointExample1 + { + strings: + $a = { E8 00 00 00 00 } + + condition: + $a at entrypoint + } + + rule EntryPointExample2 + { + strings: + $a = { 9C 50 66 A1 ?? ?? ?? 00 66 A9 ?? ?? 58 0F 85 } + + condition: + $a in (entrypoint..entrypoint + 10) + } + +The presence of the ``entrypoint`` variable in a rule implies that only PE or +ELF files can satisfy that rule. If the file is not a PE or ELF, any rule using +this variable evaluates to false. + +.. warning:: The ``entrypoint`` variable is deprecated, you should use the + equivalent ``pe.entry_point`` from the :ref:`pe-module` instead. Starting + with YARA 3.0 you'll get a warning if you use ``entrypoint`` and it will be + completely removed in future versions. + + +Accessing data at a given position +---------------------------------- + +There are many situations in which you may want to write conditions that depend +on data stored at a certain file offset or virtual memory address, depending on +if we are scanning a file or a running process. In those situations you can use +one of the following functions to read data from the file at the given offset:: + + int8() + int16() + int32() + + uint8() + uint16() + uint32() + + int8be() + int16be() + int32be() + + uint8be() + uint16be() + uint32be() + +The ``intXX`` functions read 8, 16, and 32 bits signed integers from +, while functions ``uintXX`` read unsigned integers. +Both 16 and 32 bit integers are considered to be little-endian. If you +want to read a big-endian integer use the corresponding function ending +in ``be``. The parameter can be any expression returning +an unsigned integer, including the return value of one the ``uintXX`` functions +itself. As an example let's see a rule to distinguish PE files:: + + rule IsPE + { + condition: + // MZ signature at offset 0 and ... + uint16(0) == 0x5A4D and + // ... PE signature at offset stored in MZ header at 0x3C + uint32(uint32(0x3C)) == 0x00004550 + } + + +Sets of strings +--------------- + +There are circumstances in which it is necessary to express that the file should +contain a certain number strings from a given set. None of the strings in the +set are required to be present, but at least some of them should be. In these +situations the ``of`` operator can be used. :: + + rule OfExample1 + { + strings: + $a = "dummy1" + $b = "dummy2" + $c = "dummy3" + + condition: + 2 of ($a,$b,$c) + } + +This rule requires that at least two of the strings in the set ($a,$b,$c) +must be present in the file, but it does not matter which two. Of course, when +using this operator, the number before the ``of`` keyword must be less than or +equal to the number of strings in the set. + +The elements of the set can be explicitly enumerated like in the previous +example, or can be specified by using wild cards. For example:: + + rule OfExample2 + { + strings: + $foo1 = "foo1" + $foo2 = "foo2" + $foo3 = "foo3" + + condition: + 2 of ($foo*) // equivalent to 2 of ($foo1,$foo2,$foo3) + } + + rule OfExample3 + { + strings: + $foo1 = "foo1" + $foo2 = "foo2" + + $bar1 = "bar1" + $bar2 = "bar2" + + condition: + 3 of ($foo*,$bar1,$bar2) + } + +You can even use ``($*)`` to refer to all the strings in your rule, or write +the equivalent keyword ``them`` for more legibility. :: + + rule OfExample4 + { + strings: + $a = "dummy1" + $b = "dummy2" + $c = "dummy3" + + condition: + 1 of them // equivalent to 1 of ($*) + } + +In all the examples above, the number of strings have been specified by a +numeric constant, but any expression returning a numeric value can be used. +The keywords ``any`` and ``all`` can be used as well. :: + + all of them // all strings in the rule + any of them // any string in the rule + all of ($a*) // all strings whose identifier starts by $a + any of ($a,$b,$c) // any of $a, $b or $c + 1 of ($*) // same that "any of them" + +Applying the same condition to many strings +------------------------------------------- + +There is another operator very similar to ``of`` but even more powerful, the +``for..of`` operator. The syntax is:: + + for expression of string_set : ( boolean_expression ) + +And its meaning is: from those strings in ``string_set`` at least ``expression`` +of them must satisfy ``boolean_expression``. + +In other words: ``boolean_expression`` is evaluated for every string in +``string_set`` and there must be at least ``expression`` of them returning +True. + +Of course, ``boolean_expression`` can be any boolean expression accepted in +the condition section of a rule, except for one important detail: here you +can (and should) use a dollar sign ($) as a place-holder for the string being +evaluated. Take a look at the following expression:: + + for any of ($a,$b,$c) : ( $ at entrypoint ) + +The $ symbol in the boolean expression is not tied to any particular string, +it will be $a, and then $b, and then $c in the three successive evaluations +of the expression. + +Maybe you already realised that the ``of`` operator is an special case of +``for..of``. The following expressions are the same:: + + any of ($a,$b,$c) + for any of ($a,$b,$c) : ( $ ) + +You can also employ the symbols # and @ to make reference to the number of +occurrences and the first offset of each string respectively. :: + + for all of them : ( # > 3 ) + for all of ($a*) : ( @ > @b ) + +Using anonymous strings with ``of`` and ``for..of`` +--------------------------------------------------- + +When using the ``of`` and ``for..of`` operators followed by ``them``, the +identifier assigned to each string of the rule is usually superfluous. As +we are not referencing any string individually we do not need to provide +a unique identifier for each of them. In those situations you can declare +anonymous strings with identifiers consisting only of the $ character, as in +the following example:: + + rule AnonymousStrings + { + strings: + $ = "dummy1" + $ = "dummy2" + + condition: + 1 of them + } + + +Iterating over string occurrences +--------------------------------- + +As seen in :ref:`string-offsets`, the offsets or virtual addresses where a given +string appears within a file or process address space can be accessed by +using the syntax: @a[i], where i is an index indicating which occurrence +of the string $a you are referring to. (@a[1], @a[2],...). + +Sometimes you will need to iterate over some of these offsets and guarantee +they satisfy a given condition. For example:: + + rule Occurrences + { + strings: + $a = "dummy1" + $b = "dummy2" + + condition: + for all i in (1,2,3) : ( @a[i] + 10 == @b[i] ) + } + +The previous rule says that the first three occurrences of $b should be 10 +bytes away from the first three occurrences of $a. + +The same condition could be written also as:: + + for all i in (1..3) : ( @a[i] + 10 == @b[i] ) + +Notice that we’re using a range (1..3) instead of enumerating the index +values (1,2,3). Of course, we’re not forced to use constants to specify range +boundaries, we can use expressions as well like in the following example:: + + for all i in (1..#a) : ( @a[i] < 100 ) + +In this case we’re iterating over every occurrence of $a (remember that #a +represents the number of occurrences of $a). This rule is specifying that every +occurrence of $a should be within the first 100 bytes of the file. + +In case you want to express that only some occurrences of the string +should satisfy your condition, the same logic seen in the ``for..of`` operator +applies here:: + + for any i in (1..#a) : ( @a[i] < 100 ) + for 2 i in (1..#a) : ( @a[i] < 100 ) + +In summary, the syntax of this operator is:: + + for expression identifier in indexes : ( boolean_expression ) + +.. _referencing-rules: + +Referencing other rules +----------------------- + +When writing the condition for a rule you can also make reference to a +previously defined rule in a manner that resembles a function invocation of +traditional programming languages. In this way you can create rules that +depend on others. Let's see an example:: + + rule Rule1 + { + strings: + $a = "dummy1" + + condition: + $a + } + + rule Rule2 + { + strings: + $a = "dummy2" + + condition: + $a and Rule1 + } + +As can be seen in the example, a file will satisfy Rule2 only if it contains +the string "dummy2" and satisfies Rule1. Note that it is strictly necessary to +define the rule being invoked before the one that will make the invocation. + +More about rules +================ + +There are some aspects of YARA rules that have not been covered yet, but are +still very important. These are: global rules, private rules, tags and +metadata. + +Global rules +------------ + +Global rules give you the possibility of imposing restrictions in all your +rules at once. For example, suppose that you want all your rules ignoring +those files that exceed a certain size limit, you could go rule by rule making +the required modifications to their conditions, or just write a global rule +like this one:: + + global rule SizeLimit + { + condition: + filesize < 2MB + } + +You can define as many global rules as you want, they will be evaluated +before the rest of the rules, which in turn will be evaluated only if all +global rules are satisfied. + +Private rules +------------- + +Private rules are a very simple concept. They are just rules that are not +reported by YARA when they match on a given file. Rules that are not reported +at all may seem sterile at first glance, but when mixed with the possibility +offered by YARA of referencing one rule from another (see +:ref:`referencing-rules`) they become useful. Private rules can serve as +building blocks for other rules, and at the same time prevent cluttering +YARA's output with irrelevant information. To delcare a rule as private +just add the keyword ``private`` before the rule declaration. :: + + private rule PrivateRuleExample + { + ... + } + +You can apply both ``private`` and ``global`` modifiers to a rule, resulting in +a global rule that does not get reported by YARA but must be satisfied. + +Rule tags +--------- + +Another useful feature of YARA is the possibility of adding tags to rules. +Those tags can be used later to filter YARA's output and show only the rules +that you are interested in. You can add as many tags as you want to a rule, +they are declared after the rule identifier as shown below:: + + rule TagsExample1 : Foo Bar Baz + { + ... + } + + rule TagsExample2 : Bar + { + ... + } + + +Tags must follow the same lexical convention of rule identifiers, therefore +only alphanumeric characters and underscores are allowed, and the tag cannot +start with a digit. They are also case sensitive. + +When using YARA you can output only those rules which are tagged with the tag +or tags that you provide. + + +Metadata +-------- + +Besides the string definition and condition sections, rules can also have a +metadata section where you can put additional information about your rule. +The metadata section is defined with the keyword ``meta`` and contains +identifier/value pairs like in the following example:: + + rule MetadataExample + { + meta: + my_identifier_1 = "Some string data" + my_identifier_2 = 24 + my_identifier_3 = true + + strings: + $my_text_string = "text here" + $my_hex_string = { E2 34 A1 C8 23 FB } + + condition: + $my_text_string or $my_hex_string + } + +As can be seen in the example, metadata identifiers are always followed by +an equals sign and the value assigned to them. The assigned values can be +strings, integers, or one of the boolean values true or false. Note that +identifier/value pairs defined in the metadata section can not be used in +the condition section, their only purpose is to store additional information +about the rule. + +.. _using-modules: + +Using modules +============= + +Modules are extensions to YARA's core functionality. Some modules like +the :ref:`PE module ` and the :ref:`Cuckoo module ` +are officially distributed with YARA and additional ones can be created by +third-parties or even yourself as described in :ref:`writing-modules`. + +The first step to using a module is importing it with the ``import`` statement. +These statements must be placed outside any rule definition and followed by +the module name enclosed in double-quotes. Like this:: + + + import "pe" + import "cuckoo" + +After importing the module you can make use of its features, always using +``.`` as a prefix to any variable or function exported by the +module. For example:: + + pe.entry_point == 0x1000 + cuckoo.http_request(/someregexp/) + +.. _undefined-values: + +Undefined values +================ + +Modules often leave variables in an undefined state, for example when the +variable doesn't make sense in the current context (think of ``pe.entry_point`` +while scanning a non-PE file). YARA handles undefined values in way that allows +the rule to keep its meaningfulness. Take a look at this rule:: + + import "pe" + + rule Test + { + strings: + $a = "some string" + + condition: + $a and pe.entry_point == 0x1000 + } + +If the scanned file is not a PE you wouldn't expect this rule to match the file, +even if it contains the string, because **both** conditions (the presence of +the string and the right value for the entry point) must be satisfied. However, +if the condition is changed to:: + + $a or pe.entry_point == 0x1000 + +You would expect the rule to match in this case if the file contains the string, +even if it isn't a PE file. That's exactly how YARA behaves. The logic is +simple: any arithmetic, comparison, or boolean operation will result in an +undefined value if one of its operands is undefined, except for *OR* operations +where an undefined operand is interpreted as a False. + + +External variables +================== + +External variables allow you to define rules which depends on values provided +from the outside. For example you can write the following rule:: + + rule ExternalVariableExample1 + { + condition: + ext_var == 10 + } + +In this case ``ext_var`` is an external variable whose value is assigned at +run-time (see ``-d`` option of command-line tool, and ``externals`` parameter of +``compile`` and ``match`` methods in yara-python). External variables could be +of types: integer, string or boolean; their type depends on the value assigned +to them. An integer variable can substitute any integer constant in the +condition and boolean variables can occupy the place of boolean expressions. +For example:: + + rule ExternalVariableExample2 + { + condition: + bool_ext_var or filesize < int_ext_var + } + +External variables of type string can be used with the operators: ``contains`` +and ``matches``. The ``contains`` operator returns true if the string contains +the specified substring. The ``matches`` operator returns true if the string +matches the given regular expression. :: + + + rule ExternalVariableExample3 + { + condition: + string_ext_var contains "text" + } + + rule ExternalVariableExample4 + { + condition: + string_ext_var matches /[a-z]+/ + } + +You can use regular expression modifiers along with the ``matches`` operator, +for example, if you want the regular expression from the previous example +to be case insensitive you can use ``/[a-z]+/i``. Notice the ``i`` following the +regular expression in a Perl-like manner. You can also use the ``s`` modifier +for single-line mode, in this mode the dot matches all characters including +line breaks. Of course both modifiers can be used simultaneously, like in the +following example:: + + rule ExternalVariableExample5 + { + condition: + /* case insensitive single-line mode */ + string_ext_var matches /[a-z]+/is + } + +Keep in mind that every external variable used in your rules must be defined +at run-time, either by using the ``-d`` option of the command-line tool, or by +providing the ``externals`` parameter to the appropriate method in +``yara-python``. + +Including files +=============== + +In order to allow for more flexible organization of your rules files, +YARA provides the ``include`` directive. This directive works in a similar way +to the *#include* pre-processor directive in C programs, which inserts the +content of the specified source file into the current file during compilation. +The following example will include the content of *other.yar* into the current +file:: + + include "other.yar" + +The base path when searching for a file in an ``include`` directive will be the +directory where the current file resides. For this reason, the file *other.yar* +in the previous example should be located in the same directory of the current +file. However, you can also specify relative paths like these:: + + include "./includes/other.yar" + include "../includes/other.yar" + +Or use absolute paths:: + + include "/home/plusvic/yara/includes/other.yar" + +In Windows, both forward and back slashes are accepted, but don’t forget to +write the drive letter:: + + include "c:/yara/includes/other.yar" + include "c:\\yara\\includes\\other.yar" diff --git a/yara-master/docs/yarapython.rst b/yara-master/docs/yarapython.rst new file mode 100644 index 0000000..100dc3f --- /dev/null +++ b/yara-master/docs/yarapython.rst @@ -0,0 +1,385 @@ +********************** +Using YARA from Python +********************** + +YARA can be also used from Python through the ``yara-python`` library. Once +the library is built and installed as described in :ref:`compiling-yara` +you'll have access to the full potential of YARA from your Python scripts. + +The first step is importing the YARA library: + +.. code-block:: python + + import yara + +Then you will need to compile your YARA rules before applying them to your data, +the rules can be compiled from a file path: + +.. code-block:: python + + rules = yara.compile(filepath='/foo/bar/myrules') + +The default argument is filepath, so you don't need to explicitly specify its +name: + +.. code-block:: python + + rules = yara.compile('/foo/bar/myrules') + +You can also compile your rules from a file object: + +.. code-block:: python + + fh = open('/foo/bar/myrules') + rules = yara.compile(file=fh) + fh.close() + +Or you can compile them directly from a Python string: + +.. code-block:: python + + rules = yara.compile(source='rule dummy { condition: true }') + +If you want to compile a group of files or strings at the same time you can do +it by using the ``filepaths`` or ``sources`` named arguments: + +.. code-block:: python + + rules = yara.compile(filepaths={ + + 'namespace1':'/my/path/rules1', + 'namespace2':'/my/path/rules2' + }) + + rules = yara.compile(sources={ + + 'namespace1':'rule dummy { condition: true }', + 'namespace2':'rule dummy { condition: false }' + }) + +Notice that both ``filepaths`` and ``sources`` must be dictionaries with keys +of string type. The dictionary keys are used as a namespace identifier, allowing +to differentiate between rules with the same name in different sources, as +occurs in the second example with the *dummy* name. + +The ``compile`` method also has an optional boolean parameter named +``includes`` which allows you to control whether or not the include directive +should be accepted in the source files, for example: + +.. code-block:: python + + rules = yara.compile('/foo/bar/my_rules', includes=False) + + +If the source file contains include directives the previous line would raise +an exception. + +If includes are used, a python callback can be set to define a custom source for +the imported files (by default they are read from disk). This callback function +is set through the ``include_callback`` optional parameter. +It receives the following parameters: + *``requested_filename``: file requested with 'include' + *``filename``: file containing the 'include' directive if applicable, else None + *``namespace``: namespace +And returns the requested rules sources as a single string. + +.. code-block:: python + import yara + import sys + if sys.version_info >= (3, 0): + import urllib.request as urllib + else: + import urllib as urllib + + def mycallback(requested_filename, filename, namespace): + if requested_filename == 'req.yara': + uf = urllib.urlopen('https://pastebin.com/raw/siZ2sMTM') + sources = uf.read() + if sys.version_info >= (3, 0): + sources = str(sources, 'utf-8') + return sources + else: + raise Exception(filename+": Can't fetch "+requested_filename) + + rules = yara.compile(source='include "req.yara" rule r{ condition: true }', + include_callback=mycallback) + +If you are using external variables in your rules you must define those +external variables either while compiling the rules, or while applying the +rules to some file. To define your variables at the moment of compilation you +should pass the ``externals`` parameter to the ``compile`` method. For example: + +.. code-block:: python + + rules = yara.compile('/foo/bar/my_rules’, + externals= {'var1': 'some string’, 'var2': 4, 'var3': True}) + +The ``externals`` parameter must be a dictionary with the names of the variables +as keys and an associated value of either string, integer or boolean type. + +The ``compile`` method also accepts the optional boolean argument +``error_on_warning``. This arguments tells YARA to raise an exception when a +warning is issued during compilation. Such warnings are typically issued when +your rules contains some construct that could be slowing down the scanning. +The default value for the ``error_on_warning`` argument is False. + + +In all cases ``compile`` returns an instance of the class :py:class:`yara.Rules` +Rules. This class has a ``save`` method that can be used to save the compiled +rules to a file: + +.. code-block:: python + + rules.save('/foo/bar/my_compiled_rules') + +The compiled rules can be loaded later by using the ``load`` method: + +.. code-block:: python + + rules = yara.load('/foo/bar/my_compiled_rules') + +Starting with YARA 3.4 both ``save`` and ``load`` accept file objects. For +example, you can save your rules to a memory buffer with this code: + +.. code-block:: python + + import StringIO + + buff = StringIO.StringIO() + rules.save(file=buff) + +The saved rules can be loaded from the memory buffer: + +.. code-block:: python + + buff.seek(0) + rule = yara.load(file=buff) + +The result of ``load`` is also an instance of the class :py:class:`yara.Rules`. + +Instances of ``Rules`` also have a ``match`` method, which allows you to apply +the rules to a file: + +.. code-block:: python + + matches = rules.match('/foo/bar/my_file') + +But you can also apply the rules to a Python string: + +.. code-block:: python + + with open('/foo/bar/my_file', 'rb') as f: + matches = rules.match(data=f.read()) + +Or to a running process: + +.. code-block:: python + + matches = rules.match(pid=1234) + +As in the case of ``compile``, the ``match`` method can receive definitions for +external variables in the ``externals`` argument. + +.. code-block:: python + + matches = rules.match('/foo/bar/my_file', + externals= {'var1': 'some other string', 'var2': 100}) + +External variables defined during compile-time don’t need to be defined again +in subsequent calls to the ``match`` method. However you can redefine +any variable as needed, or provide additional definitions that weren’t provided +during compilation. + +In some situations involving a very large set of rules or huge files the +``match`` method can take too much time to run. In those situations you may +find useful the ``timeout`` argument: + +.. code-block:: python + + matches = rules.match('/foo/bar/my_huge_file', timeout=60) + +If the ``match`` function does not finish before the specified number of +seconds elapsed, a ``TimeoutError`` exception is raised. + +You can also specify a callback function when invoking the ``match`` method. By +default, the provided function will be called for every rule, no matter if +matching or not. You can choose when your callback function is called by setting +the ``which_callbacks`` parameter to one of ``yara.CALLBACK_MATCHES``, +``yara.CALLBACK_NON_MATCHES`` or ``yara.CALLBACK_ALL``. The default is to use +``yara.CALLBACK_ALL``. Your callback function should expect a single parameter +of dictionary type, and should return ``CALLBACK_CONTINUE`` to proceed to the +next rule or ``CALLBACK_ABORT`` to stop applying rules to your data. + +Here is an example: + +.. code-block:: python + + import yara + + def mycallback(data): + print data + return yara.CALLBACK_CONTINUE + + matches = rules.match('/foo/bar/my_file', callback=mycallback, which_callbacks=yara.CALLBACK_MATCHES) + +The passed dictionary will be something like this: + +.. code-block:: python + + { + 'tags': ['foo', 'bar'], + 'matches': True, + 'namespace': 'default', + 'rule': 'my_rule', + 'meta': {}, + 'strings': [(81L, '$a', 'abc'), (141L, '$b', 'def')] + } + +The *matches* field indicates if the rule matches the data or not. The +*strings* fields is a list of matching strings, with vectors of the form:: + + (, , ) + +The ``match`` method returns a list of instances of the class ``Match``. +Instances of this class have the same attributes as the dictionary passed to the +callback function. + + +You can also specify a module callback function when invoking the ``match`` +method. The provided function will be called for every imported module that +scanned a file. Your callback function should expect a single parameter of +dictionary type, and should return ``CALLBACK_CONTINUE`` to proceed to the next +rule or ``CALLBACK_ABORT`` to stop applying rules to your data. + +Here is an example: + +.. code-block:: python + + import yara + + def modules_callback(data): + print data + return yara.CALLBACK_CONTINUE + + matches = rules.match('/foo/bar/my_file', modules_callback=modules_callback) + +The passed dictionary will contain the information from the module. + + +You may also find that the default sizes for the stack for the matching engine in +yara or the default size for the maximum number of strings per rule is too low. In +the C libyara API, you can modify these using the ``YR_CONFIG_STACK_SIZE`` and +``YR_CONFIG_MAX_STRINGS_PER_RULE`` variables via the ``yr_set_configuration`` +function in libyara. The command-line tool exposes these as the ``--stack-size`` +(``-k``) and ``--max-strings-per-rule`` command-line arguments. In order to set +these values via the Python API, you can use ``yara.set_config`` with either or +both ``stack_size`` and ``max_strings_per_rule`` provided as kwargs. At the time +of this writing, the default stack size was ``16384`` and the default maximum +strings per rule was ``10000``. + +Here are a few example calls: + +.. code-block:: python + + yara.set_config(stack_size=65536) + yara.set_config(max_strings_per_rule=50000, stack_size=65536) + yara.set_config(max_strings_per_rule=20000) + + +Reference +--------- + +.. py:module:: yara + +.. py:function:: yara.compile(...) + + Compile YARA sources. + + Either *filepath*, *source*, *file*, *filepaths* or *sources* must be + provided. The remaining arguments are optional. + + :param str filepath: Path to the source file. + :param str source: String containing the rules code. + :param file-object file: Source file as a file object. + :param dict filepaths: Dictionary where keys are namespaces and values are + paths to source files. + :param dict sources: Dictionary where keys are namespaces and values are + strings containing rules code. + :param dict externals: Dictionary with external variables. Keys are variable + names and values are variable values. + :param boolean includes: True if include directives are allowed or False + otherwise. Default value: *True*. + :param boolean error_on_warning: If true warnings are treated as errors, + raising an exception. + :return: Compiled rules object. + :rtype: :py:class:`yara.Rules` + :raises YaraSyntaxError: If a syntax error was found. + :raises YaraError: If an error occurred. + +.. py:function:: yara.load(...) + + .. versionchanged:: 3.4.0 + + Load compiled rules from a path or file object. Either *filepath* or + *file* must be provided. + + :param str filepath: Path to a compiled rules file + :param file-object file: A file object supporting the ``read`` method. + :return: Compiled rules object. + :rtype: :py:class:`yara.Rules` + :raises: **YaraError**: If an error occurred while loading the file. + +.. py:function:: yara.set_config(...) + + Set the configuration variables accessible through the yr_set_configuration + API. + + Provide either *stack_size* or *max_strings_per_rule*. These kwargs take + unsigned integer values as input and will assign the provided value to the + yr_set_configuration(...) variables YR_CONFIG_STACK_SIZE and + YR_CONFIG_MAX_STRINGS_PER_RULE, respectively. + + :param int stack_size: Stack size to use for YR_CONFIG_STACK_SIZE + :param int max_strings_per_rule: Maximum number of strings to allow per + yara rule. Will be mapped to YR_CONFIG_MAX_STRINGS_PER_RULE. + :return: None + :rtype: **NoneType** + :raises: **YaraError**: If an error occurred. + +.. py:class:: Rules + + Instances of this class are returned by :py:func:`yara.compile` and + represents a set of compiled rules. + + .. py:method:: match(filepath, pid, data, externals=None, callback=None, fast=False, timeout=None, modules_data=None, modules_callback=None) + + Scan a file, process memory or data string. + + Either *filepath*, *pid* or *data* must be provided. The remaining + arguments are optional. + + :param str filepath: Path to the file to be scanned. + :param int pid: Process id to be scanned. + :param str data: Data to be scanned. + :param dict externals: Dictionary with external variables. Keys are variable + names and values are variable values. + :param function callback: Callback function invoked for each rule. + :param bool fast: If true performs a fast mode scan. + :param int timeout: Aborts the scanning when the number of specified seconds + have elapsed. + :param dict modules_data: Dictionary with additional data to modules. Keys + are module names and values are *bytes* objects containing the additional + data. + :param function modules_callback: Callback function invoked for each module. + :raises YaraTimeoutError: If the timeout was reached. + :raises YaraError: If an error occurred during the scan. + + .. py:method:: save(...) + + .. versionchanged:: 3.4.0 + + Save compiled rules to a file. Either *filepath* or *file* must be provided. + + :param str filepath: Path to the file. + :param file-object file: A file object supporting the ``write`` method. + :raises: **YaraError**: If an error occurred while saving the file. diff --git a/yara-master/extra/TextMate-bundle.zip b/yara-master/extra/TextMate-bundle.zip new file mode 100644 index 0000000..5bf7975 Binary files /dev/null and b/yara-master/extra/TextMate-bundle.zip differ diff --git a/yara-master/extra/UltraEdit-wordfile.txt b/yara-master/extra/UltraEdit-wordfile.txt new file mode 100644 index 0000000..d497de4 --- /dev/null +++ b/yara-master/extra/UltraEdit-wordfile.txt @@ -0,0 +1,33 @@ +/L20"YARA rules" YARA_LANG Line Comment = // Block Comment On = /* Block Comment Off = */ Escape Char = \ String Chars = " File Extensions = YAR +/Marker Characters = "//" +/Delimiters = ~!@%^&*()-+=|\/{}[]<>:;"' , .? +/Function String = "rule [a-zA-Z0-9_]*" +/Indent Strings = "{" +/Unindent Strings = "}" +/Open Brace Strings = "{" "(" "[" +/Close Brace Strings = "}" ")" "]" + +/C1"YARA Keywords" +and at any all ascii +condition contains +entrypoint +for false filesize fullword +global +is in include int8 int16 int32 +meta matches +nocase not +or of +private +rule rva +section strings +them true +uint8 uint16 uint32 +wide + +/C4"YARA Strings" +" +// / + + + + diff --git a/yara-master/extra/logo.ai b/yara-master/extra/logo.ai new file mode 100644 index 0000000..2d2c9de --- /dev/null +++ b/yara-master/extra/logo.ai @@ -0,0 +1,293 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R 21 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + logo + + + + + 2015-12-10T09:39:10+01:00 + 2015-12-10T09:39:10+01:00 + 2015-12-10T09:33:55+01:00 + Adobe Illustrator CS5 + + + + 256 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXm/5kfnF/gvXINL/AER9f9a1S69b6x6N OckkfHj6Un++61rlGTNwmqd32b2P+axmfFw0a5X3eY72NWf/ADkhdXt3FaWnlVp7mdxHDCl5VmZj QAAW+Q/M+TnT9mxEGUstAf0f+PPYdKn1WezSXU7SOxumALW8UxuAtexf04hUewp75kRJPN5rLGAl UDxDvqv0lJPzD86jyd5fGrmz+vVnSAQep6X2wxry4ydOPhkcuTgFuV2dovzOTgvh2vvZBp919csL a748PrESS8K1481DUrQVpXJRNgFxMkeGRHcVfJMHYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXzh/zkh/ynFj/wBsyL/qInzC1P1fB7b2b/xeX9c/dFb/AM46 WFrcedLq5lXlLZ2bvb17M7pGW/4FiPpyOnFzX2jyEYAB/FJ7h+YHmS48teT9S1q2jWW4tUQQo9Sv OWVYlLAEEgF69czMkjGNh5Xs/TDPmjjPI/oFvmfzX+aPm7zTp6afqs8TWiSCb04olSrqCASRvtyP fMCWSUuZe50nZeHBLigDfvfU2kXEFt5Zsrm4kWKCCyikmlY0VUSIMzE+AAzPx/SPc+f5/wC8l7yk n/K3fyv/AOpp0z/pJj/rk2plqOjoroQyMAVYdCDuDiqXa95m8veX7eO51vUbfTbeV/TiluZFjVno W4gt3oCcVQWi/mB5I1y+Fho+uWV/elS4t7eZJH4r9o8VPQYqu13z15N0C7Sz1vWrPTrqSMTJBczJ G5jZiocBj0LIR9GKpd/yt38r/wDqadM/6SY/64q2v5uflezBR5p0ypNBW6iA+8nFWR6bqumanard 6beQX1q/2Li2kSaM/J0LLiqnrWu6Nodib/WL2GwslYI1xcOI0DNso5HbfFUp0v8AMnyBqt/Dp+m+ YLC8vrgkQ20M6PI5ALEKoNTsCcVQmpfm9+Wmm6mdLu/MFqt8riNoULSlXJpxYxq6hq9QTiqYa1+Y HkjQ742Gsa5ZWF6FDm3uJkjfi32TxY9DiqA/5W7+V/8A1NOmf9JMf9cVbX82/wAsGYKPNOmVY0Fb qIDfxJNBirJrHULDULZbqwuYru2f7E8DrJGfkyEg4qr4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXzh/ zkh/ynFj/wBsyL/qInzC1P1fB7b2b/xeX9c/dFI/yT1v9FfmHp4ZuMOoB7GX39YVjH/I1UyvFKpB yu28HiaaXfH1fL9lvo7zzoba75Q1bSkFZbm3b0B4yp8cf/DqMzcsbiQ8Voc/hZoz7j9nV8bkEEgi hGxBzXPpb681b/yV17/2w5f+oQ5ssX0j3Pl2o/vJe8vz/wAmwfpBpn/HNtP+MMf/ABEYsXiH/OX3 /KEaN/20x/1DyYpDyz/nFn/ya8P/ADBXP6hipegf85GflN+YHnDzvY6n5d0r69ZQ6ZFbSS/WLaGk q3E7leM0kbfZkU1pTFQ8s/6Fw/Of/qXv+nyx/wCq+KbQWr/kP+bWk2E1/e+XpRawKXlaGa2uGVVF S3CGWR6Ae2K2lH5f/mF5g8ka9DqmlTt6QYfXLEsfRuIq/Ejr0rT7LdVPTFX09/zkjqFtqX5KrqNq 3O1vZrK4gbxjl+NT9xxYh8reS7TzNeeZbS08sBm1y4EsVmEdIm+OF1fi8jIqn0y1DUffiyZvp3/O O35xw6hazSeX+Mcc0bu31yxNFVgSdp8UWz78/Pyd/MbzV+YMuraBpH1zT2tYIhP9YtYvjQHkOMss bbfLFQ85/wChcPzn/wCpe/6fLH/qvim0u138jvzV0LTZdS1LQJUsoAWmlilt7goo3LMsEkjBR3NK DFbQv5Z/mTrvkXzDBf2M7nT3kUalp9f3c8NaMCp2DgfZbqD7VGKl96288VxbxXELcopkWSNvFWFQ fuOLFUxV2KuxV2KuxV2KuxV2KuxV2KuxV84f85If8pxY/wDbMi/6iJ8wtT9Xwe29m/8AF5f1z90W Vfl/+Rmj2lrp3mDW7ySa7VYr1beMiOGMiki82pzbjtXcZLHgFcRLru0O3ZyMseMVHcX1PRPvMX58 +R9KMsNq82qXcdV9OBCkYYdmkk4/eobJy1Mem7iabsHUZKJqI8/1B806ldre6jdXixiFbmaSYQqa hBIxbiDt0rTMJ7nFDhiI86FPrTVv/JXXv/bDl/6hDmyxfSPc+Y6j+8l7y/P/ACbB+kGmf8c20/4w x/8AERixeIf85ff8oRo3/bTH/UPJikPLP+cWf/Jrw/8AMFc/qGKl9C/mn+ePlj8v2js54n1LWpk9 RNOgZU4IejTSHlwDdvhJ9qYoeUv/AM5j35YlPK0QSvwg3jEge5EI/Vimlp/5zF1Eih8rwkH/AJe2 /wCqWK0+e764S5vbi4jiEEc0jyJCv2UDMSFHTZa0xS+mfzIZm/5xX8vFiWP1fTBU77BQAPoGKHkH 5A/+Tf8ALf8Axml/6h5MUl90YsXmX5p/n15Z8g3Q0xoJNV1soJGsYWEaxqwqvrSkNxLdgFJpv4VV eYN/zmNqHI8fK0IWuwN4xNPn6IxTSx/+cw790ZH8qwMjAhlN2xBB2IIMWK0+dcUv0H/LiWSb8vPK 80h5SSaRYO7bCrNbRknbFiyLFXYq7FXYq7FXYq7FXYq7FXYq7FXzh/zkh/ynFj/2zIv+oifMLU/V 8HtvZv8AxeX9c/dFmv5LfmJ5v8yyyWGo2kU1jYxAPqaAxsG6IjKKo5IB6UyeDJImujqu2uzsOACU SRKR+lP/AM3NN8mr5S1HUtbsoXuViZLO4CqtwbhlIiVJB8X2tyOlB0yeeMeGzzcTsjJn8aMcZNXv 3V1fKmYL6A+wb63lufy2uLeFeUs2jPHGo7s1qQB95zZYvpHufLtR/eS95fn3k2D748p/mb5D1by9 YXkGuWUXKCMSQT3EUUsbhBySRHYMGU/2bYsXlH/OV3mDQdT8m6RFp2pWt7Kmohnjt545WC+hIKkI zECpxSHnn/OLP/k14f8AmCuf1DFSwr809Ru9Q/MjzNc3dfW/SVzFxbcqkMpijT/YIgX6MUh6l+RX kX8lNb8sS3nm68tptaM7q1lc3rWfpRLx4FVSSFn5deW47dsUF6V/yqb/AJxl/k07/uLz/wDZVii3 yPrcNrBrN/DaU+qxXMyW/FuQ9NZCEoxJr8PeuLJ9JfmN/wCsreX/APjBpv6sUPIfyB/8m/5b/wCM 0v8A1DyYpL7oxYvz08+ahd6h51168u2LXE1/clye1JWAX5KBQYsg9l/JLyB+RuseT0vvNN5bXOuS SSfWbS5vmszAoYrGqoksJYMo5cjXr7YoJehf8qm/5xl/k07/ALi8/wD2VYot8dYsn6Cfll/5Lbyn /wBsbT/+oWPFiyXFXYq7FXYq7FXYq7FXYq7FXYq7FXzx+f8AYXWo/mRpFhaLzubuwt4YU8XkuZ1X 8TmFqPqD2Xs/kENLOR5CRP8AsQ9u8oeVtP8ALGgW2kWSjjCKzS0o0srAc5G92P3DbMrHDhFPLazV Sz5DOXX7B3PnH84vPsvmjzI9vbP/ALh9NZobNR0kYGjzHx5EfD/k/M5g5cnEfJ7XsbQDBis/XLn+ pgGVu4fa/l//AI4Om/8AMLB/ybXNlj+ke58uz/3kveXzj+b/APzjNq76tPrfkeJbm2u3MtxpBdY5 IpGNWMLSFVZD14k1Hao6TawXlh/I/wDNn/qWbz7k/wCasU2lHmT8vfOnlm1iu9e0mfT7ed/SikmC gM9C3EUJ7DFbZ5/ziz/5NeH/AJgrn9QxQXoP56/8486xrWtz+afKKLcXN4eepaYzrGxkAp6sLOQp 5U+JSeu4rXZUF4yfyP8AzZ/6lm8+5P8AmrFNu/5Uf+bP/Us3n3J/zVitu/5Uf+bP/Us3n3J/zVit voDzz5L8033/ADjtovl2002abW7eKwWaxUD1FMQ+MHenw4sXmn5M/lR+YujfmboWp6poNzaWFtLI 09xIF4oGgkUE0J7kDFJL67xQ+afzt/5xz12/1+78y+Tokukv3M17pXJYpFmbd5Ii5VGDn4iKg16V 7KQXkv8Ayo/82f8AqWbz7k/5qxTbv+VH/mz/ANSzefcn/NWK27/lR/5s/wDUs3n3J/zVitvtLyBY 3dh5E8uWF5EYLy00uyguYW+0kkduiOp91YUxYp9irsVdirsVdirsVdirsVdirsVdirxj8wL+zsPz 48rXN4QsC2kKMzdFMk1zGrH5MwOYmU1MPTdn45T7PyiPPiP3RezkAgg9Dscy3mXzl+af5RaB5R0R tWtdRmZ5rhYbWylVTs1WI5Ch+FV60zAy4uHq9r2V2vk1GTgMRsNy8myl6F9o6XM0Pla0mUAtFYxu oPSqwgiubLH9I9z5dqP7yXvL5b/6G6/Mn/q26N/yIuv+ynJtdO/6G6/Mn/q26N/yIuv+ynFaYD+Y v5r+bfP9xbSa48KQWfL6tZ2qGOFDJTk3xM7sTxH2mNO2Kaep/wDOKPkPWv8AENx5uu7aS30uK1e3 sZZFKieWVhUx1+0qKpqelT88UF9SYodirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVYt5p/LTyj5o1CPUNYtnmuoohboySyRj01ZnAopA6ucrniEjZc/S9p5sEeGBoXfJPtL0 2HTbGOygklkhhHGMzyNK4XsObksae5yUY0KcTLkM5cRqz3bJb5r8k+XvNUNvDrULzR2rM8ISR46F gAa8CK9MjPGJc2/Sa3JpyTjNWxv/AJUP+W3/ACwS/wDSRN/zVkPy8XN/l7Vfzh8gzqOyt47FbJVP 1dIhCq1NeAXjSvXplwFCnUykZEk9Xmf/AELL+UH/AFapv+ku4/5rwsbd/wBCy/lB/wBWqb/pLuP+ a8VtMNI/5x+/KTS51uIdAjuJkbkpu5Jrhdu3pyu0ZHzXFXoUcaRoscahEQBURRQADYAAYq3irsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdir//Z + + + + + + uuid:91f869a7-49a3-b04e-bb5d-b31bdb5179ca + xmp.did:FD7F1174072068119109D8284DAF73E2 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + uuid:b793da81-910d-904c-b6eb-fb165ce2789b + xmp.did:F87F1174072068119109D8284DAF73E2 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:0180117407206811822AE61051C92AC8 + 2015-12-08T18:34:02+01:00 + Adobe Illustrator CS6 (Macintosh) + / + + + saved + xmp.iid:F87F1174072068119109D8284DAF73E2 + 2015-12-10T09:25:38+01:00 + Adobe Illustrator CS5 + / + + + saved + xmp.iid:FD7F1174072068119109D8284DAF73E2 + 2015-12-10T09:33:53+01:00 + Adobe Illustrator CS5 + / + + + + + + Document + Print + + + False + False + 1 + + 987.777778 + 987.777778 + Millimeters + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + + + Adobe PDF library 9.90 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 26 0 R/TrimBox[0.0 0.0 2800.0 2800.0]/Type/Page>> endobj 23 0 obj <>stream +HTˊ$DTN[@+!F-gvl+=3"annߏot?o}co+Mc<|ϖV9rKV{8ӪogEm% ß5d}V:g|d,XJ=kQΜr+g[gr*Lˁ<9bi츤usjJ􄊅-kaQbdm^HVj,Pkj9+?rgxtTÉRWD֕˖"6wXJX֙r^7qVy 9$!C%Έ:U{kkѓ>KXvXI޽jm6[goТGTh6/:M{v%RzjZGAgӏV)qR%Ά"&]2U8@ kM=yJ:tgtR:;)^DIIym1#.ݹ\/V67M IBw# 5 0]*pV觢,RE׎)-dEu(׺oSOC*I",>۾-|pw;`™׊~kEhc;E-%*&Y*NBTBBY,$@ՋQ C%O#DlXJilPg8;^y DI tIv:?E%Cϖ8ާYVΤqҚVNeAJPoC43R%9ȤamnIqVݟoI8 &R9`d+e#4sxf6*!MAV q?fB)wC:ἨB$>{y1ҵQ8X*QBS#D +!Yc>f{q>KOhei5[V;l? OJTxW2`Y.#KbҕXɸƯT5iZ"{pbO="z9%)o^G/8;}[$Qb}?'VVOTvEHm5I |wli ?~˛R$ƥƗRPE nRjPgzޮKAUB@R{H.N`w_ RiHA\56qiЀ[crfbFrUcz<IOUswKQ%q@{^#([;h[g,!-tr $SLG㒃o]^pI/\h6"Ȗ?4em&rbPjJqEDEFX!QYYDam!1tϼ?1m7L[r@o6*,,BDvEiSL Q\5S[[,p'^ hyU"5*Uʰ!m3 Q~K!W5%Q݂ .4-GA]|iy&\,՜ %u! +A)\ͰpRmE= V0jOq!jz]ʹ0Tt+ըQj5RҘ`)Vt5,NdUu? !|YO{ʗlNݠ&j!5Xxt _+a%U m04dM^mSO?PQuԒ%zx6}~l|O\h:,eIQ-[nФ˼Yl]72 ,; Wb5@ޛ@Y`EBh' dP$z1Rx>_&rg,eRSYg|d+N &qꅸJUU" Lz`e$gWL0@v/Ft =9A{/ƨR`MWUФ U׵sìt#S΋ɻI(?~R+H 7 <jo%!ZF>kFЫ#gTY:Qa|Tf]N`9<\ +ݛ6_.GdDPLΤMW4zAiP9IH);;B"1cD"F$N$xE*> eU endstream endobj 26 0 obj <>stream +8;Z\ulOC`S%"oKFs#_7lGVlU&0IAnM>_D>Dd +&G'G*>EA8V73&;\F+I#I[>l6kG\EZA;AkJ5hEmkh5F7\W^8*n@d8Tj'A3-@Y%m4%mt8$SsP,MA3L=69CNU8Xkg +UpCe)[t[p\MSJ3a96Nm1=%7J"'^b"EF<6_'J'oQ[Vp;2&ZJ6SWrT7]BH*hYIaZr$QLE8Ssa)a7X*Yp4TGH^z!!!#6c"d=5,Y'B~> endstream endobj 27 0 obj [/Indexed/DeviceRGB 255 28 0 R] endobj 28 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 21 0 obj <> endobj 29 0 obj [/View/Design] endobj 30 0 obj <>>> endobj 25 0 obj <> endobj 24 0 obj <> endobj 31 0 obj <> endobj 32 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 15.0 %%AI8_CreatorVersion: 15.0.2 %%For: (plusvic) () %%Title: (logo.ai) %%CreationDate: 10/12/15 09:39 %%Canvassize: 16383 %%BoundingBox: 0 0 2800 2800 %%HiResBoundingBox: 0 0 2800 2800 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 11.0 %AI12_BuildNumber: 399 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%CMYKProcessColor: 1 1 1 1 ([Registration]) %AI3_Cropmarks: 0 0 2800 2800 %AI3_TemplateBox: 1399.5 1399.5 1399.5 1399.5 %AI3_TileBox: 1094 1004 1706 1796 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 1 %AI9_ColorModel: 2 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: 642.875 1718.875 16 1620 999 26 0 0 43 135 0 0 0 1 1 0 1 1 0 1 %AI5_OpenViewLayers: 7 %%PageOrigin:1102 979 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 33 0 obj <>stream +%%BoundingBox: 0 0 2800 2800 %%HiResBoundingBox: 0 0 2800 2800 %AI7_Thumbnail: 128 128 8 %%BeginData: 5054 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFAFFCAFFCAFFCAFFA8FD78FFA093 %93936F9393A0CAFD04FFCA8DCAFD70FFA06893699368A0FD06FFA093A1FD %70FFA0939393699AFD07FFC98DCAFD70FFA168936993A0FD04FFC9999A6F %93A1FD70FFA09369938DC9FD04FF6F938D9369CAFD70FFA169936993A1FF %FFFFCA9368936993A1FFFFA8527D527DA8FD05FF7D5252597DFFFFA8527D %527D527D527D527D7DFD05FFA853527D52FF7D522752FF7D527D527D527D %527D527D7DFD34FFA09393938DC3FD04FFFD049369CAFFFF7D27272720FD %06FF7D20272752FFFF7D2720272727202727272027277DFFFFFFA8202727 %277DFD0427FF52272027272720272727202727A8FD32FFA16993699393FD %04FF9A68936993A1FFFF7DF827F827A8FD05FF5227F82752FFFF7DF827F8 %27F827F827F827F827F87DFFFF8427F8272027F827F852FF52F827F827F8 %27F827F827F827F8A8FD31FFA09393936993CAFFFFFFA19369938DCAFFFF %7D27F82727FD06FF7D2727F852FFFF7DFD0B27F82727FFFFA82727F8FD05 %2752FF52FD0B27F82727FD31FFA06893699368C3FD04FF6F936893A1FFFF %7EF827F827A8FD05FF5227F82752FFFFFFA8FFA8FFA8FFA8FFA87DF827F8 %277DFF7D27F827F8A8FFFFA8FFFFFFA8FFA8FFA8FFA8FFA852F827F827A8 %FD30FFA093939369939AFD04FFA069938DCAFFFF7D27202727FD06FF7D27 %27207DFD0DFF522027277DFFA827272027A8FD10FF27202727A8FD30FFA1 %6893699AA0FD05FF9A936993A1FFFFA8F827F827A8FD05FF5227F82752FD %05FFA8A8A8AFA8A8A8FF5227F82752FF7D27F827F8AFFD08FFA8A8A8AFFD %04A82727F8277DFD30FFA09369A0FD04FFCAC99993939369CAFFFF7D2727 %2720FD06FF7DF8272752FFFFFF84FD04272027272720272727F87DFFA8F8 %272727A8FD06FF7DFD04272027272720272727F87DFD30FFA16993A1FFFF %FF9A93699369936993A1FFFF7DF827F827A8FD05FF5227F82752FFFF7DF8 %27F827F827F827F827F827F82752FF7E27F827F8A8FD05FF52F827F827F8 %27F827F827F827F82753FD30FFA09393CFFD04FFA7A0FD049369CAFFFF7D %FD0427FD06FF7D20272752FFFF272720FD0B27207DFFA820272727A8FD04 %FFA8272720FD0B27207DFD30FFA169936FC3CAFD04FFA168936993A1FFFF %7DF827F827A8FD05FF5227F82752FF7D27F827F87DA8FFA8FFFFFF5227F8 %2752FFA827F827F8A8FD04FF5227F827F87DFFFFA8FFFFFF2727F8277DFD %30FFA093939369A0FD04FFA09369938DCAFFFF7D27F82727A8FD05FF7D27 %27F853FF7DF8272727A8FD06FF53F827277DFFA82727F827A8FD04FF52F8 %272727FD07FF27F827277DFD30FFA068936993A8FFFFFFA19369936893A1 %FFFFA8F827F827277D7D7E7DA82727F82752FF5227F827F8527DA87D7D7D %A82727F82752FF7D27F827F8A8FD04FF5227F827F8527D84FD047D2027F8 %277DFD30FFA0938D93A7FD04FF9A8D9393938DCAFFFFFF52202727272027 %272720272727207DFFA82027272720272727202727272027277DFFA82727 %2027A8FD04FF7E2027272720272727202727272027277DFD30FFA16893A0 %FD04FF9A689369936993A1FFFFFFA852F827F827F827F827F827F82752FF %FF59F827F827F827F827F827F827F82752FF7D27F827F8A9FD05FF52F827 %F827F827F827F827F827F8277DFD30FFA09393FD04FFCA8D936993939369 %CAFD05FF7DF8272727F8272727F8272752FFFFFF7DFD0427F8272727F827 %2727F87DFFA8F8272727A8FD06FF7DF8272727F8272727F8272727F87DFD %30FFA169A1FD04FF6F93699369936993A1FD06FFA87DA87DA87DA85227F8 %2752FD05FF7DA87DA87DA87DA87DA87DA8A8FFA8A87DA87DFD08FFA87DA8 %7DA87DA87DA87DA87DA8A8FD30FFA093CAFFFFFFCA938DFD059369CAFD0D %FF5220272752FD5EFFA169CFFD04FFA09A939369936993A1FFFFFFFD087D %5352F827F82752FD5EFFA093CAFD06FFCA939369938DCAFFFFA827F82727 %27F8272727F8272727F8A8FD5EFFA0689AFD06FF9A9369936893A1FFFFA8 %F827F827F827F827F827F8272784FD5FFFA0938DC3FD05FF9A8DFD0493CA %FFFFA82720FD0827527DFD62FFA8CAA7FD05FFA8CAA8CAA8CACFFFFFFFA8 %A8A8AFA8A8A8AFA8FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD %FCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD %FCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDAEFFFF %%EndData endstream endobj 34 0 obj <>stream +%AI12_CompressedDataxܽz*9(zn{ ` Lhn`]ߏڏNa={? *T*j7=fHy^hZs45oj|X.= 7F2%@C6lSnY#<,·[_hwZ.7Ӎw0wpmQ da[1-X|#BG,̴(E57k!G7I A'qXRz}$O1O1`ʎ>=`.7qV]hAmK[6c8F#`2|C + c,3O0(Q'ƒ840Uu0y5z>$IH= 7gz SkvrOwާ&@[Xsd}k0`1 xe 5ixFOal vf43ֆ?h,y)lU@`X4edџܿo Xe̯_r cۀj/mD[MP [@0 +j"A{`?ZwffٟѯGcbH1 Z+csr>|$@9yv +cY 7n%K}@%S+5hz I7lZ6y>xԅ/Ę'P,WYo^?qar}σet|9( aV-zv c|? 0ϝ*cd`_C0$@QA܁}PH8X +t;jp\Dc$?*g]&}7N|10wB-c-`枆 +r x0p/6}ϖ}@+j?_5ZڻC'If4M6Iχ==r%@ybuIcv7]|*; =oxw1\܌XNkYH^f=h 6` > NŢH&Ӏ|CinB]QLA!L_,5xvxD4GoY{aGnUjg"͚8{Fu<ZZrz=rc+qmPqo tc)㗤~9_S=6hf$MnOў~C`=E>7|4ӛ|IU?tF87/n]Ð!M6(?VCj|Y||϶3;3咋[)B(pVTtI,m󸮒 fCCqs4X~ciEF{f`H  `A$b+фoޞj{JrO 22a=S;I_iR͚u" k IZ.qN#fES \8 #W +绽 !ʬKh$֊,Z٢>.Hـ0zBTy_B"x!7*Y#ZMq*үf]ƼbcHG@ +Uنrֺ|;Dd4)3)AUdOP4%U +dP%NPf-R 3h|(jSZl)&FFbQQp n7zlA3|G3&ZL`6 F3 qbSoyV!1Zv\w]5 ـ$.HbZKbrHUH]2c`J-̶ڨ52i,nht3IH.AM8 ?Cܬ`BΖSŴb<ċ>Ӄn;@7w 9ŌX޻D*ujh8'z4 D9 9h9Bͪh| 0 'j5h>;-T Rk_$_#}+|3MuRaˡ޼e75?!n"IimexW:(~;ʕw[E{i<1X!?zde'>Y6?"퍁 v?M鱬>tFQŞdue߮tZQgh%F~ +LA|qviyh!Sm;҉Y` '_zd[nv@=E!6 [FE8>`~ɧ;MeAjM;ځyy[RܦJqV0TiS~ !Rم#aY=)$o&; D]b|+T9wvW*Up;]21y; ղ! h};%t5`#*~ >"uQq'oa0dחXyrz~ҜS5 1BtNVs/1YYI#x#6WLq Gh}{ (҉ޜi=CP7ājSۨ>N?ԚHa&?;2bC4%pJ Sl93ve]Lۨ'~\a2k+S7^49@0崽X.E:{taeTfNuew7;\oȝءAO={?8>'KmrC=_feT=2"X\w?~]H̎ˆ~74O9 e!&>5uÍB6,n&yvy6g XJZ_pMts5a>C=ph,}{ C.tW낵:Yd +t@Y GʟJ6lKÙ}~9L<Ȉ p_}*\~"lcɟY#eV0%g*v ]7XT-_ZX)^01<\lUII S4ix{K5c=ՖZ5~’}>7_^0\/Xœ 8"I_ q Ix3;GO/%R}9-V[Er>Q1ROkͼ<7Xon0խwY(Z]l,YL5zG}zw9b=`kl9s5@~c(Qi7cc*ӷz-Ҁ0~BQ}bInaToNQ}1ͭYUIwtLKiںin~]FoGÎ~#Kbj]Li(Ʈr'zsg{~c)jx|P=RW}Ls0ܙb[v M.2X_OFmgyI$chib^poI Cd*~V{ $Yv@<C>)s{ oͿ 0_:dA^@޷6@d g%+e5$$,7!Zfzth{L-^-ny=KӴ'v29|طNo%жnf39›KOS9-2V&k FfD۲|MQ#21"#$I[b2z$ŜQttKQ\Kp\T)c扡$K˧+)~}Ot +AY0 t{:`SC{fV\\ح~fU0+D-}3͑ +(ro˻Bqc}ͮj1ZCK)Aځ Z'-8{dwZ4UҴO6Wac@kNpoSMahD` 179-fRJ#fb(oй2=*\vG4D'ހUTlt2k3"sSB&䩼@AAcAPG{EKV'uaZCXLTsЭg6] |%'br&mݚtT3|؃EZg}07QuP>]rhЅF*uKqZG:@|e r%؍0\8P^4IG "\n%cD҆[,0 PpW7kLcSݵ1g)-|qFdLtmoQErbnOXd,' ^4Mx+j6 `ϣ.a`.z0ԯ o1Y'^4q2c;֩ߺs|"& M#7CJ>+D&Ͻul  !t%jF8yPEDJGb +fyՇ/]EXUxrsj +Tz^ 7A0.eZS\7>n&yt(;&b<K􎚭\%{VVfKz6 +h:ꋐSgoX#~T4IBiBOcTzx^XSBæB,q-܂9:BڈQ˴:b=IH8jfs/ùRWZ>MMRf(*`etc@,ļ؉6fNz+6Mn4A)N pR03EJ+/̏h^Io۪5Q6ju uZ P I2Bhrkl;]-Chm&aGq>4\yf?S[XB\.i#f6F36~ڛo_CC`Qj7OwU`4 6C o)=cb[bF ZNi +##J:޷;/4RhVB6 -2zTm[SӁpȄB!UW6`ǁ^*a(=fJdғ IgC2meP7\G=[ +.勠zWNԈs8ixX4PkxZpE<Pl̋x:czꄋۊz-qC>"؎Ʈh +9VLǗP15&vN/`Iq}l7#=զh‘Ӝɖ=I} ?+XE%m!EO-gl7{5L2m?W<t8(g)jh#W-Eg31l4`ǿ)7[_3l` `c1O0ua~q`r4 5k#. zH8TMM +`Kv̅X|;A[,ؙ:^bvתx;v~,WpO+_!16̀B/FR=>דu?70^oA"pgXiQ40w=?(ߙ<>[`5R3gs{5ɛ<ēu}Ȕsw\~}h ~QJ>3Xi:u7̸ϏJlo=.ПDm2w#ҙY,ӆӣh:hr{&O5F&UV01_,M}vt7,g #+2Xѐv/[oKF^.Z[=giIoynM'vms`!@'HD Fio=R%ӭ0iph)Aʍ%Z:,^lY}H݅ȎΖ>吺`Ribi?$H!6}'pMYu9Dq2*+"*e쎉RʏϵpN9,Һ͆",oijAuqJG-?3(!ѽ(ّG\pZ~Ç'*Y٢M# :Y8V^ +Hk(W@M% EhK7wUj*m+csZ\E0Xw{:ZJVX]]2H}%<!Z펢HkK`xn?\D{GZ Iia "F| +6ы#z,qߙC +$LwSkNJH7}Vi9`)"1YakC +x:_ĭnYz" uo*!}" ^ixe8?&…uRzC|uޝ>#ĭg&JOD?܏)<`,^g%|`'c'C 6ʋQb ;OVin%w%wul*;deњeLr:~iJ?}QzJ&V ilh}re7gFzV5+|RYVZJ3$i}{[غts/$7zG\Wqך[o&0[6d?wu)s@$Z|@s8;HXf᜝ړHCiM6Hݎ2Rsq ZGK[0͟JHU<1Z.H"r3&8f;4ؼ1X*"EܦxsG~ / G+"ʯH0RH/eQ$ +-X_fw7a[&tA ~VsԙvPZ GDKx~#rE#\8 ++>M_I7 kS-]kR i\0A!}|b,ߟ< 6^[+1#_?dkWb0쀱. +Va8F80'" NoF孀?%NM.$WDGO.;IҕG#? $3~ҚzIlHds&\'Kn (>B^n9K+9ʫ}@y-6սry&Xx7Gފ SfQ@]-JUuvv]ehWlKV%.W% 힬Tu ` N44E}hUަVƥ`URG¨nQ3{@Pś %#>T8A_},7;E`0,^wh :,D6?OT[$m9xPh)D&~gǼ'"Pu yX\=#&9 k/rV0 S=EVqb`Tb0%TERtDnle֓`]rX1v.AOtʟ}=wL:q,*R<sqjXX4l~|5LʱA:jˁBr20B&-MlQLî;ejHS)F8>+q\NOQIc6fӲXѫ + wgʪr 7em0J P*8 MR:nA:}0X ԗZtEK +hvuiQG c0+ і&% 7b yR`PЏ@0_@~$f씨K{^ κ9ZrH<ۻlrCHt-KAʳ /\{oIgxf~TɁSUd4b.q9b!(0|LXehK\Iӌ.nfj,adcF#@V @;$ 5r]&Y=ۭ'š87_Iu*U҉ >~ QEzEG- sm ['(ล}4 g"\ŽgY-YNW i Y^1֛ 'f_nսi45qRфh+BJΥ) ޡVyׄ7 ΋U ڀ-p`i4juޮa*g-ָnmrP! isJCbUsAOg(\8m86Tׅ24{N׆*0nRmE($@G><%a( +]E4,H7,iWbV*Z13iVsceb_G5tN%#DqK%G$zɊNZWM-k@Iǟ̤(3y5|# STHe^Nڽ4XğoO119'wQM/0>% +XpLD]R K;/,fb_9@rڬlyP(nҽb+U/ +::5t. +:b:<긂?%: +:Z: L9|Q z^-xI zJI5ttx%5ttjk+-vy zkЩW1c9NR7-NWGtDzA69EFNȋ_޺\r=8t2iqR+SǓS0>i͈9F. z_L钮GȕJb;ԢdM. g#pn)]CH&uYvj*N(%iOQ02 g!VhIJ  BdЊ.2f퉐-1S+a<)pc~H(L8IJ,qviʚ JUk''U,/:>'R.M`F|I-#ikOD0eD((/#O)S޽8b7Q,p 0q9^R脪4gtٲeibHXT8/ZZݤt=RGN$nر5LkQf;y\Aa!+M2ˁו S 9u2y}:aCaĦujdۯth1dۯrRek<'p2s0u9qjUa[Q*f>:X44i`|GYEjԁx^]"oשHBE*i\"JE*syE*rTX} $O~ ,CSu%oxZ.+õ gA_NXl1?R +w_yR)D,c2"4#/.CguNlSLȂń'q]i2+=Zn@wg0]!ڛ 谈MPS{.ntIrҷ#,hT`Ϣ=dע7{ӄW Vxx$H;x7- ou2gT!YDXetY]"NZ,̯}NeQv/Oه7R]V("Ej+ [PYr]ORF +/S;KT.Q{I70Uӊv3*uՊݦ>rukT}|G"Rӧ%D^Zp+U\==Uƺ,8Wvg>Ap̂!Ǹ v% +U-vr{doWDyiDbI>j|UZfŜ+;Z7b}$'AiNgn3_R )Dz?7T2^!;9iuوɝvv {F]&녘T[P ~TXCi%/t]+cgt`N] ]l)OUmk Xkm[[2rG#U^`*)d8s7'ʕK jV)p.?%sm"QI:-W,B vxu o2 gDϸN}2@]jYpU>qwb wgݔwr=My.C wwÝAj^ L5N_XKeFA[+)\u%\!8Y9We +ҕ־ ]68o+0ٸo*"iRbeLjEjC{^^H[X::w_٧x_vJ.a(*N1jV 5nictMyָyv(RvTGuÝZ[Æy#:Λ:}*%v#k\՛ +=e3PѴcEz.k5>²~n%cJi|=\|XGExK?9a]{W!oTDzK>GJHNJi.mbc,3J.ZNެJXWF;"R#-7'`cU)84wAe%w[GfBJZUCZ)"w)RKyZYbzG}ӮwXq 2l:5Mw%2)dDWGQVVQӑ6x2A\BVQc2r敻Lo&bot[Q<n^ΕEw$#y NSR4ҜiUiJszuӉYZ=p|9zݭ^WidN7'ʭLoscŮakhu`%- +mTօt=ckk{F=M&:Xq`@bZ^KA5KKW|L4B c+aÀYD訃0auusaWX*Gs^_TeJ6`)}]dN⸤nPH=H%5VCspmqK(yj) 6D}ݥw͟Rn"JkfZ]i)֫dWf-)֙#9S)H;*Y:ߕvjxU*ʜqB5O[J~EH i7식P jUHլV- + +'U*PJ'ߨ'#[#^Gu֥|gv|WO#pK I?t)=cS|_yΥ|Q)JRMd;3: +gCwr%½~g uƽ~CP½~)O +gC{.?JϽ~+/O\(CϺ/zd穣|i\'~LsS'~7p{2TsEX 9g*^zcg'JQ:DNtv55S;>sCpR)1Xs +#.O<_JLV?i@{+ROO + Muڽ~%&{ߙx}|=`]TzKueO=y!sٽ~|ɕla4^1^?m9v{o}|ZIz;0{½~y_ӼOYœqZ/W^~,{]Z+/O*/O\9^pߥ,ɭ~ǧ +W%J^sٚċ-ã[+ȱSOtBSwY]IV?qK1ŤWt dnR`NV?ig~4,g~= VV?,xѽ~g0g8hGwuƽ~z-/O]9T=Pc XpvY}.ME'ދQ5O[I LN=',{k %P:gMo|̐ѷߖ2QXOUvdtݚ` dg&OƕH\DjPO(V^2@7*Qzys&SfD)#Z6M6_݁xĻA| 5L~#'diw} m>-r Mv(/ѕ}oņ&h^3&G9hlmXq7>ۑNM3,}ML`lr?u&tey>rtȄ|$W?h49ł) +5{:Mo_ًV{{}O( (;|ۯ !n?= H}aYmL H}f*p&w=y='<4=07.Bss vUp,4H(]dxqnh/?<éˋ(F$"G78;@2i#aߐ? {!7^^XX}@.Xy hyqN@,}k.Sg>TSS6HvNQ.&_`_w2VßK8|_p{dMZ- 2 +UB쏊pr}ܻD1X|{s? T?!n,aF(_6wK' ]\8uSxn5H/}E_$͏{oANRnwsyWQ,Q\nCå%/NI~3"KKeþ[|| hYO6r%<^"[aP;>*PFz3wR/;YAH}ss +%XොZs~S*#I@B qQ! vtw'=Ή8,ˤꂢ°.wcrCE/.`|/#B + )r*33 0Ų`YpH˔4Hfϖggvy ~(eFz"osRMcz)0߽A ,agI`b"A{p7͍~?\izr}N3La5K22{0?L3{\fg ֲ+LF'b4``j![`[4|s),\87M/2x\4NnJnMG"\ =c}2iPh ī @mj]/QZ>=sr̗JwL+Hn$ߟz:AL/vR<~0os¶{#",2ڲ h1rC5Xu c ZH(Vz; z1#{I1'Աعb3u]:\Ե"Q'?bH o&4ʈv4ffL⺺tYk/.WPlU &{ rY_Djr8~Є>]zwCCw@L2e_>rp٘ü]9\:[P;JG0vs:y__a|3뚆 01ɘ!c +T]{s2õ.;r\ew~sP JXOk8^ V[zImgq6ezA@_~PWtz'nr[5]t$Ź=*B|PNDt|k|%vZ?? |-׋95HDMv[cO!rĭYerH'a. 7r{=VU\C9=`~@´oc~`XkN籗vk`kB# OY^grz:3gy W&I?5yYי IKfq qpݷeWe.%l9幘w3Mܖ/2sz& +װ'Ѽe|(@u骇h(auqhA߈^!{UYъF?cQbN \}(PIfc{YۉNt%$1X-7^ *rPQ,E\.6+04sogiLKož |@,Roܹ='jLX:G]!kUܙ6=lЊLq>$\lg?Ê?;hڙUNFGщģi>?; +{|Wx4l>?7h?7G38pv?R.y78+RE0{YVxT&LtviLO߆6E ͜˘6&܁p  X~{F~3S%?897VAC> өgxs;Vŀ3nτ'p ߕw)Dk{߾v}J{X,vP +;݈K` WbT{f>L}736?z|K)flךIH7wܪtt ,,Ų5\,32$< >,G'BGLF:0'1=k#UP$#}_Ma,RfJ$@w gHm uO`i++@:`4>aǨhM+H$ {I r`~.KQJU3t$,r*R&`pu: .0nX@ G"}@² :f#~YRYL&NJ H=PQyn? lA;s97@.aU0KϣczԧAPyw";kI9/\\=\ : +@ϐ:wkSBRQL/%39B~ys+K-\.YwL "@(,I`FQic7t.=L],Do{BW7x O'GŊ6'9$"F77S4饧\QN福XGw:`yGӻ T5\Xc41~h^=mN3_`ie9\ @/h:z>y""ʢ|;Zk |0F$?_ISI|O\-V9[jX9,($Ve7HƧkk1YN~gJ0#W΂Ţ0їXTLۨVa|gb"\X4/-?^[R aWkC݀W[<>HloCm8pAEAS"v_MYX3h~\*mP=$7 keŒ`A!d$|0' w}G(ldL}vzڷNG*i{Okg5" 342EC3Hp9ܲMtvi0 ݋mr_XGU#ՒTw7^V>M_ʡI:$|qDQ}"!0|zsc;se@zT"3՛W B'=A`3m`~2O),{Pk>Q9ߔ!P4%Et6 /@HST>Vzo}f!S͘2C^| "ʾcXiQ4 MIsk0'-.l>)x^omC<;Eë绸1qD 0ft%KE7oqlw"^춊wM1r~`,O|z잁/KN::dw.C4StsqrpdDblX>wO^u~3r-IB2Wvs`ѡzf/j?hǎsWc+ lRi7~.^ExU?X^XE2G\JD9`KEAХL12#J5jqK~$puT/T?xxc +,zX u5$a6xZ>tPtk^i*Ez(wn'3XχJ`.˼&sHeieop'#u:p>ê 7lxw06c&P|(ci4 @ZԆZ΃14ȟ2* /I4+ʠI>~g̷磋{? ٮ M}U^'] N0SGp_@' Tؚ;IKuPJWщ6[1Xo.g MCC3nعrp"aqg2X91'[dw9+%|BQp@‘=^ESwFZʟL^&PnO{M#g145gݲ]yzR;U 9Lkx9=9Ц3{6p|hP0+50V?du؎%R7^ | @. vH7M{Q?tPn M'=OXLfC1l1Y7|D$&bD +YR>L7OC7V[K浵Kޑ+Z9̱XWĪ!|]*f +_vY7/gT {D-ONX$I=fH ;# D",rt: 5GmcDP $E׌m V-^}-wL sMO9V]bp\hyɊ@KՆ1x%è:`@G {^26 [}mc v! w^&aGGܚ >x%=du%>"$8^DSI_dm Jny l1s@-pGkW:vRXb >USFUzcRGcz Nsfg4(eӖ+0I m`F&;}x)  +)($aϪTj}N].>pY,-ySIn"VsU'%ȪkΝ%u"(e]Rҵؠcħ]%O\p@%.$ˡ:7rV(d t+^+ ;Nv\Ł?- +Fgڀ^"3; d;Nq4xD* LQţ]]W9bQ;]y_;Հ&ħ Q*w뵏seErǹdtq+&HtykV gsdça>Avq/@zu} fN$>z6la祢M$#w򛇬\ +)$ ÆJ5CӮ- x,l)C`;zVKAuu HHF(_C5cum}zz@1OC72mmh!5x[}þ0f 𒡰1O"6. 1|?m$ 0: C4H7ƌ+Ƣ +I2 XK܏H 0`~ +_H0GH P$F+QD_7#K-ƬC {;_HDTwg[w3VVf뜈vTS@fUbVr(Kz֑lvGyl|c H/ejiQEK[ VpDkhcYGc% <:G:@Xiˉ _i{EK͔yΣ1P;JO5\gcLLe\+r9u`^Viŏk\VV܏e\ZdלaFkGJSWM6޲T0xMS:z,ǿ)S-ա׀\ +KG]z옅FD6A$c ldgfO8%&ϐwG૽Wn`Ks4<1eiBwՎvFDpٲMU1b>(6k)93r0VɴpŦ#u_JPQ>Vh]I'6F:0Vzigb4< +EN <$le%qF5;#z c~Vj=3=2С"ԖԈ,Ϭ=K9GR9Ϯo)e_p7 q\|)Q6p̀fH8Jt.}; +[Lh*NʣN9D@VΖ[xIf-,+t&\6W`؄y6UҤ{U_!iAtҖ"*ES),/ɏ㞊\K/L~.ʀͳ:q-DZ;" QAq=8)AThG%:$- MRԭcpqCxnԈ4Rr*[ۏ MΞsmTfb.4KLXC|]vC> |,V묊P_A$ <5GTAvBB%tZMU$ aƹv4߁ +ZC +ry.K *DFE ys)!DՋ:?!IK?X::ϙJ]?ߋsx*%˽jB4!)g/x6:tP9:ĔHNyg28ng BΥ$yB"$Irj=pVzH5J;񖔙 +moJ%=,M$+2A +rFM2'@.*U%%؞{e<[rHsY-Spн7">B/Z= Pw +jʡ⥕] LrHDD%!NS8 ^I>6&'4$GqD~ y0SL|^^t.5^w =I]QMTLF_ɩtx,(! #QރfoˏAZCUfi鸆b=b!RR=h@BcNsIPN%RC)Ti2 #1dҳdOLt&k"-%eO ἮLpN+CX!oӡ<ש3"aQHe&Q b7A<+ ו:A&*5 ̌ORmLn ,UBe(]Z U3 Wx̛%#[se,>AXrtu.J*>K MAA\ p6hĔ=6ڮjXܓAҊ̠Kz-15tUᝓRmQ$2UH_3I ҳuʧidZv6G +rP8xk$˞,e\s޽!: d!T EuN@aJdUNeʆ\M05bLmiGFpJi)pY'DtI1$A JR𴟧C@sӝ1bJdqܛ5Jy yqT +j9xp8V{@X]R @KdmZe ݳ:CrJF @dAF_q>C،c,]H0e?04/y$tBrz$[*d9'o(InC. =ӵk|k=*K}|%u5Xii>$.9hݪ>GӥZVDQu;wT%sDȿݒ$v;ջ\@<Q8Dl#-8fn6Tߌ}C#4sYVU`_Lnh0׊j;-B BѤnu;9+p?҇p޸҈[W_oU3/k% h\1+֦\ +e㐥^׆,4d;|Γ\Q=VScNu6o V#W k٢D?l!q'X5yjQ$ 9ٟ2$d+ + bQ bBU/QX0#j 0T^uUzEIV[ZnaVc6XkS_G89ڰn{EDܱoKU?d)'1U懕gP):M]\O HgT眚@4 + UT&~#bbH^SKB).Tt{kI{DS{~__Mtg}Ø' XΜ4(?Q&JV ,:z ,NNi@_,e<" "<4nq|T~D&;9N@oT`;#Xܩ$W)rX;l裼Cv,hO(Vn>]xB%ZiC79c@&Smc.fkgq]@#JЃ Ld 6&03_cnLc&-Jl!Q>OGq"W& ͦNM'n;TjLdc2?{cKv\e4ڌaIvomt ^Yp˺ᄑ> o>W_]޽^\>ϟϯ/׏_^/ן~BXr{ݻo9I\ endstream endobj 5 0 obj <> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 22 0 obj [21 0 R] endobj 35 0 obj <> endobj xref 0 36 0000000004 65535 f +0000000016 00000 n +0000000159 00000 n +0000016155 00000 n +0000000000 00000 f +0000055236 00000 n +0000000000 00000 f +0000016206 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000055306 00000 n +0000055337 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000020707 00000 n +0000055422 00000 n +0000016539 00000 n +0000021007 00000 n +0000020894 00000 n +0000019609 00000 n +0000020146 00000 n +0000020194 00000 n +0000020778 00000 n +0000020809 00000 n +0000021081 00000 n +0000021255 00000 n +0000022240 00000 n +0000027472 00000 n +0000055447 00000 n +trailer <]>> startxref 55615 %%EOF \ No newline at end of file diff --git a/yara-master/extra/logo.svg b/yara-master/extra/logo.svg new file mode 100644 index 0000000..af8983c --- /dev/null +++ b/yara-master/extra/logo.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + diff --git a/yara-master/extra/old-logo.png b/yara-master/extra/old-logo.png new file mode 100644 index 0000000..9d585e3 Binary files /dev/null and b/yara-master/extra/old-logo.png differ diff --git a/yara-master/extra/old-logo.psd b/yara-master/extra/old-logo.psd new file mode 100644 index 0000000..b3a0432 Binary files /dev/null and b/yara-master/extra/old-logo.psd differ diff --git a/yara-master/libyara/Makefile.am b/yara-master/libyara/Makefile.am new file mode 100644 index 0000000..19318fa --- /dev/null +++ b/yara-master/libyara/Makefile.am @@ -0,0 +1,184 @@ + +MODULES = modules/tests.c +MODULES += modules/pe.c +MODULES += modules/elf.c +MODULES += modules/math.c +MODULES += modules/time.c + +# This isn't really a module, but needs to be compiled with them. +MODULES += modules/pe_utils.c + +if CUCKOO_MODULE +MODULES += modules/cuckoo.c +endif + +if MAGIC_MODULE +MODULES += modules/magic.c +endif + +if HASH_MODULE +MODULES += modules/hash.c +endif + +if DOTNET_MODULE +MODULES += modules/dotnet.c +endif + +if MACHO_MODULE +MODULES += modules/macho.c +endif + +if DEX_MODULE +MODULES += modules/dex.c +endif + +# +# Add your modules here: +# +# MODULES += modules/yourmodule.c +# + +AM_YFLAGS=-d + +AM_CFLAGS=-Wall -Wno-deprecated-declarations -std=gnu99 -I$(srcdir)/include + +if DEBUG +AM_CFLAGS+=-g +endif + +if OPTIMIZATION +AM_CFLAGS+=-O3 +else +AM_CFLAGS+=-O0 +endif + +if ADDRESS_SANITIZER +AM_CFLAGS+=-fsanitize=address +endif + +if GCC +AM_CFLAGS+=-fvisibility=hidden +endif + +ACLOCAL_AMFLAGS=-I m4 + +include_HEADERS = include/yara.h + +yaraincludedir = $(includedir)/yara +yarainclude_HEADERS = \ + include/yara/ahocorasick.h \ + include/yara/arena.h \ + include/yara/atoms.h \ + include/yara/compiler.h \ + include/yara/error.h \ + include/yara/exec.h \ + include/yara/exefiles.h \ + include/yara/filemap.h \ + include/yara/hash.h \ + include/yara/integers.h \ + include/yara/libyara.h \ + include/yara/limits.h \ + include/yara/mem.h \ + include/yara/modules.h \ + include/yara/object.h \ + include/yara/parser.h \ + include/yara/proc.h \ + include/yara/re.h \ + include/yara/rules.h \ + include/yara/scan.h \ + include/yara/scanner.h \ + include/yara/sizedstr.h \ + include/yara/stopwatch.h \ + include/yara/stream.h \ + include/yara/strutils.h \ + include/yara/threading.h \ + include/yara/types.h \ + include/yara/utils.h + +noinst_HEADERS = \ + crypto.h \ + exception.h \ + include/yara/dotnet.h \ + include/yara/elf.h \ + include/yara/endian.h \ + include/yara/globals.h \ + include/yara/hex_lexer.h \ + include/yara/lexer.h \ + include/yara/pe.h \ + include/yara/pe_utils.h \ + include/yara/re_lexer.h \ + modules/module_list + + +lib_LTLIBRARIES = libyara.la + +libyara_la_LDFLAGS = -version-number 3:7:0 + +BUILT_SOURCES = \ + lexer.c \ + hex_lexer.c \ + re_lexer.c \ + grammar.c \ + hex_grammar.c \ + re_grammar.c + +libyara_la_SOURCES = \ + $(MODULES) \ + grammar.y \ + ahocorasick.c \ + arena.c \ + atoms.c \ + compiler.c \ + endian.c \ + exec.c \ + exefiles.c \ + filemap.c \ + hash.c \ + hex_grammar.y \ + hex_lexer.l \ + lexer.l \ + libyara.c \ + mem.c \ + modules.c \ + object.c \ + parser.c \ + proc.c \ + re.c \ + re_grammar.y \ + re_lexer.l \ + rules.c \ + scan.c \ + scanner.c \ + sizedstr.c \ + stopwatch.c \ + strutils.c \ + stream.c \ + threading.c + + +if USE_WINDOWS_PROC +libyara_la_SOURCES += proc/windows.c +endif + +if USE_LINUX_PROC +libyara_la_SOURCES += proc/linux.c +endif + +if USE_FREEBSD_PROC +libyara_la_SOURCES += proc/freebsd.c +endif + +if USE_OPENBSD_PROC +libyara_la_SOURCES += proc/openbsd.c +endif + +if USE_MACH_PROC +libyara_la_SOURCES += proc/mach.c +endif + +if USE_NO_PROC +libyara_la_SOURCES += proc/none.c +endif + +pkgconfigdir = $(libdir)/pkgconfig +nodist_pkgconfig_DATA = yara.pc diff --git a/yara-master/libyara/ahocorasick.c b/yara-master/libyara/ahocorasick.c new file mode 100644 index 0000000..c419b48 --- /dev/null +++ b/yara-master/libyara/ahocorasick.c @@ -0,0 +1,969 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include + + + +typedef struct _QUEUE_NODE +{ + YR_AC_STATE* value; + + struct _QUEUE_NODE* previous; + struct _QUEUE_NODE* next; + +} QUEUE_NODE; + + +typedef struct _QUEUE +{ + QUEUE_NODE* head; + QUEUE_NODE* tail; + +} QUEUE; + + +// +// _yr_ac_queue_push +// +// Pushes a state in a queue. +// +// Args: +// QUEUE* queue - The queue +// YR_AC_STATE* state - The state +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +static int _yr_ac_queue_push( + QUEUE* queue, + YR_AC_STATE* value) +{ + QUEUE_NODE* pushed_node; + + pushed_node = (QUEUE_NODE*) yr_malloc(sizeof(QUEUE_NODE)); + + if (pushed_node == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + pushed_node->previous = queue->tail; + pushed_node->next = NULL; + pushed_node->value = value; + + if (queue->tail != NULL) + queue->tail->next = pushed_node; + else // queue is empty + queue->head = pushed_node; + + queue->tail = pushed_node; + + return ERROR_SUCCESS; +} + + +// +// _yr_ac_queue_pop +// +// Pops a state from a queue. +// +// Args: +// QUEUE* queue - The queue +// +// Returns: +// Pointer to the poped state. +// + +static YR_AC_STATE* _yr_ac_queue_pop( + QUEUE* queue) +{ + YR_AC_STATE* result; + QUEUE_NODE* popped_node; + + if (queue->head == NULL) + return NULL; + + popped_node = queue->head; + queue->head = popped_node->next; + + if (queue->head) + queue->head->previous = NULL; + else // queue is empty + queue->tail = NULL; + + result = popped_node->value; + + yr_free(popped_node); + return result; +} + + +// +// _yr_ac_queue_is_empty +// +// Checks if a queue is empty. +// +// Args: +// QUEUE* queue - The queue +// +// Returns: +// TRUE if queue is empty, FALSE otherwise. +// + +static int _yr_ac_queue_is_empty( + QUEUE* queue) +{ + return queue->head == NULL; +} + + +// +// _yr_ac_next_state +// +// Given an automaton state and an input symbol, returns the new state +// after reading the input symbol. +// +// Args: +// YR_AC_STATE* state - Automaton state +// uint8_t input - Input symbol +// +// Returns: +// Pointer to the next automaton state. +// + +static YR_AC_STATE* _yr_ac_next_state( + YR_AC_STATE* state, + uint8_t input) +{ + YR_AC_STATE* next_state = state->first_child; + + while (next_state != NULL) + { + if (next_state->input == input) + return next_state; + + next_state = next_state->siblings; + } + + return NULL; +} + + +// +// _yr_ac_state_create +// +// Creates a new automaton state, the automaton will transition from +// the given state to the new state after reading the input symbol. +// +// Args: +// YR_AC_STATE* state - Origin state +// uint8_t input - Input symbol +// +// Returns: +// YR_AC_STATE* pointer to the newly allocated state or NULL in case +// of error. + +static YR_AC_STATE* _yr_ac_state_create( + YR_AC_STATE* state, + uint8_t input) +{ + YR_AC_STATE* new_state = (YR_AC_STATE*) yr_malloc(sizeof(YR_AC_STATE)); + + if (new_state == NULL) + return NULL; + + new_state->input = input; + new_state->depth = state->depth + 1; + new_state->matches = NULL; + new_state->failure = NULL; + new_state->t_table_slot = 0; + new_state->first_child = NULL; + new_state->siblings = state->first_child; + state->first_child = new_state; + + return new_state; +} + + +// +// _yr_ac_state_destroy +// + +static int _yr_ac_state_destroy( + YR_AC_STATE* state) +{ + YR_AC_STATE* child_state = state->first_child; + + while (child_state != NULL) + { + YR_AC_STATE* next_child_state = child_state->siblings; + _yr_ac_state_destroy(child_state); + child_state = next_child_state; + } + + yr_free(state); + + return ERROR_SUCCESS; +} + + +// +// _yr_ac_create_failure_links +// +// Create failure links for each automaton state. This function must +// be called after all the strings have been added to the automaton. +// + +static int _yr_ac_create_failure_links( + YR_AC_AUTOMATON* automaton) +{ + YR_AC_STATE* current_state; + YR_AC_STATE* failure_state; + YR_AC_STATE* temp_state; + YR_AC_STATE* state; + YR_AC_STATE* transition_state; + YR_AC_STATE* root_state; + YR_AC_MATCH* match; + + QUEUE queue; + + queue.head = NULL; + queue.tail = NULL; + + root_state = automaton->root; + + // Set the failure link of root state to itself. + root_state->failure = root_state; + + // Push root's children and set their failure link to root. + + state = root_state->first_child; + + while (state != NULL) + { + FAIL_ON_ERROR(_yr_ac_queue_push(&queue, state)); + state->failure = root_state; + state = state->siblings; + } + + // Traverse the trie in BFS order calculating the failure link + // for each state. + + while (!_yr_ac_queue_is_empty(&queue)) + { + current_state = _yr_ac_queue_pop(&queue); + + match = current_state->matches; + + if (match != NULL) + { + while (match->next != NULL) + match = match->next; + + if (match->backtrack > 0) + match->next = root_state->matches; + } + else + { + current_state->matches = root_state->matches; + } + + transition_state = current_state->first_child; + + while (transition_state != NULL) + { + FAIL_ON_ERROR(_yr_ac_queue_push(&queue, transition_state)); + failure_state = current_state->failure; + + while (1) + { + temp_state = _yr_ac_next_state( + failure_state, transition_state->input); + + if (temp_state != NULL) + { + transition_state->failure = temp_state; + + if (transition_state->matches == NULL) + { + transition_state->matches = temp_state->matches; + } + else + { + match = transition_state->matches; + + while (match != NULL && match->next != NULL) + match = match->next; + + match->next = temp_state->matches; + } + + break; + } + else + { + if (failure_state == root_state) + { + transition_state->failure = root_state; + break; + } + else + { + failure_state = failure_state->failure; + } + } + } // while(1) + + transition_state = transition_state->siblings; + } + + } // while(!__yr_ac_queue_is_empty(&queue)) + + return ERROR_SUCCESS; +} + + +// +// _yr_ac_transitions_subset +// +// Returns true if the transitions for state s2 are a subset of the transitions +// for state s1. In other words, if at state s2 input X is accepted, it must be +// accepted in s1 too. +// + +static int _yr_ac_transitions_subset( + YR_AC_STATE* s1, + YR_AC_STATE* s2) +{ + uint8_t set[32]; + + YR_AC_STATE* state = s1->first_child; + + memset(set, 0, 32); + + while (state != NULL) + { + set[state->input / 8] |= 1 << state->input % 8; + state = state->siblings; + } + + state = s2->first_child; + + while (state != NULL) + { + if (!(set[state->input / 8] & 1 << state->input % 8)) + return FALSE; + + state = state->siblings; + } + + return TRUE; +} + + +// +// _yr_ac_optimize_failure_links +// +// Removes unnecessary failure links. +// + +static int _yr_ac_optimize_failure_links( + YR_AC_AUTOMATON* automaton) +{ + QUEUE queue = { NULL, NULL}; + + // Push root's children. + + YR_AC_STATE* root_state = automaton->root; + YR_AC_STATE* state = root_state->first_child; + + while (state != NULL) + { + FAIL_ON_ERROR(_yr_ac_queue_push(&queue, state)); + state = state->siblings; + } + + while (!_yr_ac_queue_is_empty(&queue)) + { + YR_AC_STATE* current_state = _yr_ac_queue_pop(&queue); + + if (current_state->failure != root_state) + { + if (_yr_ac_transitions_subset(current_state, current_state->failure)) + current_state->failure = current_state->failure->failure; + } + + // Push childrens of current_state + state = current_state->first_child; + + while (state != NULL) + { + FAIL_ON_ERROR(_yr_ac_queue_push(&queue, state)); + state = state->siblings; + } + } + + return ERROR_SUCCESS; +} + + +// +// _yr_ac_find_suitable_transition_table_slot +// +// Find a place within the transition table where the transitions for the given +// state can be put. The function first searches for an unused slot to put the +// failure link, then it checks if the slots corresponding to the state +// transitions (wich are at offsets 1 to 256 relative to the failure link ) are +// available too. +// + +static int _yr_ac_find_suitable_transition_table_slot( + YR_AC_AUTOMATON* automaton, + YR_AC_STATE* state, + uint32_t* slot) +{ + YR_AC_STATE* child_state; + + uint32_t i = automaton->t_table_unused_candidate; + + int first_unused = TRUE; + int found = FALSE; + + while (!found) + { + // Check if there is enough room in the table to hold 257 items + // (1 failure link + 256 transitions) starting at offset i. If there's + // no room double the table size. + + if (automaton->tables_size - i < 257) + { + size_t t_bytes_size = automaton->tables_size * + sizeof(YR_AC_TRANSITION); + + size_t m_bytes_size = automaton->tables_size * + sizeof(YR_AC_MATCH_TABLE_ENTRY); + + automaton->t_table = (YR_AC_TRANSITION_TABLE) yr_realloc( + automaton->t_table, t_bytes_size * 2); + + automaton->m_table = (YR_AC_MATCH_TABLE) yr_realloc( + automaton->m_table, m_bytes_size * 2); + + if (automaton->t_table == NULL || automaton->m_table == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + memset((uint8_t*) automaton->t_table + t_bytes_size, 0, t_bytes_size); + memset((uint8_t*) automaton->m_table + m_bytes_size, 0, m_bytes_size); + + automaton->tables_size *= 2; + } + + if (YR_AC_UNUSED_TRANSITION_SLOT(automaton->t_table[i])) + { + // A unused slot in the table has been found and could be a potential + // candidate. Let's check if table slots for the transitions are + // unused too. + + found = TRUE; + child_state = state->first_child; + + while (child_state != NULL) + { + if (YR_AC_USED_TRANSITION_SLOT( + automaton->t_table[child_state->input + i + 1])) + { + found = FALSE; + break; + } + + child_state = child_state->siblings; + } + + // If this is the first unused entry we found, use it as the first + // candidate in the next call to this function. + + if (first_unused) + { + automaton->t_table_unused_candidate = found ? i + 1 : i; + first_unused = FALSE; + } + + if (found) + *slot = i; + } + + i++; + } + + return ERROR_SUCCESS; +} + +// +// _yr_ac_build_transition_table +// +// Builds the transition table for the automaton. The transition table (T) is a +// large array of 64-bits integers. Each state in the automaton is represented +// by an offset S within the array. The integer stored in T[S] is the failure +// link for state S, it contains the offset for the next state when no valid +// transition exists for the next input byte. +// +// At position T[S+1+B] (where B is a byte) we can find the transition (if any) +// that must be followed from state S if the next input is B. The value in +// T[S+1+B] contains the offset for next state or 0. The 0 means that no +// valid transition exists from state S when next input is B, and the failure +// link must be used instead. +// +// The transition table for state S starts at T[S] and spans the next 257 +// slots in the array (1 for the failure link and 256 for all the possible +// transitions). But many of those slots are for invalid transitions, so +// the transitions for multiple states can be interleaved as long as they don't +// collide. For example, instead of having this transition table with state S1 +// and S2 separated by a large number of slots: +// +// S1 S2 +// +------+------+------+------+-- ~ --+------+------+------+-- ~ --+ +// | FLS1 | X | - | - | - | Y | FLS2 | Z | - | +// +------+------+------+------+-- ~ --+------+------+------+-- ~ --+ +// +// We can interleave the transitions for states S1 and S2 and get this other +// transition table, which is more compact: +// +// S1 S2 +// +------+------+------+------+-- ~ --+------+ +// | FLS1 | X | FLS2 | Z | - | Y | +// +------+------+------+------+-- ~ --+------+ +// +// And how do we know that transition Z belongs to state S2 and not S1? Or that +// transition Y belongs to S1 and not S2? Because each slot of the array not +// only contains the offset for the state where the transition points to, it +// also contains the offset of the transition relative to its owner state. So, +// the value for the owner offset would be 1 for transitions X, because X +// belongs to state S1 and it's located 1 position away from S1. The same occurs +// for Z, it belongs to S2 and it's located one position away from S2 so its +// owner offset is 1. If we are in S1 and next byte is 2, we are going to read +// the transition at T[S1+1+2] which is Z. But we know that transition Z is not +// a valid transition for state S1 because the owner offset for Z is 1 not 3. +// +// A more detailed description can be found in: http://goo.gl/lE6zG + + +static int _yr_ac_build_transition_table( + YR_AC_AUTOMATON* automaton) +{ + YR_AC_STATE* state; + YR_AC_STATE* child_state; + YR_AC_STATE* root_state = automaton->root; + + uint32_t slot; + + QUEUE queue = { NULL, NULL}; + + automaton->tables_size = 1024; + + automaton->t_table = (YR_AC_TRANSITION_TABLE) yr_malloc( + automaton->tables_size * sizeof(YR_AC_TRANSITION)); + + automaton->m_table = (YR_AC_MATCH_TABLE) yr_malloc( + automaton->tables_size * sizeof(YR_AC_MATCH_TABLE_ENTRY)); + + if (automaton->t_table == NULL || automaton->m_table == NULL) + { + yr_free(automaton->t_table); + yr_free(automaton->m_table); + + return ERROR_INSUFFICIENT_MEMORY; + } + + memset(automaton->t_table, 0, + automaton->tables_size * sizeof(YR_AC_TRANSITION)); + + memset(automaton->m_table, 0, + automaton->tables_size * sizeof(YR_AC_MATCH_TABLE_ENTRY)); + + automaton->t_table[0] = YR_AC_MAKE_TRANSITION(0, 0, YR_AC_USED_FLAG); + automaton->m_table[0].match = root_state->matches; + + // Index 0 is for root node. Unused indexes start at 1. + automaton->t_table_unused_candidate = 1; + + child_state = root_state->first_child; + + while (child_state != NULL) + { + child_state->t_table_slot = child_state->input + 1; + automaton->t_table[child_state->input + 1] = YR_AC_MAKE_TRANSITION( + 0, child_state->input + 1, YR_AC_USED_FLAG); + + FAIL_ON_ERROR(_yr_ac_queue_push(&queue, child_state)); + child_state = child_state->siblings; + } + + while (!_yr_ac_queue_is_empty(&queue)) + { + state = _yr_ac_queue_pop(&queue); + + FAIL_ON_ERROR(_yr_ac_find_suitable_transition_table_slot( + automaton, + state, + &slot)); + + automaton->t_table[state->t_table_slot] |= ((uint64_t) slot << 32); + + state->t_table_slot = slot; + + automaton->t_table[slot] = YR_AC_MAKE_TRANSITION( + state->failure->t_table_slot, 0, YR_AC_USED_FLAG); + + automaton->m_table[slot].match = state->matches; + + // Push childrens of current_state + + child_state = state->first_child; + + while (child_state != NULL) + { + child_state->t_table_slot = slot + child_state->input + 1; + automaton->t_table[child_state->t_table_slot] = YR_AC_MAKE_TRANSITION( + 0, child_state->input + 1, YR_AC_USED_FLAG); + + FAIL_ON_ERROR(_yr_ac_queue_push(&queue, child_state)); + + child_state = child_state->siblings; + } + } + + return ERROR_SUCCESS; +} + + +// +// _yr_ac_print_automaton_state +// +// Prints automaton state for debug purposes. This function is invoked by +// yr_ac_print_automaton, is not intended to be used stand-alone. +// + +static void _yr_ac_print_automaton_state( + YR_AC_STATE* state) +{ + int i; + int child_count; + + YR_AC_MATCH* match; + YR_AC_STATE* child_state; + + for (i = 0; i < state->depth; i++) + printf(" "); + + child_state = state->first_child; + child_count = 0; + + while(child_state != NULL) + { + child_count++; + child_state = child_state->siblings; + } + + printf("%p childs:%d depth:%d failure:%p", + state, child_count, state->depth, state->failure); + + match = state->matches; + + while (match != NULL) + { + printf("\n"); + + for (i = 0; i < state->depth + 1; i++) + printf(" "); + + printf("%s = ", match->string->identifier); + + if (STRING_IS_HEX(match->string)) + { + printf("{ "); + + for (i = 0; i < yr_min(match->string->length, 10); i++) + printf("%02x ", match->string->string[i]); + + printf("}"); + } + else if (STRING_IS_REGEXP(match->string)) + { + printf("/"); + + for (i = 0; i < yr_min(match->string->length, 10); i++) + printf("%c", match->string->string[i]); + + printf("/"); + } + else + { + printf("\""); + + for (i = 0; i < yr_min(match->string->length, 10); i++) + printf("%c", match->string->string[i]); + + printf("\""); + } + + match = match->next; + } + + printf("\n"); + + child_state = state->first_child; + + while(child_state != NULL) + { + _yr_ac_print_automaton_state(child_state); + child_state = child_state->siblings; + } +} + + +// +// yr_ac_automaton_create +// +// Creates a new automaton +// + +int yr_ac_automaton_create( + YR_AC_AUTOMATON** automaton) +{ + YR_AC_AUTOMATON* new_automaton; + YR_AC_STATE* root_state; + + new_automaton = (YR_AC_AUTOMATON*) yr_malloc(sizeof(YR_AC_AUTOMATON)); + root_state = (YR_AC_STATE*) yr_malloc(sizeof(YR_AC_STATE)); + + if (new_automaton == NULL || root_state == NULL) + { + yr_free(new_automaton); + yr_free(root_state); + + return ERROR_INSUFFICIENT_MEMORY; + } + + root_state->depth = 0; + root_state->matches = NULL; + root_state->failure = NULL; + root_state->first_child = NULL; + root_state->siblings = NULL; + root_state->t_table_slot = 0; + + new_automaton->root = root_state; + new_automaton->m_table = NULL; + new_automaton->t_table = NULL; + new_automaton->tables_size = 0; + + *automaton = new_automaton; + + return ERROR_SUCCESS; +} + + +// +// yr_ac_automaton_destroy +// +// Destroys automaton +// + +int yr_ac_automaton_destroy( + YR_AC_AUTOMATON* automaton) +{ + _yr_ac_state_destroy(automaton->root); + + yr_free(automaton->t_table); + yr_free(automaton->m_table); + yr_free(automaton); + + return ERROR_SUCCESS; +} + + +// +// yr_ac_add_string +// +// Adds a string to the automaton. This function is invoked once for each +// string defined in the rules. +// + +int yr_ac_add_string( + YR_AC_AUTOMATON* automaton, + YR_STRING* string, + YR_ATOM_LIST_ITEM* atom, + YR_ARENA* matches_arena) +{ + int result = ERROR_SUCCESS; + int i; + + YR_AC_STATE* state; + YR_AC_STATE* next_state; + YR_AC_MATCH* new_match; + + // For each atom create the states in the automaton. + + while (atom != NULL) + { + state = automaton->root; + + for (i = 0; i < atom->atom_length; i++) + { + next_state = _yr_ac_next_state(state, atom->atom[i]); + + if (next_state == NULL) + { + next_state = _yr_ac_state_create(state, atom->atom[i]); + + if (next_state == NULL) + return ERROR_INSUFFICIENT_MEMORY; + } + + state = next_state; + } + + result = yr_arena_allocate_struct( + matches_arena, + sizeof(YR_AC_MATCH), + (void**) &new_match, + offsetof(YR_AC_MATCH, string), + offsetof(YR_AC_MATCH, forward_code), + offsetof(YR_AC_MATCH, backward_code), + offsetof(YR_AC_MATCH, next), + EOL); + + if (result == ERROR_SUCCESS) + { + new_match->backtrack = state->depth + atom->backtrack; + new_match->string = string; + new_match->forward_code = atom->forward_code; + new_match->backward_code = atom->backward_code; + new_match->next = state->matches; + state->matches = new_match; + } + else + { + break; + } + + atom = atom->next; + } + + return result; +} + + +// +// yr_ac_compile +// + +int yr_ac_compile( + YR_AC_AUTOMATON* automaton, + YR_ARENA* arena, + YR_AC_TABLES* tables) +{ + uint32_t i; + + FAIL_ON_ERROR(_yr_ac_create_failure_links(automaton)); + FAIL_ON_ERROR(_yr_ac_optimize_failure_links(automaton)); + FAIL_ON_ERROR(_yr_ac_build_transition_table(automaton)); + + FAIL_ON_ERROR(yr_arena_reserve_memory( + arena, + automaton->tables_size * sizeof(tables->transitions[0]) + + automaton->tables_size * sizeof(tables->matches[0]))); + + FAIL_ON_ERROR(yr_arena_write_data( + arena, + automaton->t_table, + sizeof(YR_AC_TRANSITION), + (void**) &tables->transitions)); + + for (i = 1; i < automaton->tables_size; i++) + { + FAIL_ON_ERROR(yr_arena_write_data( + arena, + automaton->t_table + i, + sizeof(YR_AC_TRANSITION), + NULL)); + } + + FAIL_ON_ERROR(yr_arena_write_data( + arena, + automaton->m_table, + sizeof(YR_AC_MATCH_TABLE_ENTRY), + (void**) &tables->matches)); + + FAIL_ON_ERROR(yr_arena_make_ptr_relocatable( + arena, + tables->matches, + offsetof(YR_AC_MATCH_TABLE_ENTRY, match), + EOL)); + + for (i = 1; i < automaton->tables_size; i++) + { + void* ptr; + + FAIL_ON_ERROR(yr_arena_write_data( + arena, + automaton->m_table + i, + sizeof(YR_AC_MATCH_TABLE_ENTRY), + (void**) &ptr)); + + FAIL_ON_ERROR(yr_arena_make_ptr_relocatable( + arena, + ptr, + offsetof(YR_AC_MATCH_TABLE_ENTRY, match), + EOL)); + } + + return ERROR_SUCCESS; +} + + +// +// yr_ac_print_automaton +// +// Prints automaton for debug purposes. +// + +void yr_ac_print_automaton(YR_AC_AUTOMATON* automaton) +{ + printf("-------------------------------------------------------\n"); + _yr_ac_print_automaton_state(automaton->root); + printf("-------------------------------------------------------\n"); +} diff --git a/yara-master/libyara/arena.c b/yara-master/libyara/arena.c new file mode 100644 index 0000000..55134c7 --- /dev/null +++ b/yara-master/libyara/arena.c @@ -0,0 +1,1110 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +/* + +This module implements a structure I've called "arena". An arena is a data +container composed of a set of pages. The arena grows automatically when +needed by adding new pages to hold new data. Arenas can be saved and loaded +from files. + +*/ + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +#pragma pack(push) +#pragma pack(1) + +typedef struct _ARENA_FILE_HEADER +{ + char magic[4]; + uint32_t size; + uint32_t version; + +} ARENA_FILE_HEADER; + +#pragma pack(pop) + + +#define free_space(page) \ + ((page)->size - (page)->used) + + +// +// _yr_arena_new_page +// +// Creates a new arena page of a given size +// +// Args: +// size_t size - Size of the page +// +// Returns: +// A pointer to the newly created YR_ARENA_PAGE structure +// + +static YR_ARENA_PAGE* _yr_arena_new_page( + size_t size) +{ + YR_ARENA_PAGE* new_page; + + new_page = (YR_ARENA_PAGE*) yr_malloc(sizeof(YR_ARENA_PAGE)); + + if (new_page == NULL) + return NULL; + + new_page->address = (uint8_t*) yr_malloc(size); + + if (new_page->address == NULL) + { + yr_free(new_page); + return NULL; + } + + new_page->size = size; + new_page->used = 0; + new_page->next = NULL; + new_page->prev = NULL; + new_page->reloc_list_head = NULL; + new_page->reloc_list_tail = NULL; + + return new_page; +} + + +// +// _yr_arena_page_for_address +// +// Returns the page within the arena where an address reside. +// +// Args: +// YR_ARENA* arena - Pointer to the arena +// void* address - Address to be located +// +// Returns: +// A pointer the corresponding YR_ARENA_PAGE structure where the address +// resides. +// + +static YR_ARENA_PAGE* _yr_arena_page_for_address( + YR_ARENA* arena, + void* address) +{ + YR_ARENA_PAGE* page; + + // Most of the times this function is called with an address within + // the current page, let's check the current page first to avoid + // looping through the page list. + + page = arena->current_page; + + if (page != NULL && + (uint8_t*) address >= page->address && + (uint8_t*) address < page->address + page->used) + return page; + + page = arena->page_list_head; + + while (page != NULL) + { + if ((uint8_t*) address >= page->address && + (uint8_t*) address < page->address + page->used) + return page; + + page = page->next; + } + + return NULL; +} + + +// +// _yr_arena_make_ptr_relocatable +// +// Tells the arena that certain addresses contains a relocatable pointer. +// +// Args: +// YR_ARENA* arena - Pointer the arena +// void* address - Base address +// va_list offsets - List of offsets relative to base address +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +static int _yr_arena_make_ptr_relocatable( + YR_ARENA* arena, + void* base, + va_list offsets) +{ + YR_RELOC* reloc; + YR_ARENA_PAGE* page; + + size_t offset; + size_t base_offset; + + int result = ERROR_SUCCESS; + + // If the arena must be relocatable. + assert(arena->flags & ARENA_FLAGS_RELOCATABLE); + + page = _yr_arena_page_for_address(arena, base); + + assert(page != NULL); + + base_offset = (uint8_t*) base - page->address; + offset = va_arg(offsets, size_t); + + while (offset != -1) + { + assert(page->used >= sizeof(int64_t)); + assert(base_offset + offset <= page->used - sizeof(int64_t)); + + reloc = (YR_RELOC*) yr_malloc(sizeof(YR_RELOC)); + + if (reloc == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + reloc->offset = (uint32_t) (base_offset + offset); + reloc->next = NULL; + + if (page->reloc_list_head == NULL) + page->reloc_list_head = reloc; + + if (page->reloc_list_tail != NULL) + page->reloc_list_tail->next = reloc; + + page->reloc_list_tail = reloc; + offset = va_arg(offsets, size_t); + } + + return result; +} + + +// +// yr_arena_create +// +// Creates a new arena. +// +// Args: +// size_t initial_size - Initial size +// int flags - Flags +// YR_ARENA** arena - Address where a pointer to the new arena will be +// written to. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_create( + size_t initial_size, + int flags, + YR_ARENA** arena) +{ + YR_ARENA* new_arena; + YR_ARENA_PAGE* new_page; + + *arena = NULL; + new_arena = (YR_ARENA*) yr_malloc(sizeof(YR_ARENA)); + + if (new_arena == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + new_page = _yr_arena_new_page(initial_size); + + if (new_page == NULL) + { + yr_free(new_arena); + return ERROR_INSUFFICIENT_MEMORY; + } + + new_arena->page_list_head = new_page; + new_arena->current_page = new_page; + new_arena->flags = flags | ARENA_FLAGS_COALESCED; + + *arena = new_arena; + return ERROR_SUCCESS; +} + + +// +// yr_arena_destroy +// +// Destroys an arena releasing its resource. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +void yr_arena_destroy( + YR_ARENA* arena) +{ + YR_RELOC* reloc; + YR_RELOC* next_reloc; + YR_ARENA_PAGE* page; + YR_ARENA_PAGE* next_page; + + if (arena == NULL) + return; + + page = arena->page_list_head; + + while(page != NULL) + { + next_page = page->next; + reloc = page->reloc_list_head; + + while (reloc != NULL) + { + next_reloc = reloc->next; + yr_free(reloc); + reloc = next_reloc; + } + + yr_free(page->address); + yr_free(page); + + page = next_page; + } + + yr_free(arena); +} + + +// +// yr_arena_base_address +// +// Returns the base address for the arena. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// +// Returns: +// A pointer to the arena's data. NULL if no data has been written to +// the arena yet. +// + +void* yr_arena_base_address( + YR_ARENA* arena) +{ + if (arena->page_list_head->used == 0) + return NULL; + + return arena->page_list_head->address; +} + + +// +// yr_arena_next_address +// +// Given an address and an offset, returns the address where +// address + offset resides. The arena is a collection of non-contiguous +// regions of memory (pages), if address is pointing at the end of a page, +// address + offset could cross the page boundary and point at somewhere +// within the next page, this function handles these situations. It works +// also with negative offsets. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// void* address - Base address. +// int offset - Offset. +// +// Returns: +// A pointer +// + + +void* yr_arena_next_address( + YR_ARENA* arena, + void* address, + size_t offset) +{ + YR_ARENA_PAGE* page; + + page = _yr_arena_page_for_address(arena, address); + + assert(page != NULL); + + if ((uint8_t*) address + offset >= page->address && + (uint8_t*) address + offset < page->address + page->used) + { + return (uint8_t*) address + offset; + } + + if (offset > 0) + { + offset -= page->address + page->used - (uint8_t*) address; + page = page->next; + + while (page != NULL) + { + if (offset < page->used) + return page->address + offset; + + offset -= page->used; + page = page->next; + } + } + else + { + offset += page->used; + page = page->prev; + + while (page != NULL) + { + if (offset < page->used) + return page->address + page->used + offset; + + offset += page->used; + page = page->prev; + } + } + + return NULL; +} + + +// +// yr_arena_coalesce +// +// Coalesce the arena into a single page. This is a required step before +// saving the arena to a file. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_coalesce( + YR_ARENA* arena) +{ + YR_ARENA_PAGE* page; + YR_ARENA_PAGE* big_page; + YR_ARENA_PAGE* next_page; + YR_RELOC* reloc; + + uint8_t** reloc_address; + uint8_t* reloc_target; + size_t total_size = 0; + + page = arena->page_list_head; + + while(page != NULL) + { + total_size += page->used; + page = page->next; + } + + // Create a new page that will contain the entire arena. + big_page = _yr_arena_new_page(total_size); + + if (big_page == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + // Copy data from current pages to the big page and adjust relocs. + page = arena->page_list_head; + + while (page != NULL) + { + page->new_address = big_page->address + big_page->used; + memcpy(page->new_address, page->address, page->used); + + reloc = page->reloc_list_head; + + while (reloc != NULL) + { + reloc->offset += (uint32_t) big_page->used; + reloc = reloc->next; + } + + if (big_page->reloc_list_head == NULL) + big_page->reloc_list_head = page->reloc_list_head; + + if (big_page->reloc_list_tail != NULL) + big_page->reloc_list_tail->next = page->reloc_list_head; + + if (page->reloc_list_tail != NULL) + big_page->reloc_list_tail = page->reloc_list_tail; + + big_page->used += page->used; + page = page->next; + } + + // Relocate pointers. + reloc = big_page->reloc_list_head; + + while (reloc != NULL) + { + reloc_address = (uint8_t**) (big_page->address + reloc->offset); + reloc_target = *reloc_address; + + if (reloc_target != NULL) + { + page = _yr_arena_page_for_address(arena, reloc_target); + assert(page != NULL); + *reloc_address = page->new_address + (reloc_target - page->address); + } + + reloc = reloc->next; + } + + // Release current pages. + page = arena->page_list_head; + + while(page != NULL) + { + next_page = page->next; + yr_free(page->address); + yr_free(page); + page = next_page; + } + + arena->page_list_head = big_page; + arena->current_page = big_page; + arena->flags |= ARENA_FLAGS_COALESCED; + + return ERROR_SUCCESS; +} + + +// +// yr_arena_reserve_memory +// +// Ensures that the arena have enough contiguous memory for future allocations. +// if the available space in the current page is lower than "size", a new page +// is allocated. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// size_t size - Size of the region to be reserved. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + + +int yr_arena_reserve_memory( + YR_ARENA* arena, + size_t size) +{ + YR_ARENA_PAGE* new_page; + size_t new_page_size; + uint8_t* new_page_address; + + if (size > free_space(arena->current_page)) + { + // Requested space is bigger than current page's empty space, + // lets calculate the size for a new page. + + new_page_size = arena->current_page->size * 2; + + while (new_page_size < size) + new_page_size *= 2; + + if (arena->current_page->used == 0) + { + // Current page is not used at all, it can be reallocated. + + new_page_address = (uint8_t*) yr_realloc( + arena->current_page->address, + new_page_size); + + if (new_page_address == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + arena->current_page->address = new_page_address; + arena->current_page->size = new_page_size; + } + else + { + new_page = _yr_arena_new_page(new_page_size); + + if (new_page == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + new_page->prev = arena->current_page; + arena->current_page->next = new_page; + arena->current_page = new_page; + arena->flags &= ~ARENA_FLAGS_COALESCED; + } + } + + return ERROR_SUCCESS; +} + + +// +// yr_arena_allocate_memory +// +// Allocates memory within the arena. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// size_t size - Size of the region to be allocated. +// void** allocated_memory - Address of a pointer to newly allocated +// region. +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_allocate_memory( + YR_ARENA* arena, + size_t size, + void** allocated_memory) +{ + FAIL_ON_ERROR(yr_arena_reserve_memory(arena, size)); + + *allocated_memory = arena->current_page->address + \ + arena->current_page->used; + + arena->current_page->used += size; + + return ERROR_SUCCESS; +} + + +// +// yr_arena_allocate_struct +// +// Allocates a structure within the arena. This function is similar to +// yr_arena_allocate_memory but additionally receives a variable-length +// list of offsets within the structure where pointers reside. This allows +// the arena to keep track of pointers that must be adjusted when memory +// is relocated. This is an example on how to invoke this function: +// +// yr_arena_allocate_struct( +// arena, +// sizeof(MY_STRUCTURE), +// (void**) &my_structure_ptr, +// offsetof(MY_STRUCTURE, field_1), +// offsetof(MY_STRUCTURE, field_2), +// .. +// offsetof(MY_STRUCTURE, field_N), +// EOL); +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// size_t size - Size of the region to be allocated. +// void** allocated_memory - Address of a pointer to newly allocated +// region. +// ... - Variable number of offsets relative to the +// beginning of the struct. Offsets are of type +// size_t. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_allocate_struct( + YR_ARENA* arena, + size_t size, + void** allocated_memory, + ...) +{ + int result; + + va_list offsets; + va_start(offsets, allocated_memory); + + result = yr_arena_allocate_memory(arena, size, allocated_memory); + + if (result == ERROR_SUCCESS && arena->flags & ARENA_FLAGS_RELOCATABLE) + result = _yr_arena_make_ptr_relocatable(arena, *allocated_memory, offsets); + + va_end(offsets); + + if (result == ERROR_SUCCESS) + memset(*allocated_memory, 0, size); + + return result; +} + + +// +// yr_arena_make_ptr_relocatable +// +// Tells the arena that certain addresses contains a relocatable pointer. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// void* base - Address within the arena. +// ... - Variable number of size_t arguments with offsets +// relative to base. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_make_ptr_relocatable( + YR_ARENA* arena, + void* base, + ...) +{ + int result; + + va_list offsets; + va_start(offsets, base); + + result = _yr_arena_make_ptr_relocatable(arena, base, offsets); + + va_end(offsets); + + return result; +} + + +// +// yr_arena_write_data +// +// Writes data to the arena. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// void* data - Pointer to data to be written. +// size_t size - Size of data. +// void** written_data - Address where a pointer to the written data will +// be returned. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_write_data( + YR_ARENA* arena, + const void* data, + size_t size, + void** written_data) +{ + void* output; + int result; + + if (size > free_space(arena->current_page)) + { + result = yr_arena_allocate_memory(arena, size, &output); + + if (result != ERROR_SUCCESS) + return result; + } + else + { + output = arena->current_page->address + arena->current_page->used; + arena->current_page->used += size; + } + + memcpy(output, data, size); + + if (written_data != NULL) + *written_data = output; + + return ERROR_SUCCESS; +} + + +// +// yr_arena_write_string +// +// Writes string to the arena. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// const char* string - Pointer to string to be written. +// char** written_string - Address where a pointer to the written data will +// be returned. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_write_string( + YR_ARENA* arena, + const char* string, + char** written_string) +{ + return yr_arena_write_data( + arena, + (void*) string, + strlen(string) + 1, + (void**) written_string); +} + + +// +// yr_arena_append +// +// Appends source_arena to target_arena. This operation destroys source_arena, +// after returning any pointer to source_arena is no longer valid. The data +// from source_arena is guaranteed to be aligned to a 16 bytes boundary when +// written to the source_arena +// +// Args: +// YR_ARENA* target_arena - Pointer to target the arena. +// YR_ARENA* source_arena - Pointer to source arena. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_append( + YR_ARENA* target_arena, + YR_ARENA* source_arena) +{ + uint8_t padding_data[15]; + size_t padding_size = 16 - target_arena->current_page->used % 16; + + if (padding_size < 16) + { + memset(&padding_data, 0xCC, padding_size); + + FAIL_ON_ERROR(yr_arena_write_data( + target_arena, + padding_data, + padding_size, + NULL)); + } + + target_arena->current_page->next = source_arena->page_list_head; + source_arena->page_list_head->prev = target_arena->current_page; + target_arena->current_page = source_arena->current_page; + + yr_free(source_arena); + + return ERROR_SUCCESS; +} + + +// +// yr_arena_duplicate +// +// Duplicates the arena, making an exact copy. This function requires the +// arena to be coalesced. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// YR_ARENA** duplicated - Address where a pointer to the new arena arena +// will be returned. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_duplicate( + YR_ARENA* arena, + YR_ARENA** duplicated) +{ + YR_RELOC* reloc; + YR_RELOC* new_reloc; + YR_ARENA_PAGE* page; + YR_ARENA_PAGE* new_page; + YR_ARENA* new_arena; + uint8_t** reloc_address; + uint8_t* reloc_target; + + // Arena must be coalesced and relocatable in order to be duplicated. + assert(arena->flags & ARENA_FLAGS_COALESCED); + assert(arena->flags & ARENA_FLAGS_RELOCATABLE); + + page = arena->page_list_head; + + FAIL_ON_ERROR(yr_arena_create(page->size, arena->flags, &new_arena)); + + new_page = new_arena->current_page; + new_page->used = page->used; + + memcpy(new_page->address, page->address, page->size); + + reloc = page->reloc_list_head; + + while (reloc != NULL) + { + new_reloc = (YR_RELOC*) yr_malloc(sizeof(YR_RELOC)); + + if (new_reloc == NULL) + { + yr_arena_destroy(new_arena); + return ERROR_INSUFFICIENT_MEMORY; + } + + new_reloc->offset = reloc->offset; + new_reloc->next = NULL; + + if (new_page->reloc_list_head == NULL) + new_page->reloc_list_head = new_reloc; + + if (new_page->reloc_list_tail != NULL) + new_page->reloc_list_tail->next = new_reloc; + + new_page->reloc_list_tail = new_reloc; + + reloc_address = (uint8_t**) (new_page->address + new_reloc->offset); + reloc_target = *reloc_address; + + if (reloc_target != NULL) + { + assert(reloc_target >= page->address); + assert(reloc_target < page->address + page->used); + + *reloc_address = reloc_target - \ + page->address + \ + new_page->address; + } + + reloc = reloc->next; + } + + *duplicated = new_arena; + + return ERROR_SUCCESS; +} + + +// +// yr_arena_load_stream +// +// Loads an arena from a stream. The resulting arena is not relocatable, which +// implies that the arena can't be duplicated with yr_arena_duplicate nor +// saved with yr_arena_save_stream. +// +// Args: +// YR_STREAM* stream - Pointer to stream object +// YR_ARENA** - Address where a pointer to the loaded arena +// will be returned +// +// Returns: +// ERROR_SUCCESS if successful, appropriate error code otherwise. +// + +int yr_arena_load_stream( + YR_STREAM* stream, + YR_ARENA** arena) +{ + YR_ARENA_PAGE* page; + YR_ARENA* new_arena; + ARENA_FILE_HEADER header; + + uint32_t real_hash; + uint32_t file_hash; + uint32_t reloc_offset; + uint8_t** reloc_address; + uint8_t* reloc_target; + + int result; + + if (yr_stream_read(&header, sizeof(header), 1, stream) != 1) + return ERROR_INVALID_FILE; + + if (header.magic[0] != 'Y' || + header.magic[1] != 'A' || + header.magic[2] != 'R' || + header.magic[3] != 'A') + { + return ERROR_INVALID_FILE; + } + + if (header.size < 2048) // compiled rules are always larger than 2KB + return ERROR_CORRUPT_FILE; + + if (header.version != ARENA_FILE_VERSION) + return ERROR_UNSUPPORTED_FILE_VERSION; + + real_hash = yr_hash(0, &header, sizeof(header)); + + result = yr_arena_create(header.size, ARENA_FLAGS_COALESCED, &new_arena); + + if (result != ERROR_SUCCESS) + return result; + + page = new_arena->current_page; + + if (yr_stream_read(page->address, header.size, 1, stream) != 1) + { + yr_arena_destroy(new_arena); + return ERROR_CORRUPT_FILE; + } + + page->used = header.size; + + real_hash = yr_hash(real_hash, page->address, page->used); + + if (yr_stream_read(&reloc_offset, sizeof(reloc_offset), 1, stream) != 1) + { + yr_arena_destroy(new_arena); + return ERROR_CORRUPT_FILE; + } + + while (reloc_offset != 0xFFFFFFFF) + { + if (reloc_offset > header.size - sizeof(uint8_t*)) + { + yr_arena_destroy(new_arena); + return ERROR_CORRUPT_FILE; + } + + //yr_arena_make_ptr_relocatable(new_arena, page->address, reloc_offset, EOL); + + reloc_address = (uint8_t**) (page->address + reloc_offset); + reloc_target = *reloc_address; + + if (reloc_target != (uint8_t*) (size_t) 0xFFFABADA) + *reloc_address += (size_t) page->address; + else + *reloc_address = 0; + + if (yr_stream_read(&reloc_offset, sizeof(reloc_offset), 1, stream) != 1) + { + yr_arena_destroy(new_arena); + return ERROR_CORRUPT_FILE; + } + } + + if (yr_stream_read(&file_hash, sizeof(file_hash), 1, stream) != 1) + { + yr_arena_destroy(new_arena); + return ERROR_CORRUPT_FILE; + } + + if (file_hash != real_hash) + { + yr_arena_destroy(new_arena); + return ERROR_CORRUPT_FILE; + } + + *arena = new_arena; + + return ERROR_SUCCESS; +} + + +// +// yr_arena_save_stream +// +// Saves the arena into a stream. If the file exists its overwritten. This +// function requires the arena to be coalesced. +// +// Args: +// YR_ARENA* arena - Pointer to the arena. +// YR_STREAM* stream - Pointer to stream object. +// +// Returns: +// ERROR_SUCCESS if succeed or the corresponding error code otherwise. +// + +int yr_arena_save_stream( + YR_ARENA* arena, + YR_STREAM* stream) +{ + YR_ARENA_PAGE* page; + YR_RELOC* reloc; + ARENA_FILE_HEADER header; + + uint32_t end_marker = 0xFFFFFFFF; + uint32_t file_hash; + uint8_t** reloc_address; + uint8_t* reloc_target; + + // Only coalesced and relocatable arenas can be saved. + assert(arena->flags & ARENA_FLAGS_COALESCED); + assert(arena->flags & ARENA_FLAGS_RELOCATABLE); + + page = arena->page_list_head; + reloc = page->reloc_list_head; + + // Convert pointers to offsets before saving. + while (reloc != NULL) + { + reloc_address = (uint8_t**) (page->address + reloc->offset); + reloc_target = *reloc_address; + + if (reloc_target != NULL) + { + assert(reloc_target >= page->address); + assert(reloc_target < page->address + page->used); + *reloc_address = (uint8_t*) (*reloc_address - page->address); + } + else + { + *reloc_address = (uint8_t*) (size_t) 0xFFFABADA; + } + + reloc = reloc->next; + } + + assert(page->size < 0x80000000); // 2GB + + header.magic[0] = 'Y'; + header.magic[1] = 'A'; + header.magic[2] = 'R'; + header.magic[3] = 'A'; + header.size = (int32_t) page->size; + header.version = ARENA_FILE_VERSION; + + yr_stream_write(&header, sizeof(header), 1, stream); + yr_stream_write(page->address, header.size, 1, stream); + + file_hash = yr_hash(0, &header, sizeof(header)); + file_hash = yr_hash(file_hash, page->address, page->used); + + reloc = page->reloc_list_head; + + // Convert offsets back to pointers. + while (reloc != NULL) + { + yr_stream_write(&reloc->offset, sizeof(reloc->offset), 1, stream); + + reloc_address = (uint8_t**) (page->address + reloc->offset); + reloc_target = *reloc_address; + + if (reloc_target != (void*) (size_t) 0xFFFABADA) + *reloc_address += (size_t) page->address; + else + *reloc_address = 0; + + reloc = reloc->next; + } + + yr_stream_write(&end_marker, sizeof(end_marker), 1, stream); + yr_stream_write(&file_hash, sizeof(file_hash), 1, stream); + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/atoms.c b/yara-master/libyara/atoms.c new file mode 100644 index 0000000..0890a22 --- /dev/null +++ b/yara-master/libyara/atoms.c @@ -0,0 +1,1377 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +/* + +This module handles atom extraction from regexps and hex strings. Atoms are +undivided substrings found in a regexps and hex strings. Let's consider this +hex string: + +{ 01 02 03 04 05 ?? 06 07 08 [1-2] 09 0A } + +In the above string, byte sequences 0102030405, 060708 and 090A are atoms. +Similarly, in this regexp: + +/abc.*ed[0-9]+fgh/ + +The strings "abc", "ed" and "fgh" are atoms. + +When searching for regexps/hex strings matching a file, YARA uses these +atoms to find locations inside the file where the regexp/hex string could +match. If the atom "abc" is found somewhere inside the file, there is a chance +for /abc.*ed[0-9]+fgh/ to match the file, if "abc" doesn't appear in the file +there's no chance for the regexp to match. When the atom is found in the file +YARA proceeds to fully evaluate the regexp/hex string to determine if it's +actually a match. + +For each regexp/hex string YARA extracts one or more atoms. Sometimes a +single atom is enough (like in the previous example "abc" is enough for finding +/abc.*ed[0-9]+fgh/), but sometimes a single atom isn't enough like in the +regexp /(abc|efg)/. In this case YARA must search for both "abc" AND "efg" and +fully evaluate the regexp whenever one of these atoms is found. + +In the regexp /Look(at|into)this/ YARA can search for "Look", or search for +"this", or search for both "at" and "into". This is what we call an atoms tree, +because it can be represented by the following tree structure: + +-OR + |- "Look" + | + |- AND + | | + | |- "at" + | - "into" + | + - "this" + +From an atom tree YARA chooses the best combination, trying to minimize the +number of required atoms, but also using high quality atoms (long atoms with +not too many zeroes and a bit of byte diversity). In the previous example YARA +will end up using the "Look" atom alone, but in /a(bcd|efg)h/ atoms "bcd" and +"efg" will be used because "a" and "h" are too short. + +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define YR_MAX_ATOM_QUALITY 100000 +#define YR_MIN_ATOM_QUALITY -100000 + + +#define append_current_leaf_to_node(node) \ + if (atom_tree->current_leaf != NULL) \ + { \ + _yr_atoms_tree_node_append(node, atom_tree->current_leaf); \ + atom_tree->current_leaf = NULL; \ + } \ + + +// +// _yr_atoms_quality +// +// Returns a numeric value indicating the quality of an atom. The quality +// depends on some characteristics of the atom, including its length, number +// of very common bytes like 00 and FF and number of unique distinct bytes. +// Atom 00 00 has a very low quality, because it's only two bytes long and +// both bytes are zeroes. Atom 01 01 01 01 is better but still not optimal, +// because the same byte is repeated. Atom 01 02 03 04 is an optimal one. +// +// Args: +// uint8_t* atom - Pointer to the atom's bytes. +// int atom_length - Atom's length. +// +// Returns: +// An integer indicating the atom's quality +// + +static int _yr_atoms_quality( + uint8_t* atom, + int atom_length) +{ + int penalty = 0; + int unique_bytes = 0; + int is_unique; + int i, j; + + for (i = 0; i < atom_length; i++) + { + if (atom[i] == 0x00 || atom[i] == 0xFF || atom[i] == 0x20 || + atom[i] == 0x0A || atom[i] == 0x0D) + { + // Penalize common bytes, specially if they are in the first two positions. + + switch(i) + { + case 0: + penalty += 3; + break; + case 1: + penalty += 2; + break; + default: + penalty += 1; + break; + } + } + + is_unique = TRUE; + + for (j = i + 1; j < atom_length; j++) + if (atom[i] == atom[j]) + { + is_unique = FALSE; + break; + } + + if (is_unique) + unique_bytes += 1; + } + + return atom_length + unique_bytes - penalty; +} + +// +// yr_atoms_min_quality +// +// Returns the quality for the worst quality atom in a list. +// + +int yr_atoms_min_quality( + YR_ATOM_LIST_ITEM* atom_list) +{ + YR_ATOM_LIST_ITEM* atom; + + int quality; + int min_quality = YR_MAX_ATOM_QUALITY; + + if (atom_list == NULL) + return YR_MIN_ATOM_QUALITY; + + atom = atom_list; + + while (atom != NULL) + { + quality = _yr_atoms_quality(atom->atom, atom->atom_length); + + if (quality < min_quality) + min_quality = quality; + + atom = atom->next; + } + + return min_quality; +} + + +// +// _yr_atoms_tree_node_create +// +// Creates a new node for an atoms tree. +// + +static ATOM_TREE_NODE* _yr_atoms_tree_node_create( + uint8_t type) +{ + ATOM_TREE_NODE* new_node = (ATOM_TREE_NODE*) \ + yr_malloc(sizeof(ATOM_TREE_NODE)); + + if (new_node != NULL) + { + new_node->type = type; + new_node->atom_length = 0; + new_node->next_sibling = NULL; + new_node->children_head = NULL; + new_node->children_tail = NULL; + new_node->forward_code = NULL; + new_node->backward_code = NULL; + } + + return new_node; +} + + +// +// _yr_atoms_tree_node_destroy +// +// Destroys a node from an atoms tree. +// + +static void _yr_atoms_tree_node_destroy( + ATOM_TREE_NODE* node) +{ + ATOM_TREE_NODE* child; + ATOM_TREE_NODE* next_child; + + if (node == NULL) + return; + + if (node->type == ATOM_TREE_OR || node->type == ATOM_TREE_AND) + { + child = node->children_head; + + while (child != NULL) + { + next_child = child->next_sibling; + _yr_atoms_tree_node_destroy(child); + child = next_child; + } + } + + yr_free(node); +} + + +// +// _yr_atoms_tree_node_append +// +// Appends a new child node to another atoms tree node. +// + +static void _yr_atoms_tree_node_append( + ATOM_TREE_NODE* dest, + ATOM_TREE_NODE* node) +{ + if (dest->children_head == NULL) + dest->children_head = node; + + if (dest->children_tail != NULL) + dest->children_tail->next_sibling = node; + + dest->children_tail = node; +} + + +// +// _yr_atoms_tree_destroy +// +// Destroys an atoms tree. +// + +static void _yr_atoms_tree_destroy( + ATOM_TREE* atom_tree) +{ + _yr_atoms_tree_node_destroy(atom_tree->root_node); + yr_free(atom_tree); +} + + +// +// yr_atoms_list_destroy +// +// Destroys an atoms list. +// + +void yr_atoms_list_destroy( + YR_ATOM_LIST_ITEM* list_head) +{ + YR_ATOM_LIST_ITEM* item = list_head; + YR_ATOM_LIST_ITEM* next; + + while (item != NULL) + { + next = item->next; + yr_free(item); + item = next; + } +} + + +// +// yr_atoms_list_destroy +// +// Concats two atoms lists. +// + +static YR_ATOM_LIST_ITEM* _yr_atoms_list_concat( + YR_ATOM_LIST_ITEM* list1, + YR_ATOM_LIST_ITEM* list2) +{ + YR_ATOM_LIST_ITEM* item; + + if (list1 == NULL) + return list2; + + item = list1; + + while (item->next != NULL) + { + item = item->next; + } + + item->next = list2; + return list1; +} + + +// +// _yr_atoms_choose +// +// Chooses which atoms from an atoms tree will be used to feed the +// Aho-Corasick automaton, and puts them in a list. +// + +static int _yr_atoms_choose( + ATOM_TREE_NODE* node, + YR_ATOM_LIST_ITEM** chosen_atoms, + int* atoms_quality) +{ + ATOM_TREE_NODE* child; + YR_ATOM_LIST_ITEM* item; + YR_ATOM_LIST_ITEM* tail; + + int i, quality; + int max_quality = YR_MIN_ATOM_QUALITY; + int min_quality = YR_MAX_ATOM_QUALITY; + + *chosen_atoms = NULL; + + switch (node->type) + { + case ATOM_TREE_LEAF: + + item = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (item == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + for (i = 0; i < node->atom_length; i++) + item->atom[i] = node->atom[i]; + + item->atom_length = node->atom_length; + item->forward_code = node->forward_code; + item->backward_code = node->backward_code; + item->backtrack = 0; + item->next = NULL; + + *chosen_atoms = item; + *atoms_quality = _yr_atoms_quality(node->atom, node->atom_length); + break; + + case ATOM_TREE_OR: + + child = node->children_head; + + while (child != NULL) + { + FAIL_ON_ERROR(_yr_atoms_choose(child, &item, &quality)); + + if (quality > max_quality) + { + max_quality = quality; + yr_atoms_list_destroy(*chosen_atoms); + *chosen_atoms = item; + } + else + { + yr_atoms_list_destroy(item); + } + + child = child->next_sibling; + } + + *atoms_quality = max_quality; + break; + + case ATOM_TREE_AND: + + child = node->children_head; + + while (child != NULL) + { + FAIL_ON_ERROR(_yr_atoms_choose(child, &item, &quality)); + + if (quality < min_quality) + min_quality = quality; + + if (item != NULL) + { + tail = item; + while (tail->next != NULL) + tail = tail->next; + + tail->next = *chosen_atoms; + *chosen_atoms = item; + } + + child = child->next_sibling; + } + + *atoms_quality = min_quality; + break; + } + + return ERROR_SUCCESS; +} + + +// +// _yr_atoms_case_combinations +// +// Returns all combinations of lower and upper cases for a given atom. For +// atom "abc" the output would be "abc" "abC" "aBC" and so on. Resulting +// atoms are written into the output buffer in this format: +// +// [size of atom 1] [atom 1] ... [size of atom N] [atom N] [0] +// +// Notice the zero at the end to indicate where the output ends. +// +// The caller is responsible of providing a buffer large enough to hold the +// returned atoms. +// + +static uint8_t* _yr_atoms_case_combinations( + uint8_t* atom, + int atom_length, + int atom_offset, + uint8_t* output_buffer) +{ + uint8_t c; + uint8_t* new_atom; + + if (atom_offset + 1 < atom_length) + output_buffer = _yr_atoms_case_combinations( + atom, + atom_length, + atom_offset + 1, + output_buffer); + + c = atom[atom_offset]; + + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + { + // Write atom length. + *output_buffer = atom_length; + output_buffer++; + + memcpy(output_buffer, atom, atom_length); + + new_atom = output_buffer; + output_buffer += atom_length; + + // Swap character case. + if (c >= 'a' && c <= 'z') + new_atom[atom_offset] -= 32; + else + new_atom[atom_offset] += 32; + + if (atom_offset + 1 < atom_length) + output_buffer = _yr_atoms_case_combinations( + new_atom, + atom_length, + atom_offset + 1, + output_buffer); + } + + if (atom_offset == 0) + *output_buffer = 0; + + return output_buffer; +} + +// Size of buffer used in _yr_atoms_case_insensitive for storing the all +// the possible combinations for an atom. Each atom has up to MAX_ATOM_LENGTH +// characters and each character has two possible values (upper and lower case). +// That means 2 ^ MAX_ATOM_LENGTH combinations for an atom, where each atom +// occupies MAX_ATOM_LENGTH + 1 bytes (the atom itself +1 byte for its length) +// One extra bytes is allocated for the zero value indicating the end. + +#define CASE_COMBINATIONS_BUFFER_SIZE \ + (1 << MAX_ATOM_LENGTH) * (MAX_ATOM_LENGTH + 1) + 1 + +// +// _yr_atoms_case_insensitive +// +// For a given list of atoms returns another list of atoms +// with every case combination. +// + +static int _yr_atoms_case_insensitive( + YR_ATOM_LIST_ITEM* atoms, + YR_ATOM_LIST_ITEM** case_insensitive_atoms) +{ + YR_ATOM_LIST_ITEM* atom; + YR_ATOM_LIST_ITEM* new_atom; + + uint8_t buffer[CASE_COMBINATIONS_BUFFER_SIZE]; + uint8_t atom_length; + uint8_t* atoms_cursor; + + int i; + + *case_insensitive_atoms = NULL; + atom = atoms; + + while (atom != NULL) + { + _yr_atoms_case_combinations( + atom->atom, + atom->atom_length, + 0, + buffer); + + atoms_cursor = buffer; + atom_length = *atoms_cursor; + atoms_cursor++; + + while (atom_length != 0) + { + new_atom = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (new_atom == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + for (i = 0; i < atom_length; i++) + new_atom->atom[i] = atoms_cursor[i]; + + new_atom->atom_length = atom_length; + new_atom->forward_code = atom->forward_code; + new_atom->backward_code = atom->backward_code; + new_atom->backtrack = atom->backtrack; + new_atom->next = *case_insensitive_atoms; + + *case_insensitive_atoms = new_atom; + + atoms_cursor += atom_length; + atom_length = *atoms_cursor; + atoms_cursor++; + } + + atom = atom->next; + } + + return ERROR_SUCCESS; +} + + +// +// _yr_atoms_xor +// +// For a given list of atoms returns another list after a single byte xor +// has been applied to it. +// +static int _yr_atoms_xor( + YR_ATOM_LIST_ITEM* atoms, + YR_ATOM_LIST_ITEM** xor_atoms) +{ + YR_ATOM_LIST_ITEM* atom; + YR_ATOM_LIST_ITEM* new_atom; + + int i, j; + *xor_atoms = NULL; + atom = atoms; + + while (atom != NULL) + { + for (j = 1; j <= 255; j++) + { + new_atom = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (new_atom == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + for (i = 0; i < atom->atom_length; i++) + new_atom->atom[i] = atom->atom[i] ^ j; + + new_atom->atom_length = yr_min(atom->atom_length, MAX_ATOM_LENGTH); + new_atom->forward_code = atom->forward_code; + new_atom->backward_code = atom->backward_code; + new_atom->backtrack = atom->backtrack; + new_atom->next = *xor_atoms; + + *xor_atoms = new_atom; + } + + atom = atom->next; + } + return ERROR_SUCCESS; +} +// +// _yr_atoms_wide +// +// For a given list of atoms returns another list with the corresponding +// wide atoms. Wide atoms are just the original atoms with interleaved zeroes, +// for example: 01 02 -> 01 00 02 00 +// + +static int _yr_atoms_wide( + YR_ATOM_LIST_ITEM* atoms, + YR_ATOM_LIST_ITEM** wide_atoms) +{ + YR_ATOM_LIST_ITEM* atom; + YR_ATOM_LIST_ITEM* new_atom; + + int i; + + *wide_atoms = NULL; + atom = atoms; + + while (atom != NULL) + { + new_atom = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (new_atom == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + for (i = 0; i < MAX_ATOM_LENGTH; i++) + new_atom->atom[i] = 0; + + for (i = 0; i < atom->atom_length; i++) + { + if (i * 2 < MAX_ATOM_LENGTH) + new_atom->atom[i * 2] = atom->atom[i]; + else + break; + } + + new_atom->atom_length = yr_min(atom->atom_length * 2, MAX_ATOM_LENGTH); + new_atom->forward_code = atom->forward_code; + new_atom->backward_code = atom->backward_code; + new_atom->backtrack = atom->backtrack * 2; + new_atom->next = *wide_atoms; + + *wide_atoms = new_atom; + + atom = atom->next; + } + + return ERROR_SUCCESS; +} + + +// +// _yr_atoms_extract_from_re_node +// +// Extract atoms from a regular expression node. See description for +// _yr_atoms_extract_from_re for more details. +// + +static ATOM_TREE_NODE* _yr_atoms_extract_from_re_node( + RE_NODE* re_node, + ATOM_TREE* atom_tree, + ATOM_TREE_NODE* current_node) +{ + ATOM_TREE_NODE* left_node; + ATOM_TREE_NODE* right_node; + ATOM_TREE_NODE* and_node; + ATOM_TREE_NODE* current_leaf; + ATOM_TREE_NODE* temp; + + int quality; + int new_quality; + int i; + + uint8_t new_atom[MAX_ATOM_LENGTH]; + + switch(re_node->type) + { + case RE_NODE_LITERAL: + + if (atom_tree->current_leaf == NULL) + { + atom_tree->current_leaf = _yr_atoms_tree_node_create(ATOM_TREE_LEAF); + + if (atom_tree->current_leaf == NULL) + return NULL; + + atom_tree->current_leaf->forward_code = re_node->forward_code; + atom_tree->current_leaf->backward_code = re_node->backward_code; + + assert(atom_tree->current_leaf->forward_code != NULL); + assert(atom_tree->current_leaf->backward_code != NULL); + } + + current_leaf = atom_tree->current_leaf; + + if (current_leaf->atom_length < MAX_ATOM_LENGTH) + { + current_leaf->atom[current_leaf->atom_length] = + (uint8_t) re_node->value; + current_leaf->recent_nodes[current_leaf->atom_length] = re_node; + current_leaf->atom_length++; + } + else + { + for (i = 1; i < MAX_ATOM_LENGTH; i++) + current_leaf->recent_nodes[i - 1] = current_leaf->recent_nodes[i]; + + current_leaf->recent_nodes[MAX_ATOM_LENGTH - 1] = re_node; + + for (i = 0; i < MAX_ATOM_LENGTH; i++) + new_atom[i] = (uint8_t) current_leaf->recent_nodes[i]->value; + + quality = _yr_atoms_quality( + current_leaf->atom, + MAX_ATOM_LENGTH); + + new_quality = _yr_atoms_quality( + new_atom, + MAX_ATOM_LENGTH); + + if (new_quality > quality) + { + for (i = 0; i < MAX_ATOM_LENGTH; i++) + current_leaf->atom[i] = new_atom[i]; + + current_leaf->forward_code = \ + current_leaf->recent_nodes[0]->forward_code; + + current_leaf->backward_code = \ + current_leaf->recent_nodes[0]->backward_code; + + assert(current_leaf->forward_code != NULL); + assert(current_leaf->backward_code != NULL); + } + } + + return current_node; + + case RE_NODE_CONCAT: + + current_node = _yr_atoms_extract_from_re_node( + re_node->left, atom_tree, current_node); + + if (current_node == NULL) + return NULL; + + current_node = _yr_atoms_extract_from_re_node( + re_node->right, atom_tree, current_node); + + return current_node; + + case RE_NODE_ALT: + + append_current_leaf_to_node(current_node); + + left_node = _yr_atoms_tree_node_create(ATOM_TREE_OR); + + if (left_node == NULL) + return NULL; + + left_node = _yr_atoms_extract_from_re_node( + re_node->left, atom_tree, left_node); + + if (left_node == NULL) + return NULL; + + append_current_leaf_to_node(left_node); + + if (left_node->children_head == NULL) + { + _yr_atoms_tree_node_destroy(left_node); + return current_node; + } + + if (left_node->children_head == left_node->children_tail) + { + temp = left_node; + left_node = left_node->children_head; + yr_free(temp); + } + + right_node = _yr_atoms_tree_node_create(ATOM_TREE_OR); + + if (right_node == NULL) + return NULL; + + right_node = _yr_atoms_extract_from_re_node( + re_node->right, atom_tree, right_node); + + if (right_node == NULL) + return NULL; + + append_current_leaf_to_node(right_node); + + if (right_node->children_head == NULL) + { + _yr_atoms_tree_node_destroy(left_node); + _yr_atoms_tree_node_destroy(right_node); + return current_node; + } + + if (right_node->children_head == right_node->children_tail) + { + temp = right_node; + right_node = right_node->children_head; + yr_free(temp); + } + + and_node = _yr_atoms_tree_node_create(ATOM_TREE_AND); + + if (and_node == NULL) + return NULL; + + and_node->children_head = left_node; + and_node->children_tail = right_node; + left_node->next_sibling = right_node; + + _yr_atoms_tree_node_append(current_node, and_node); + + return current_node; + + case RE_NODE_RANGE: + + if (re_node->start == 0) + append_current_leaf_to_node(current_node); + + // In a regexp like /a{10,20}/ the optimal atom is 'aaaa' (assuming that + // MAX_ATOM_LENGTH = 4) because the 'a' character must appear at least + // 10 times in the matching string. Each call in the loop will append + // one 'a' to the atom, so MAX_ATOM_LENGTH iterations are enough. + + for (i = 0; i < yr_min(re_node->start, MAX_ATOM_LENGTH); i++) + { + current_node = _yr_atoms_extract_from_re_node( + re_node->left, atom_tree, current_node); + + if (current_node == NULL) + return NULL; + } + + if (re_node->start != re_node->end) + append_current_leaf_to_node(current_node); + + return current_node; + + case RE_NODE_PLUS: + + current_node = _yr_atoms_extract_from_re_node( + re_node->left, atom_tree, current_node); + + if (current_node == NULL) + return NULL; + + append_current_leaf_to_node(current_node); + return current_node; + + case RE_NODE_ANY: + case RE_NODE_RANGE_ANY: + case RE_NODE_STAR: + case RE_NODE_CLASS: + case RE_NODE_MASKED_LITERAL: + case RE_NODE_WORD_CHAR: + case RE_NODE_NON_WORD_CHAR: + case RE_NODE_SPACE: + case RE_NODE_NON_SPACE: + case RE_NODE_DIGIT: + case RE_NODE_NON_DIGIT: + case RE_NODE_EMPTY: + case RE_NODE_ANCHOR_START: + case RE_NODE_ANCHOR_END: + case RE_NODE_WORD_BOUNDARY: + case RE_NODE_NON_WORD_BOUNDARY: + + append_current_leaf_to_node(current_node); + return current_node; + + default: + assert(FALSE); + } + + return NULL; +} + +// +// yr_atoms_extract_triplets +// +// On certain cases YARA can not extract long enough atoms from a regexp, but +// can infer them. For example, in the hex string { 01 ?? 02 } the only explicit +// atoms are 01 and 02, and both of them are too short to be efficiently used. +// However YARA can use simultaneously atoms 01 00 02, 01 01 02, 01 02 02, +// 01 03 02, and so on up to 01 FF 02. Searching for 256 three-bytes atoms is +// faster than searching for a single one-byte atom. +// +// This function extracts these three-bytes atoms from a regexp node if +// possible. +// + +int yr_atoms_extract_triplets( + RE_NODE* re_node, + YR_ATOM_LIST_ITEM** atoms) + { + RE_NODE* left_child; + RE_NODE* left_grand_child; + + int i; + int shift; + + *atoms = NULL; + + if (re_node->type == RE_NODE_CONCAT) + left_child = re_node->left; + else + return ERROR_SUCCESS; + + if (left_child->type == RE_NODE_CONCAT) + left_grand_child = left_child->left; + else + return ERROR_SUCCESS; + + if (re_node->right->type != RE_NODE_LITERAL) + return yr_atoms_extract_triplets(left_child, atoms); + + if (left_child->left->type == RE_NODE_LITERAL && + (left_child->right->type == RE_NODE_ANY)) + { + for (i = 0; i < 256; i++) + { + YR_ATOM_LIST_ITEM* atom = (YR_ATOM_LIST_ITEM*) + yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (atom == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + atom->atom[0] = (uint8_t) left_child->left->value; + atom->atom[1] = (uint8_t) i; + atom->atom[2] = (uint8_t) re_node->right->value; + + atom->atom_length = 3; + atom->forward_code = left_child->left->forward_code; + atom->backward_code = left_child->left->backward_code; + atom->backtrack = 0; + atom->next = *atoms; + + *atoms = atom; + } + + return ERROR_SUCCESS; + } + + if (left_child->left->type == RE_NODE_LITERAL && + (left_child->right->type == RE_NODE_MASKED_LITERAL)) + { + for (i = 0; i < 16; i++) + { + YR_ATOM_LIST_ITEM* atom = (YR_ATOM_LIST_ITEM*) + yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (atom == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + if (left_child->right->mask == 0xF0) + shift = 0; + else + shift = 4; + + atom->atom[0] = (uint8_t) left_child->left->value; + atom->atom[1] = (uint8_t)(left_child->right->value | (i << shift)); + atom->atom[2] = (uint8_t) re_node->right->value; + + atom->atom_length = 3; + atom->forward_code = left_child->left->forward_code; + atom->backward_code = left_child->left->backward_code; + atom->backtrack = 0; + atom->next = *atoms; + + *atoms = atom; + } + + return ERROR_SUCCESS; + } + + if (left_grand_child->type == RE_NODE_CONCAT && + left_grand_child->right->type == RE_NODE_LITERAL && + (left_child->right->type == RE_NODE_ANY)) + { + for (i = 0; i < 256; i++) + { + YR_ATOM_LIST_ITEM* atom = (YR_ATOM_LIST_ITEM*) + yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (atom == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + atom->atom[0] = (uint8_t) left_grand_child->right->value; + atom->atom[1] = (uint8_t) i; + atom->atom[2] = (uint8_t) re_node->right->value; + + atom->atom_length = 3; + atom->forward_code = left_grand_child->right->forward_code; + atom->backward_code = left_grand_child->right->backward_code; + atom->backtrack = 0; + atom->next = *atoms; + + *atoms = atom; + } + + return ERROR_SUCCESS; + } + + if (left_grand_child->type == RE_NODE_CONCAT && + left_grand_child->right->type == RE_NODE_LITERAL && + (left_child->right->type == RE_NODE_MASKED_LITERAL)) + { + for (i = 0; i < 16; i++) + { + YR_ATOM_LIST_ITEM* atom = (YR_ATOM_LIST_ITEM*) + yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (atom == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + if (left_child->right->mask == 0xF0) + shift = 0; + else + shift = 4; + + atom->atom[0] = (uint8_t) left_grand_child->right->value; + atom->atom[1] = (uint8_t)(left_child->right->value | (i << shift)); + atom->atom[2] = (uint8_t) re_node->right->value; + + atom->atom_length = 3; + atom->forward_code = left_grand_child->right->forward_code; + atom->backward_code = left_grand_child->right->backward_code; + atom->backtrack = 0; + atom->next = *atoms; + + *atoms = atom; + } + + return ERROR_SUCCESS; + } + + return yr_atoms_extract_triplets(left_child, atoms);; + } + +// +// _yr_atoms_extract_from_re +// +// Extract atoms from a regular expression. +// + +int yr_atoms_extract_from_re( + RE_AST* re_ast, + int flags, + YR_ATOM_LIST_ITEM** atoms) +{ + ATOM_TREE* atom_tree = (ATOM_TREE*) yr_malloc(sizeof(ATOM_TREE)); + ATOM_TREE_NODE* temp; + YR_ATOM_LIST_ITEM* wide_atoms; + YR_ATOM_LIST_ITEM* case_insensitive_atoms; + YR_ATOM_LIST_ITEM* triplet_atoms; + + int min_atom_quality = YR_MIN_ATOM_QUALITY; + + if (atom_tree == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + atom_tree->root_node = _yr_atoms_tree_node_create(ATOM_TREE_OR); + + if (atom_tree->root_node == NULL) + { + _yr_atoms_tree_destroy(atom_tree); + return ERROR_INSUFFICIENT_MEMORY; + } + + atom_tree->current_leaf = NULL; + + atom_tree->root_node = _yr_atoms_extract_from_re_node( + re_ast->root_node, atom_tree, atom_tree->root_node); + + if (atom_tree->root_node == NULL) + { + _yr_atoms_tree_destroy(atom_tree); + return ERROR_INSUFFICIENT_MEMORY; + } + + if (atom_tree->current_leaf != NULL) + _yr_atoms_tree_node_append(atom_tree->root_node, atom_tree->current_leaf); + + if (atom_tree->root_node->children_head == + atom_tree->root_node->children_tail) + { + // The root OR node has a single child, there's no need for the OR node so + // we proceed to destroy it and use its child as root. + + temp = atom_tree->root_node; + atom_tree->root_node = atom_tree->root_node->children_head; + yr_free(temp); + } + + // Initialize atom list + *atoms = NULL; + + if (atom_tree->root_node != NULL) + { + // Choose the atoms that will be used. + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_atoms_choose(atom_tree->root_node, atoms, &min_atom_quality), + _yr_atoms_tree_destroy(atom_tree)); + } + + _yr_atoms_tree_destroy(atom_tree); + + if (min_atom_quality <= 2) + { + // Chosen atoms contain low quality ones, let's try infering some higher + // quality atoms. + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_atoms_extract_triplets(re_ast->root_node, &triplet_atoms), + { + yr_atoms_list_destroy(*atoms); + yr_atoms_list_destroy(triplet_atoms); + *atoms = NULL; + }); + + if (min_atom_quality < yr_atoms_min_quality(triplet_atoms)) + { + yr_atoms_list_destroy(*atoms); + *atoms = triplet_atoms; + } + else + { + yr_atoms_list_destroy(triplet_atoms); + } + } + + if (flags & STRING_GFLAGS_WIDE) + { + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_atoms_wide(*atoms, &wide_atoms), + { + yr_atoms_list_destroy(*atoms); + yr_atoms_list_destroy(wide_atoms); + *atoms = NULL; + }); + + if (flags & STRING_GFLAGS_ASCII) + { + *atoms = _yr_atoms_list_concat(*atoms, wide_atoms); + } + else + { + yr_atoms_list_destroy(*atoms); + *atoms = wide_atoms; + } + } + + if (flags & STRING_GFLAGS_NO_CASE) + { + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_atoms_case_insensitive(*atoms, &case_insensitive_atoms), + { + yr_atoms_list_destroy(*atoms); + yr_atoms_list_destroy(case_insensitive_atoms); + *atoms = NULL; + }); + + *atoms = _yr_atoms_list_concat(*atoms, case_insensitive_atoms); + } + + // No atoms has been extracted, let's add a zero-length atom. + + if (*atoms == NULL) + { + *atoms = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (*atoms == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + (*atoms)->atom_length = 0; + (*atoms)->backtrack = 0; + (*atoms)->forward_code = re_ast->root_node->forward_code; + (*atoms)->backward_code = NULL; + (*atoms)->next = NULL; + } + + return ERROR_SUCCESS; +} + + +// +// yr_atoms_extract_from_string +// +// Extract atoms from a string. +// + +int yr_atoms_extract_from_string( + uint8_t* string, + int32_t string_length, + int flags, + YR_ATOM_LIST_ITEM** atoms) +{ + YR_ATOM_LIST_ITEM* item; + YR_ATOM_LIST_ITEM* case_insensitive_atoms; + YR_ATOM_LIST_ITEM* xor_atoms; + YR_ATOM_LIST_ITEM* wide_atoms; + + int max_quality; + int i, j, length; + + item = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); + + if (item == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + item->forward_code = NULL; + item->backward_code = NULL; + item->next = NULL; + item->backtrack = 0; + + length = yr_min(string_length, MAX_ATOM_LENGTH); + + for (i = 0; i < length; i++) + item->atom[i] = string[i]; + + item->atom_length = i; + + max_quality = _yr_atoms_quality(string, length); + + for (i = MAX_ATOM_LENGTH; i < string_length; i++) + { + int quality = _yr_atoms_quality( + string + i - MAX_ATOM_LENGTH + 1, MAX_ATOM_LENGTH); + + if (quality > max_quality) + { + for (j = 0; j < MAX_ATOM_LENGTH; j++) + item->atom[j] = string[i + j - MAX_ATOM_LENGTH + 1]; + + item->backtrack = i - MAX_ATOM_LENGTH + 1; + max_quality = quality; + } + } + + *atoms = item; + + if (flags & STRING_GFLAGS_WIDE) + { + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_atoms_wide(*atoms, &wide_atoms), + { + yr_atoms_list_destroy(*atoms); + yr_atoms_list_destroy(wide_atoms); + *atoms = NULL; + }); + + if (flags & STRING_GFLAGS_ASCII) + { + *atoms = _yr_atoms_list_concat(*atoms, wide_atoms); + } + else + { + yr_atoms_list_destroy(*atoms); + *atoms = wide_atoms; + } + } + + if (flags & STRING_GFLAGS_NO_CASE) + { + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_atoms_case_insensitive(*atoms, &case_insensitive_atoms), + { + yr_atoms_list_destroy(*atoms); + yr_atoms_list_destroy(case_insensitive_atoms); + *atoms = NULL; + }); + + *atoms = _yr_atoms_list_concat(*atoms, case_insensitive_atoms); + } + + if (flags & STRING_GFLAGS_XOR) + { + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_atoms_xor(*atoms, &xor_atoms), + { + yr_atoms_list_destroy(*atoms); + yr_atoms_list_destroy(xor_atoms); + *atoms = NULL; + }); + + if (flags & STRING_GFLAGS_ASCII || + flags & STRING_GFLAGS_WIDE || + flags & STRING_GFLAGS_NO_CASE) + { + *atoms = _yr_atoms_list_concat(*atoms, xor_atoms); + } + else + { + yr_atoms_list_destroy(*atoms); + *atoms = xor_atoms; + } + + } + + return ERROR_SUCCESS; +} + + +// +// yr_atoms_tree_node_print +// +// Prints an atom tree node. Used only for debugging purposes. +// + +void yr_atoms_tree_node_print( + ATOM_TREE_NODE* node) +{ + ATOM_TREE_NODE* child; + int i; + + if (node == NULL) + { + printf("Empty tree node\n"); + return; + } + + switch(node->type) + { + case ATOM_TREE_LEAF: + for (i = 0; i < node->atom_length; i++) + printf("%02X", node->atom[i]); + break; + + case ATOM_TREE_AND: + case ATOM_TREE_OR: + if (node->type == ATOM_TREE_AND) + printf("AND"); + else + printf("OR"); + printf("("); + child = node->children_head; + while (child != NULL) + { + yr_atoms_tree_node_print(child); + child = child->next_sibling; + if (child != NULL) + printf(","); + } + printf(")"); + break; + } +} diff --git a/yara-master/libyara/compiler.c b/yara-master/libyara/compiler.c new file mode 100644 index 0000000..b00b109 --- /dev/null +++ b/yara-master/libyara/compiler.c @@ -0,0 +1,1162 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static void _yr_compiler_default_include_free( + const char* callback_result_ptr, + void* user_data) +{ + if (callback_result_ptr != NULL) + { + yr_free((void*)callback_result_ptr); + } +} + + +const char* _yr_compiler_default_include_callback( + const char* include_name, + const char* calling_rule_filename, + const char* calling_rule_namespace, + void* user_data) +{ + #ifndef _MSC_VER + struct stat stbuf; + #endif + + char* file_buffer; + + #ifdef _MSC_VER + long file_size; + #else + off_t file_size; + #endif + + int fd = -1; + + #if defined(_MSC_VER) + _sopen_s(&fd, include_name, _O_RDONLY | _O_BINARY, _SH_DENYRW, _S_IREAD); + #elif defined(_WIN32) || defined(__CYGWIN__) + fd = open(include_name, O_RDONLY | O_BINARY); + #else + fd = open(include_name, O_RDONLY); + #endif + + if (fd == -1) + return NULL; + + #ifdef _MSC_VER + file_size = _filelength(fd); + if (file_size == -1) + { + _close(fd); + return NULL; + } + #else + if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) + { + close(fd); + return NULL; + } + file_size = stbuf.st_size; + #endif + + file_buffer = (char*) yr_malloc((size_t) file_size + 1); + + if (file_buffer == NULL) + { + #ifdef _MSC_VER + _close(fd); + #else + close(fd); + #endif + + return NULL; + } + + if (file_size != read(fd, file_buffer, (size_t) file_size)) + { + yr_free(file_buffer); + + #ifdef _MSC_VER + _close(fd); + #else + close(fd); + #endif + + return NULL; + } + else + { + file_buffer[file_size] = '\0'; + } + + #ifdef _MSC_VER + _close(fd); + #else + close(fd); + #endif + + return file_buffer; +} + + +YR_API int yr_compiler_create( + YR_COMPILER** compiler) +{ + int result; + YR_COMPILER* new_compiler; + + new_compiler = (YR_COMPILER*) yr_calloc(1, sizeof(YR_COMPILER)); + + if (new_compiler == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + new_compiler->errors = 0; + new_compiler->callback = NULL; + new_compiler->include_callback = _yr_compiler_default_include_callback; + new_compiler->incl_clbk_user_data = NULL; + new_compiler->include_free = _yr_compiler_default_include_free; + new_compiler->re_ast_callback = NULL; + new_compiler->re_ast_clbk_user_data = NULL; + new_compiler->last_error = ERROR_SUCCESS; + new_compiler->last_error_line = 0; + new_compiler->current_line = 0; + new_compiler->last_result = ERROR_SUCCESS; + new_compiler->file_name_stack_ptr = 0; + new_compiler->fixup_stack_head = NULL; + new_compiler->loop_depth = 0; + new_compiler->loop_for_of_mem_offset = -1; + new_compiler->compiled_rules_arena = NULL; + new_compiler->namespaces_count = 0; + new_compiler->current_rule = NULL; + + result = yr_hash_table_create(10007, &new_compiler->rules_table); + + if (result == ERROR_SUCCESS) + result = yr_hash_table_create(10007, &new_compiler->objects_table); + + if (result == ERROR_SUCCESS) + result = yr_hash_table_create(101, &new_compiler->strings_table); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->sz_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->rules_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->strings_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->code_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->re_code_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->externals_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->namespaces_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->metas_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->automaton_arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_create( + 65536, ARENA_FLAGS_RELOCATABLE, &new_compiler->matches_arena); + + if (result == ERROR_SUCCESS) + result = yr_ac_automaton_create(&new_compiler->automaton); + + if (result == ERROR_SUCCESS) + { + *compiler = new_compiler; + } + else // if error, do cleanup + { + yr_compiler_destroy(new_compiler); + } + + return result; +} + + +YR_API void yr_compiler_destroy( + YR_COMPILER* compiler) +{ + YR_FIXUP* fixup; + int i; + + yr_arena_destroy(compiler->compiled_rules_arena); + yr_arena_destroy(compiler->sz_arena); + yr_arena_destroy(compiler->rules_arena); + yr_arena_destroy(compiler->strings_arena); + yr_arena_destroy(compiler->code_arena); + yr_arena_destroy(compiler->re_code_arena); + yr_arena_destroy(compiler->externals_arena); + yr_arena_destroy(compiler->namespaces_arena); + yr_arena_destroy(compiler->metas_arena); + yr_arena_destroy(compiler->automaton_arena); + yr_arena_destroy(compiler->matches_arena); + + yr_ac_automaton_destroy(compiler->automaton); + + yr_hash_table_destroy( + compiler->rules_table, + NULL); + + yr_hash_table_destroy( + compiler->strings_table, + NULL); + + yr_hash_table_destroy( + compiler->objects_table, + (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy); + + for (i = 0; i < compiler->file_name_stack_ptr; i++) + yr_free(compiler->file_name_stack[i]); + + fixup = compiler->fixup_stack_head; + + while (fixup != NULL) + { + YR_FIXUP* next_fixup = fixup->next; + yr_free(fixup); + fixup = next_fixup; + } + + yr_free(compiler); +} + + +YR_API void yr_compiler_set_callback( + YR_COMPILER* compiler, + YR_COMPILER_CALLBACK_FUNC callback, + void* user_data) +{ + compiler->callback = callback; + compiler->user_data = user_data; +} + + +YR_API void yr_compiler_set_include_callback( + YR_COMPILER* compiler, + YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback, + YR_COMPILER_INCLUDE_FREE_FUNC include_free, + void* user_data) +{ + compiler->include_callback = include_callback; + compiler->include_free = include_free; + compiler->incl_clbk_user_data = user_data; +} + + +YR_API void yr_compiler_set_re_ast_callback( + YR_COMPILER* compiler, + YR_COMPILER_RE_AST_CALLBACK_FUNC re_ast_callback, + void* user_data) +{ + compiler->re_ast_callback = re_ast_callback; + compiler->re_ast_clbk_user_data = user_data; +} + + +int _yr_compiler_push_file_name( + YR_COMPILER* compiler, + const char* file_name) +{ + char* str; + int i; + + for (i = 0; i < compiler->file_name_stack_ptr; i++) + { + if (strcmp(file_name, compiler->file_name_stack[i]) == 0) + { + compiler->last_result = ERROR_INCLUDES_CIRCULAR_REFERENCE; + return ERROR_INCLUDES_CIRCULAR_REFERENCE; + } + } + + if (compiler->file_name_stack_ptr < MAX_INCLUDE_DEPTH) + { + str = yr_strdup(file_name); + + if (str == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + compiler->file_name_stack[compiler->file_name_stack_ptr] = str; + compiler->file_name_stack_ptr++; + + return ERROR_SUCCESS; + } + else + { + compiler->last_result = ERROR_INCLUDE_DEPTH_EXCEEDED; + return ERROR_INCLUDE_DEPTH_EXCEEDED; + } +} + + +void _yr_compiler_pop_file_name( + YR_COMPILER* compiler) +{ + if (compiler->file_name_stack_ptr > 0) + { + compiler->file_name_stack_ptr--; + yr_free(compiler->file_name_stack[compiler->file_name_stack_ptr]); + compiler->file_name_stack[compiler->file_name_stack_ptr] = NULL; + } +} + + +YR_API char* yr_compiler_get_current_file_name( + YR_COMPILER* compiler) +{ + if (compiler->file_name_stack_ptr > 0) + { + return compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; + } + else + { + return NULL; + } +} + + +static int _yr_compiler_set_namespace( + YR_COMPILER* compiler, + const char* namespace_) +{ + YR_NAMESPACE* ns; + + char* ns_name; + int result; + int i; + int found; + + ns = (YR_NAMESPACE*) yr_arena_base_address(compiler->namespaces_arena); + found = FALSE; + + for (i = 0; i < compiler->namespaces_count; i++) + { + if (strcmp(ns->name, namespace_) == 0) + { + found = TRUE; + break; + } + + ns = (YR_NAMESPACE*) yr_arena_next_address( + compiler->namespaces_arena, + ns, + sizeof(YR_NAMESPACE)); + } + + if (!found) + { + result = yr_arena_write_string( + compiler->sz_arena, + namespace_, + &ns_name); + + if (result == ERROR_SUCCESS) + result = yr_arena_allocate_struct( + compiler->namespaces_arena, + sizeof(YR_NAMESPACE), + (void**) &ns, + offsetof(YR_NAMESPACE, name), + EOL); + + if (result != ERROR_SUCCESS) + return result; + + ns->name = ns_name; + + for (i = 0; i < MAX_THREADS; i++) + ns->t_flags[i] = 0; + + compiler->namespaces_count++; + } + + compiler->current_namespace = ns; + return ERROR_SUCCESS; +} + + +YR_API int yr_compiler_add_file( + YR_COMPILER* compiler, + FILE* rules_file, + const char* namespace_, + const char* file_name) +{ + // Don't allow yr_compiler_add_file() after + // yr_compiler_get_rules() has been called. + + assert(compiler->compiled_rules_arena == NULL); + + // Don't allow calls to yr_compiler_add_file() if a previous call to + // yr_compiler_add_XXXX failed. + + assert(compiler->errors == 0); + + if (file_name != NULL) + _yr_compiler_push_file_name(compiler, file_name); + + if (namespace_ != NULL) + compiler->last_result = _yr_compiler_set_namespace(compiler, namespace_); + else + compiler->last_result = _yr_compiler_set_namespace(compiler, "default"); + + if (compiler->last_result == ERROR_SUCCESS) + { + return yr_lex_parse_rules_file(rules_file, compiler); + } + else + { + compiler->errors++; + return compiler->errors; + } + +} + + +YR_API int yr_compiler_add_fd( + YR_COMPILER* compiler, + YR_FILE_DESCRIPTOR rules_fd, + const char* namespace_, + const char* file_name) +{ + // Don't allow yr_compiler_add_fd() after + // yr_compiler_get_rules() has been called. + + assert(compiler->compiled_rules_arena == NULL); + + // Don't allow calls to yr_compiler_add_fd() if a previous call to + // yr_compiler_add_XXXX failed. + + assert(compiler->last_error == ERROR_SUCCESS); + + if (file_name != NULL) + _yr_compiler_push_file_name(compiler, file_name); + + if (namespace_ != NULL) + compiler->last_result = _yr_compiler_set_namespace(compiler, namespace_); + else + compiler->last_result = _yr_compiler_set_namespace(compiler, "default"); + + if (compiler->last_result == ERROR_SUCCESS) + { + return yr_lex_parse_rules_fd(rules_fd, compiler); + } + else + { + compiler->errors++; + return compiler->errors; + } +} + + +YR_API int yr_compiler_add_string( + YR_COMPILER* compiler, + const char* rules_string, + const char* namespace_) +{ + // Don't allow calls to yr_compiler_add_string() after + // yr_compiler_get_rules() has been called. + + assert(compiler->compiled_rules_arena == NULL); + + // Don't allow calls to yr_compiler_add_string() if a previous call to + // yr_compiler_add_XXXX failed. + + assert(compiler->last_error == ERROR_SUCCESS); + + if (namespace_ != NULL) + compiler->last_result = _yr_compiler_set_namespace(compiler, namespace_); + else + compiler->last_result = _yr_compiler_set_namespace(compiler, "default"); + + if (compiler->last_result == ERROR_SUCCESS) + { + return yr_lex_parse_rules_string(rules_string, compiler); + } + else + { + compiler->errors++; + return compiler->errors; + } +} + + +static int _yr_compiler_compile_rules( + YR_COMPILER* compiler) +{ + YARA_RULES_FILE_HEADER* rules_file_header = NULL; + YR_ARENA* arena = NULL; + YR_RULE null_rule; + YR_EXTERNAL_VARIABLE null_external; + YR_AC_TABLES tables; + + uint8_t halt = OP_HALT; + int result; + + // Write halt instruction at the end of code. + yr_arena_write_data( + compiler->code_arena, + &halt, + sizeof(uint8_t), + NULL); + + // Write a null rule indicating the end. + memset(&null_rule, 0xFA, sizeof(YR_RULE)); + null_rule.g_flags = RULE_GFLAGS_NULL; + + yr_arena_write_data( + compiler->rules_arena, + &null_rule, + sizeof(YR_RULE), + NULL); + + // Write a null external the end. + memset(&null_external, 0xFA, sizeof(YR_EXTERNAL_VARIABLE)); + null_external.type = EXTERNAL_VARIABLE_TYPE_NULL; + + yr_arena_write_data( + compiler->externals_arena, + &null_external, + sizeof(YR_EXTERNAL_VARIABLE), + NULL); + + // Write Aho-Corasick automaton to arena. + result = yr_ac_compile( + compiler->automaton, + compiler->automaton_arena, + &tables); + + if (result == ERROR_SUCCESS) + result = yr_arena_create(1024, ARENA_FLAGS_RELOCATABLE, &arena); + + if (result == ERROR_SUCCESS) + result = yr_arena_allocate_struct( + arena, + sizeof(YARA_RULES_FILE_HEADER), + (void**) &rules_file_header, + offsetof(YARA_RULES_FILE_HEADER, rules_list_head), + offsetof(YARA_RULES_FILE_HEADER, externals_list_head), + offsetof(YARA_RULES_FILE_HEADER, code_start), + offsetof(YARA_RULES_FILE_HEADER, match_table), + offsetof(YARA_RULES_FILE_HEADER, transition_table), + EOL); + + if (result == ERROR_SUCCESS) + { + rules_file_header->rules_list_head = (YR_RULE*) yr_arena_base_address( + compiler->rules_arena); + + rules_file_header->externals_list_head = (YR_EXTERNAL_VARIABLE*) + yr_arena_base_address(compiler->externals_arena); + + rules_file_header->code_start = (uint8_t*) yr_arena_base_address( + compiler->code_arena); + + rules_file_header->match_table = tables.matches; + rules_file_header->transition_table = tables.transitions; + } + + if (result == ERROR_SUCCESS) + { + result = yr_arena_append( + arena, + compiler->code_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->code_arena = NULL; + result = yr_arena_append( + arena, + compiler->re_code_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->re_code_arena = NULL; + result = yr_arena_append( + arena, + compiler->rules_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->rules_arena = NULL; + result = yr_arena_append( + arena, + compiler->strings_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->strings_arena = NULL; + result = yr_arena_append( + arena, + compiler->externals_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->externals_arena = NULL; + result = yr_arena_append( + arena, + compiler->namespaces_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->namespaces_arena = NULL; + result = yr_arena_append( + arena, + compiler->metas_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->metas_arena = NULL; + result = yr_arena_append( + arena, + compiler->sz_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->sz_arena = NULL; + result = yr_arena_append( + arena, + compiler->automaton_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->automaton_arena = NULL; + result = yr_arena_append( + arena, + compiler->matches_arena); + } + + if (result == ERROR_SUCCESS) + { + compiler->matches_arena = NULL; + compiler->compiled_rules_arena = arena; + result = yr_arena_coalesce(arena); + } + else + { + yr_arena_destroy(arena); + } + + return result; +} + + +YR_API int yr_compiler_get_rules( + YR_COMPILER* compiler, + YR_RULES** rules) +{ + YR_RULES* yara_rules; + YARA_RULES_FILE_HEADER* rules_file_header; + + // Don't allow calls to yr_compiler_get_rules() if a previous call to + // yr_compiler_add_XXXX failed. + + assert(compiler->last_error == ERROR_SUCCESS); + + *rules = NULL; + + if (compiler->compiled_rules_arena == NULL) + FAIL_ON_ERROR(_yr_compiler_compile_rules(compiler)); + + yara_rules = (YR_RULES*) yr_malloc(sizeof(YR_RULES)); + + if (yara_rules == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_arena_duplicate(compiler->compiled_rules_arena, &yara_rules->arena), + yr_free(yara_rules)); + + rules_file_header = (YARA_RULES_FILE_HEADER*) yr_arena_base_address( + yara_rules->arena); + + yara_rules->externals_list_head = rules_file_header->externals_list_head; + yara_rules->rules_list_head = rules_file_header->rules_list_head; + yara_rules->match_table = rules_file_header->match_table; + yara_rules->transition_table = rules_file_header->transition_table; + yara_rules->code_start = rules_file_header->code_start; + yara_rules->time_cost = 0; + + memset(yara_rules->tidx_mask, 0, sizeof(yara_rules->tidx_mask)); + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_mutex_create(&yara_rules->mutex), + // cleanup + yr_arena_destroy(yara_rules->arena); + yr_free(yara_rules)); + + *rules = yara_rules; + + return ERROR_SUCCESS; +} + + +YR_API int yr_compiler_define_integer_variable( + YR_COMPILER* compiler, + const char* identifier, + int64_t value) +{ + YR_EXTERNAL_VARIABLE* external; + YR_OBJECT* object; + + char* id; + + compiler->last_result = ERROR_SUCCESS; + + FAIL_ON_COMPILER_ERROR(yr_arena_write_string( + compiler->sz_arena, + identifier, + &id)); + + FAIL_ON_COMPILER_ERROR(yr_arena_allocate_struct( + compiler->externals_arena, + sizeof(YR_EXTERNAL_VARIABLE), + (void**) &external, + offsetof(YR_EXTERNAL_VARIABLE, identifier), + EOL)); + + external->type = EXTERNAL_VARIABLE_TYPE_INTEGER; + external->identifier = id; + external->value.i = value; + + FAIL_ON_COMPILER_ERROR(yr_object_from_external_variable( + external, + &object)); + + FAIL_ON_COMPILER_ERROR(yr_hash_table_add( + compiler->objects_table, + external->identifier, + NULL, + (void*) object)); + + return ERROR_SUCCESS; +} + + +YR_API int yr_compiler_define_boolean_variable( + YR_COMPILER* compiler, + const char* identifier, + int value) +{ + YR_EXTERNAL_VARIABLE* external; + YR_OBJECT* object; + + char* id; + + compiler->last_result = ERROR_SUCCESS; + + FAIL_ON_COMPILER_ERROR(yr_arena_write_string( + compiler->sz_arena, + identifier, + &id)); + + FAIL_ON_COMPILER_ERROR(yr_arena_allocate_struct( + compiler->externals_arena, + sizeof(YR_EXTERNAL_VARIABLE), + (void**) &external, + offsetof(YR_EXTERNAL_VARIABLE, identifier), + EOL)); + + external->type = EXTERNAL_VARIABLE_TYPE_BOOLEAN; + external->identifier = id; + external->value.i = value; + + FAIL_ON_COMPILER_ERROR(yr_object_from_external_variable( + external, + &object)); + + FAIL_ON_COMPILER_ERROR(yr_hash_table_add( + compiler->objects_table, + external->identifier, + NULL, + (void*) object)); + + return ERROR_SUCCESS; +} + + +YR_API int yr_compiler_define_float_variable( + YR_COMPILER* compiler, + const char* identifier, + double value) +{ + YR_EXTERNAL_VARIABLE* external; + YR_OBJECT* object; + + char* id; + + compiler->last_result = ERROR_SUCCESS; + + FAIL_ON_COMPILER_ERROR(yr_arena_write_string( + compiler->sz_arena, + identifier, + &id)); + + FAIL_ON_COMPILER_ERROR(yr_arena_allocate_struct( + compiler->externals_arena, + sizeof(YR_EXTERNAL_VARIABLE), + (void**) &external, + offsetof(YR_EXTERNAL_VARIABLE, identifier), + EOL)); + + external->type = EXTERNAL_VARIABLE_TYPE_FLOAT; + external->identifier = id; + external->value.f = value; + + FAIL_ON_COMPILER_ERROR(yr_object_from_external_variable( + external, + &object)); + + FAIL_ON_COMPILER_ERROR(yr_hash_table_add( + compiler->objects_table, + external->identifier, + NULL, + (void*) object)); + + return ERROR_SUCCESS; +} + + +YR_API int yr_compiler_define_string_variable( + YR_COMPILER* compiler, + const char* identifier, + const char* value) +{ + YR_OBJECT* object; + YR_EXTERNAL_VARIABLE* external; + + char* id = NULL; + char* val = NULL; + + compiler->last_result = ERROR_SUCCESS; + + FAIL_ON_COMPILER_ERROR(yr_arena_write_string( + compiler->sz_arena, + identifier, + &id)); + + FAIL_ON_COMPILER_ERROR(yr_arena_write_string( + compiler->sz_arena, + value, + &val)); + + FAIL_ON_COMPILER_ERROR(yr_arena_allocate_struct( + compiler->externals_arena, + sizeof(YR_EXTERNAL_VARIABLE), + (void**) &external, + offsetof(YR_EXTERNAL_VARIABLE, identifier), + offsetof(YR_EXTERNAL_VARIABLE, value.s), + EOL)); + + external->type = EXTERNAL_VARIABLE_TYPE_STRING; + external->identifier = id; + external->value.s = val; + + FAIL_ON_COMPILER_ERROR(yr_object_from_external_variable( + external, + &object)); + + FAIL_ON_COMPILER_ERROR(yr_hash_table_add( + compiler->objects_table, + external->identifier, + NULL, + (void*) object)); + + return compiler->last_result; +} + + +YR_API char* yr_compiler_get_error_message( + YR_COMPILER* compiler, + char* buffer, + int buffer_size) +{ + uint32_t max_strings_per_rule; + + switch(compiler->last_error) + { + case ERROR_INSUFFICIENT_MEMORY: + snprintf(buffer, buffer_size, "not enough memory"); + break; + case ERROR_DUPLICATED_IDENTIFIER: + snprintf( + buffer, + buffer_size, + "duplicated identifier \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_DUPLICATED_STRING_IDENTIFIER: + snprintf( + buffer, + buffer_size, + "duplicated string identifier \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_DUPLICATED_TAG_IDENTIFIER: + snprintf( + buffer, + buffer_size, + "duplicated tag identifier \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_DUPLICATED_META_IDENTIFIER: + snprintf( + buffer, + buffer_size, + "duplicated metadata identifier \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_DUPLICATED_LOOP_IDENTIFIER: + snprintf( + buffer, + buffer_size, + "duplicated loop identifier \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_UNDEFINED_STRING: + snprintf( + buffer, + buffer_size, + "undefined string \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_UNDEFINED_IDENTIFIER: + snprintf( + buffer, + buffer_size, + "undefined identifier \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_UNREFERENCED_STRING: + snprintf( + buffer, + buffer_size, + "unreferenced string \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_EMPTY_STRING: + snprintf( + buffer, + buffer_size, + "empty string \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_NOT_A_STRUCTURE: + snprintf( + buffer, + buffer_size, + "\"%s\" is not a structure", + compiler->last_error_extra_info); + break; + case ERROR_NOT_INDEXABLE: + snprintf( + buffer, + buffer_size, + "\"%s\" is not an array or dictionary", + compiler->last_error_extra_info); + break; + case ERROR_NOT_A_FUNCTION: + snprintf( + buffer, + buffer_size, + "\"%s\" is not a function", + compiler->last_error_extra_info); + break; + case ERROR_INVALID_FIELD_NAME: + snprintf( + buffer, + buffer_size, + "invalid field name \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_MISPLACED_ANONYMOUS_STRING: + snprintf( + buffer, + buffer_size, + "wrong use of anonymous string"); + break; + case ERROR_INCLUDES_CIRCULAR_REFERENCE: + snprintf( + buffer, + buffer_size, + "include circular reference"); + break; + case ERROR_INCLUDE_DEPTH_EXCEEDED: + snprintf(buffer, + buffer_size, + "too many levels of included rules"); + break; + case ERROR_LOOP_NESTING_LIMIT_EXCEEDED: + snprintf(buffer, + buffer_size, + "loop nesting limit exceeded"); + break; + case ERROR_NESTED_FOR_OF_LOOP: + snprintf(buffer, + buffer_size, + "'for of ' loops can't be nested"); + break; + case ERROR_UNKNOWN_MODULE: + snprintf( + buffer, + buffer_size, + "unknown module \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_INVALID_MODULE_NAME: + snprintf( + buffer, + buffer_size, + "invalid module name \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_DUPLICATED_STRUCTURE_MEMBER: + snprintf(buffer, + buffer_size, + "duplicated structure member"); + break; + case ERROR_WRONG_ARGUMENTS: + snprintf( + buffer, + buffer_size, + "wrong arguments for function \"%s\"", + compiler->last_error_extra_info); + break; + case ERROR_WRONG_RETURN_TYPE: + snprintf(buffer, + buffer_size, + "wrong return type for overloaded function"); + break; + case ERROR_INVALID_HEX_STRING: + case ERROR_INVALID_REGULAR_EXPRESSION: + case ERROR_SYNTAX_ERROR: + case ERROR_WRONG_TYPE: + snprintf( + buffer, + buffer_size, + "%s", + compiler->last_error_extra_info); + break; + case ERROR_INTERNAL_FATAL_ERROR: + snprintf( + buffer, + buffer_size, + "internal fatal error"); + break; + case ERROR_DIVISION_BY_ZERO: + snprintf( + buffer, + buffer_size, + "division by zero"); + break; + case ERROR_REGULAR_EXPRESSION_TOO_LARGE: + snprintf( + buffer, + buffer_size, + "regular expression is too large"); + break; + case ERROR_REGULAR_EXPRESSION_TOO_COMPLEX: + snprintf( + buffer, + buffer_size, + "regular expression is too complex"); + break; + case ERROR_TOO_MANY_STRINGS: + yr_get_configuration( + YR_CONFIG_MAX_STRINGS_PER_RULE, + &max_strings_per_rule); + snprintf( + buffer, + buffer_size, + "too many strings in rule \"%s\" (limit: %d)", + compiler->last_error_extra_info, + max_strings_per_rule); + break; + case ERROR_INTEGER_OVERFLOW: + snprintf( + buffer, + buffer_size, + "integer overflow in \"%s\"", + compiler->last_error_extra_info); + } + + return buffer; +} diff --git a/yara-master/libyara/crypto.h b/yara-master/libyara/crypto.h new file mode 100644 index 0000000..4a0e5ce --- /dev/null +++ b/yara-master/libyara/crypto.h @@ -0,0 +1,137 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_CRYPTO_H +#define YR_CRYPTO_H + +#define YR_MD5_LEN 16 +#define YR_SHA1_LEN 20 +#define YR_SHA256_LEN 32 + +#if defined(HAVE_LIBCRYPTO) +#include +#include +#include + +typedef MD5_CTX yr_md5_ctx; +typedef SHA_CTX yr_sha1_ctx; +typedef SHA256_CTX yr_sha256_ctx; + +#define yr_md5_init(ctx) \ + MD5_Init(ctx) +#define yr_md5_update(ctx,data,len) \ + MD5_Update(ctx,data,len) +#define yr_md5_final(digest,ctx) \ + MD5_Final(digest,ctx) + +#define yr_sha1_init(ctx) \ + SHA1_Init(ctx) +#define yr_sha1_update(ctx,data,len) \ + SHA1_Update(ctx,data,len) +#define yr_sha1_final(digest,ctx) \ + SHA1_Final(digest,ctx) + +#define yr_sha256_init(ctx) \ + SHA256_Init(ctx) +#define yr_sha256_update(ctx,data,len) \ + SHA256_Update(ctx,data,len) +#define yr_sha256_final(digest,ctx) \ + SHA256_Final(digest,ctx) + +#elif defined(HAVE_WINCRYPT_H) +#include +#include + +HCRYPTPROV yr_cryptprov; + +typedef HCRYPTHASH yr_md5_ctx; +typedef HCRYPTHASH yr_sha1_ctx; +typedef HCRYPTHASH yr_sha256_ctx; + +#define yr_md5_init(ctx) \ + CryptCreateHash(yr_cryptprov, CALG_MD5, 0, 0, ctx) +#define yr_md5_update(ctx,data,len) \ + CryptHashData(*ctx, (const BYTE*)data, len, 0) +#define yr_md5_final(digest,ctx) { \ + DWORD len = YR_MD5_LEN; \ + CryptGetHashParam(*ctx, HP_HASHVAL, digest, &len, 0); \ + CryptDestroyHash(*ctx); \ +} + +#define yr_sha1_init(ctx) \ + CryptCreateHash(yr_cryptprov, CALG_SHA1, 0, 0, ctx) +#define yr_sha1_update(ctx,data,len) \ + CryptHashData(*ctx, (const BYTE*)data, len, 0) +#define yr_sha1_final(digest,ctx) { \ + DWORD len = YR_SHA1_LEN; \ + CryptGetHashParam(*ctx, HP_HASHVAL, digest, &len, 0); \ + CryptDestroyHash(*ctx); \ +} + +#define yr_sha256_init(ctx) \ + CryptCreateHash(yr_cryptprov, CALG_SHA_256, 0, 0, ctx) +#define yr_sha256_update(ctx,data,len) \ + CryptHashData(*ctx, (const BYTE*)data, len, 0) +#define yr_sha256_final(digest,ctx) { \ + DWORD len = YR_SHA256_LEN; \ + CryptGetHashParam(*ctx, HP_HASHVAL, digest, &len, 0); \ + CryptDestroyHash(*ctx); \ +} + +#elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) +#include + +typedef CC_MD5_CTX yr_md5_ctx; +typedef CC_SHA1_CTX yr_sha1_ctx; +typedef CC_SHA256_CTX yr_sha256_ctx; + +#define yr_md5_init(ctx) \ + CC_MD5_Init(ctx) +#define yr_md5_update(ctx,data,len) \ + CC_MD5_Update(ctx, data, len) +#define yr_md5_final(digest,ctx) \ + CC_MD5_Final(digest, ctx) + +#define yr_sha1_init(ctx) \ + CC_SHA1_Init(ctx) +#define yr_sha1_update(ctx,data,len) \ + CC_SHA1_Update(ctx, data, len) +#define yr_sha1_final(digest,ctx) \ + CC_SHA1_Final(digest, ctx) + +#define yr_sha256_init(ctx) \ + CC_SHA256_Init(ctx) +#define yr_sha256_update(ctx,data,len) \ + CC_SHA256_Update(ctx, data, len) +#define yr_sha256_final(digest,ctx) \ + CC_SHA256_Final(digest, ctx) + +#endif + +#endif diff --git a/yara-master/libyara/endian.c b/yara-master/libyara/endian.c new file mode 100644 index 0000000..02fff63 --- /dev/null +++ b/yara-master/libyara/endian.c @@ -0,0 +1,53 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +uint16_t _yr_bswap16(uint16_t x) +{ + return (x >> 8 | x << 8); +} + +uint32_t _yr_bswap32(uint32_t x) +{ + return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)); +} + +uint64_t _yr_bswap64(uint64_t x) +{ + return ((((x) & 0xff00000000000000ull) >> 56) + | (((x) & 0x00ff000000000000ull) >> 40) + | (((x) & 0x0000ff0000000000ull) >> 24) + | (((x) & 0x000000ff00000000ull) >> 8) + | (((x) & 0x00000000ff000000ull) << 8) + | (((x) & 0x0000000000ff0000ull) << 24) + | (((x) & 0x000000000000ff00ull) << 40) + | (((x) & 0x00000000000000ffull) << 56)); +} diff --git a/yara-master/libyara/exception.h b/yara-master/libyara/exception.h new file mode 100644 index 0000000..bffe172 --- /dev/null +++ b/yara-master/libyara/exception.h @@ -0,0 +1,157 @@ +/* +Copyright (c) 2015. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_EXCEPTION_H +#define YR_EXCEPTION_H + +#include + +#if _WIN32 || __CYGWIN__ + +#include +#include + +jmp_buf *exc_jmp_buf[MAX_THREADS]; + +static LONG CALLBACK exception_handler( + PEXCEPTION_POINTERS ExceptionInfo) +{ + int tidx = yr_get_tidx(); + + switch(ExceptionInfo->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_IN_PAGE_ERROR: + case EXCEPTION_ACCESS_VIOLATION: + if (tidx != -1 && exc_jmp_buf[tidx] != NULL) + longjmp(*exc_jmp_buf[tidx], 1); + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +#ifdef _MSC_VER + +#include + +#define YR_TRYCATCH(_do_,_try_clause_,_catch_clause_) \ + do \ + { \ + if (_do_) \ + { \ + __try \ + { _try_clause_ } \ + __except(exception_handler(GetExceptionInformation())) \ + { _catch_clause_ } \ + } \ + else \ + { _try_clause_ } \ + } while(0) + +#else + +#define YR_TRYCATCH(_do_,_try_clause_,_catch_clause_) \ + do \ + { \ + if (_do_) \ + { \ + jmp_buf jb; \ + HANDLE exh = AddVectoredExceptionHandler(1, exception_handler); \ + int tidx = yr_get_tidx(); \ + assert(tidx != -1); \ + exc_jmp_buf[tidx] = &jb; \ + if (setjmp(jb) == 0) \ + { _try_clause_ } \ + else \ + { _catch_clause_ } \ + exc_jmp_buf[tidx] = NULL; \ + RemoveVectoredExceptionHandler(exh); \ + } \ + else \ + { \ + _try_clause_ \ + } \ + } while(0) + +#endif + +#else + +#include +#include + +sigjmp_buf *exc_jmp_buf[MAX_THREADS]; + +static void exception_handler(int sig) { + if (sig == SIGBUS || sig == SIGSEGV) + { + int tidx = yr_get_tidx(); + + if (tidx != -1 && exc_jmp_buf[tidx] != NULL) + siglongjmp(*exc_jmp_buf[tidx], 1); + + assert(FALSE); // We should not reach this point. + } +} + +typedef struct sigaction sa; + +#define YR_TRYCATCH(_do_,_try_clause_, _catch_clause_) \ + do \ + { \ + if (_do_) \ + { \ + struct sigaction old_sigbus_act; \ + struct sigaction old_sigsegv_act; \ + struct sigaction act; \ + act.sa_handler = exception_handler; \ + act.sa_flags = 0; /* SA_ONSTACK? */ \ + sigfillset(&act.sa_mask); \ + sigaction(SIGBUS, &act, &old_sigbus_act); \ + sigaction(SIGSEGV, &act, &old_sigsegv_act); \ + int tidx = yr_get_tidx(); \ + assert(tidx != -1); \ + sigjmp_buf jb; \ + exc_jmp_buf[tidx] = &jb; \ + if (sigsetjmp(jb, 1) == 0) \ + { _try_clause_ } \ + else \ + { _catch_clause_ } \ + exc_jmp_buf[tidx] = NULL; \ + sigaction(SIGBUS, &old_sigbus_act, NULL); \ + sigaction(SIGSEGV, &old_sigsegv_act, NULL); \ + } \ + else \ + { \ + _try_clause_ \ + } \ + } while (0) + +#endif + +#endif diff --git a/yara-master/libyara/exec.c b/yara-master/libyara/exec.c new file mode 100644 index 0000000..54a3614 --- /dev/null +++ b/yara-master/libyara/exec.c @@ -0,0 +1,1202 @@ +/* +Copyright (c) 2013-2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#define _GNU_SOURCE + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + + +#define MEM_SIZE MAX_LOOP_NESTING * LOOP_LOCAL_VARS + + +#define push(x) \ + if (sp < stack_size) \ + { \ + stack[sp++] = (x); \ + } \ + else \ + { \ + result = ERROR_EXEC_STACK_OVERFLOW; \ + stop = TRUE; \ + break; \ + } \ + + +#define pop(x) { assert(sp > 0); x = stack[--sp]; } + +#define is_undef(x) IS_UNDEFINED((x).i) + +#define ensure_defined(x) \ + if (is_undef(x)) \ + { \ + r1.i = UNDEFINED; \ + push(r1); \ + break; \ + } + + +#define little_endian_uint8_t(x) (x) +#define little_endian_int8_t(x) (x) +#define little_endian_uint16_t(x) yr_le16toh(x) +#define little_endian_int16_t(x) yr_le16toh(x) +#define little_endian_uint32_t(x) yr_le32toh(x) +#define little_endian_int32_t(x) yr_le32toh(x) + +#define big_endian_uint8_t(x) (x) +#define big_endian_int8_t(x) (x) +#define big_endian_uint16_t(x) yr_be16toh(x) +#define big_endian_int16_t(x) yr_be16toh(x) +#define big_endian_uint32_t(x) yr_be32toh(x) +#define big_endian_int32_t(x) yr_be32toh(x) + + +#define function_read(type, endianess) \ + int64_t read_##type##_##endianess(YR_MEMORY_BLOCK_ITERATOR* iterator, size_t offset) \ + { \ + YR_MEMORY_BLOCK* block = iterator->first(iterator); \ + while (block != NULL) \ + { \ + if (offset >= block->base && \ + block->size >= sizeof(type) && \ + offset <= block->base + block->size - sizeof(type)) \ + { \ + type result; \ + const uint8_t* data = block->fetch_data(block); \ + if (data == NULL) \ + return UNDEFINED; \ + result = *(type *)(data + offset - block->base); \ + result = endianess##_##type(result); \ + return result; \ + } \ + block = iterator->next(iterator); \ + } \ + return UNDEFINED; \ + }; + + +function_read(uint8_t, little_endian) +function_read(uint16_t, little_endian) +function_read(uint32_t, little_endian) +function_read(int8_t, little_endian) +function_read(int16_t, little_endian) +function_read(int32_t, little_endian) +function_read(uint8_t, big_endian) +function_read(uint16_t, big_endian) +function_read(uint32_t, big_endian) +function_read(int8_t, big_endian) +function_read(int16_t, big_endian) +function_read(int32_t, big_endian) + + +static const uint8_t* jmp_if( + int condition, + const uint8_t* ip) +{ + const uint8_t* result; + + if (condition) + { + result = *(const uint8_t**)(ip); + } + else + { + result = ip + sizeof(uint64_t); + } + + return result; +} + + +int yr_execute_code( + YR_SCAN_CONTEXT* context) +{ + int64_t mem[MEM_SIZE]; + int32_t sp = 0; + + const uint8_t* ip = context->rules->code_start; + + YR_VALUE args[MAX_FUNCTION_ARGS]; + YR_VALUE *stack; + YR_VALUE r1; + YR_VALUE r2; + YR_VALUE r3; + + uint64_t elapsed_time; + + #ifdef PROFILING_ENABLED + uint64_t start_time; + YR_RULE* current_rule = NULL; + #endif + + YR_INIT_RULE_ARGS init_rule_args; + + YR_RULE* rule; + YR_MATCH* match; + YR_OBJECT_FUNCTION* function; + YR_OBJECT** obj_ptr; + YR_ARENA* obj_arena; + + char* identifier; + char* args_fmt; + + int i; + int found; + int count; + int result = ERROR_SUCCESS; + int stop = FALSE; + int cycle = 0; + int tidx = context->tidx; + int stack_size; + + uint8_t opcode; + + yr_get_configuration(YR_CONFIG_STACK_SIZE, (void*) &stack_size); + + stack = (YR_VALUE*) yr_malloc(stack_size * sizeof(YR_VALUE)); + + if (stack == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_arena_create(1024, 0, &obj_arena), + yr_free(stack)); + + #ifdef PROFILING_ENABLED + start_time = yr_stopwatch_elapsed_us(&context->stopwatch); + #endif + + while(!stop) + { + opcode = *ip; + ip++; + + switch(opcode) + { + case OP_NOP: + break; + + case OP_HALT: + assert(sp == 0); // When HALT is reached the stack should be empty. + stop = TRUE; + break; + + case OP_PUSH: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + push(r1); + break; + + case OP_POP: + pop(r1); + break; + + case OP_CLEAR_M: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + mem[r1.i] = 0; + break; + + case OP_ADD_M: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + pop(r2); + if (!is_undef(r2)) + mem[r1.i] += r2.i; + break; + + case OP_INCR_M: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + mem[r1.i]++; + break; + + case OP_PUSH_M: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + r1.i = mem[r1.i]; + push(r1); + break; + + case OP_POP_M: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + pop(r2); + mem[r1.i] = r2.i; + break; + + case OP_SWAPUNDEF: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + pop(r2); + + if (is_undef(r2)) + { + r1.i = mem[r1.i]; + push(r1); + } + else + { + push(r2); + } + break; + + case OP_JNUNDEF: + pop(r1); + push(r1); + + ip = jmp_if(!is_undef(r1), ip); + break; + + case OP_JLE: + pop(r2); + pop(r1); + push(r1); + push(r2); + + ip = jmp_if(r1.i <= r2.i, ip); + break; + + case OP_JTRUE: + pop(r1); + push(r1); + + ip = jmp_if(!is_undef(r1) && r1.i, ip); + break; + + case OP_JFALSE: + pop(r1); + push(r1); + + ip = jmp_if(is_undef(r1) || !r1.i, ip); + break; + + case OP_AND: + pop(r2); + pop(r1); + + if (is_undef(r1) || is_undef(r2)) + r1.i = 0; + else + r1.i = r1.i && r2.i; + + push(r1); + break; + + case OP_OR: + pop(r2); + pop(r1); + + if (is_undef(r1)) + { + push(r2); + } + else if (is_undef(r2)) + { + push(r1); + } + else + { + r1.i = r1.i || r2.i; + push(r1); + } + break; + + case OP_NOT: + pop(r1); + + if (is_undef(r1)) + r1.i = UNDEFINED; + else + r1.i= !r1.i; + + push(r1); + break; + + case OP_MOD: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + if (r2.i != 0) + r1.i = r1.i % r2.i; + else + r1.i = UNDEFINED; + push(r1); + break; + + case OP_SHR: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + if (r2.i < 0) + r1.i = UNDEFINED; + else if (r2.i < 64) + r1.i = r1.i >> r2.i; + else + r1.i = 0; + push(r1); + break; + + case OP_SHL: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + if (r2.i < 0) + r1.i = UNDEFINED; + else if (r2.i < 64) + r1.i = r1.i << r2.i; + else + r1.i = 0; + push(r1); + break; + + case OP_BITWISE_NOT: + pop(r1); + ensure_defined(r1); + r1.i = ~r1.i; + push(r1); + break; + + case OP_BITWISE_AND: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i & r2.i; + push(r1); + break; + + case OP_BITWISE_OR: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i | r2.i; + push(r1); + break; + + case OP_BITWISE_XOR: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i ^ r2.i; + push(r1); + break; + + case OP_PUSH_RULE: + rule = *(YR_RULE**)(ip); + ip += sizeof(uint64_t); + if (RULE_IS_DISABLED(rule)) + r1.i = UNDEFINED; + else + r1.i = rule->t_flags[tidx] & RULE_TFLAGS_MATCH ? 1 : 0; + push(r1); + break; + + case OP_INIT_RULE: + memcpy(&init_rule_args, ip, sizeof(init_rule_args)); + #ifdef PROFILING_ENABLED + current_rule = init_rule_args.rule; + #endif + if (RULE_IS_DISABLED(init_rule_args.rule)) + ip = init_rule_args.jmp_addr; + else + ip += sizeof(init_rule_args); + break; + + case OP_MATCH_RULE: + pop(r1); + rule = *(YR_RULE**)(ip); + ip += sizeof(uint64_t); + + if (!is_undef(r1) && r1.i) + rule->t_flags[tidx] |= RULE_TFLAGS_MATCH; + else if (RULE_IS_GLOBAL(rule)) + rule->ns->t_flags[tidx] |= NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL; + + #ifdef PROFILING_ENABLED + elapsed_time = yr_stopwatch_elapsed_us(&context->stopwatch); + rule->time_cost += (elapsed_time - start_time); + start_time = elapsed_time; + #endif + + assert(sp == 0); // at this point the stack should be empty. + break; + + case OP_OBJ_LOAD: + identifier = *(char**)(ip); + ip += sizeof(uint64_t); + + r1.o = (YR_OBJECT*) yr_hash_table_lookup( + context->objects_table, + identifier, + NULL); + + assert(r1.o != NULL); + push(r1); + break; + + case OP_OBJ_FIELD: + identifier = *(char**)(ip); + ip += sizeof(uint64_t); + + pop(r1); + ensure_defined(r1); + + r1.o = yr_object_lookup_field(r1.o, identifier); + + assert(r1.o != NULL); + push(r1); + break; + + case OP_OBJ_VALUE: + pop(r1); + ensure_defined(r1); + + switch(r1.o->type) + { + case OBJECT_TYPE_INTEGER: + r1.i = r1.o->value.i; + break; + + case OBJECT_TYPE_FLOAT: + if (isnan(r1.o->value.d)) + r1.i = UNDEFINED; + else + r1.d = r1.o->value.d; + break; + + case OBJECT_TYPE_STRING: + if (r1.o->value.ss == NULL) + r1.i = UNDEFINED; + else + r1.ss = r1.o->value.ss; + break; + + default: + assert(FALSE); + } + + push(r1); + break; + + case OP_INDEX_ARRAY: + pop(r1); // index + pop(r2); // array + + ensure_defined(r1); + ensure_defined(r2); + assert(r2.o->type == OBJECT_TYPE_ARRAY); + + r1.o = yr_object_array_get_item(r2.o, 0, (int) r1.i); + + if (r1.o == NULL) + r1.i = UNDEFINED; + + push(r1); + break; + + case OP_LOOKUP_DICT: + pop(r1); // key + pop(r2); // dictionary + + ensure_defined(r1); + ensure_defined(r2); + assert(r2.o->type == OBJECT_TYPE_DICTIONARY); + + r1.o = yr_object_dict_get_item( + r2.o, 0, r1.ss->c_string); + + if (r1.o == NULL) + r1.i = UNDEFINED; + + push(r1); + break; + + case OP_CALL: + args_fmt = *(char**)(ip); + ip += sizeof(uint64_t); + + i = (int) strlen(args_fmt); + count = 0; + + // pop arguments from stack and copy them to args array + + while (i > 0) + { + pop(r1); + + if (is_undef(r1)) // count the number of undefined args + count++; + + args[i - 1] = r1; + i--; + } + + pop(r2); + ensure_defined(r2); + + if (count > 0) + { + // if there are undefined args, result for function call + // is undefined as well. + + r1.i = UNDEFINED; + push(r1); + break; + } + + function = object_as_function(r2.o); + result = ERROR_INTERNAL_FATAL_ERROR; + + for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++) + { + if (function->prototypes[i].arguments_fmt == NULL) + break; + + if (strcmp(function->prototypes[i].arguments_fmt, args_fmt) == 0) + { + result = function->prototypes[i].code(args, context, function); + break; + } + } + + // if i == MAX_OVERLOADED_FUNCTIONS at this point no matching + // prototype was found, but this shouldn't happen. + + assert(i < MAX_OVERLOADED_FUNCTIONS); + + // make a copy of the returned object and push the copy into the stack + // function->return_obj can't be pushed because it can change in + // subsequent calls to the same function. + + if (result == ERROR_SUCCESS) + result = yr_object_copy(function->return_obj, &r1.o); + + // a pointer to the copied object is stored in a arena in order to + // free the object before exiting yr_execute_code + + if (result == ERROR_SUCCESS) + result = yr_arena_write_data(obj_arena, &r1.o, sizeof(r1.o), NULL); + + stop = (result != ERROR_SUCCESS); + push(r1); + break; + + case OP_FOUND: + pop(r1); + r1.i = r1.s->matches[tidx].tail != NULL ? 1 : 0; + push(r1); + break; + + case OP_FOUND_AT: + pop(r2); + pop(r1); + + if (is_undef(r1)) + { + r1.i = 0; + push(r1); + break; + } + + match = r2.s->matches[tidx].head; + r3.i = FALSE; + + while (match != NULL) + { + if (r1.i == match->base + match->offset) + { + r3.i = TRUE; + break; + } + + if (r1.i < match->base + match->offset) + break; + + match = match->next; + } + + push(r3); + break; + + case OP_FOUND_IN: + pop(r3); + pop(r2); + pop(r1); + + ensure_defined(r1); + ensure_defined(r2); + + match = r3.s->matches[tidx].head; + r3.i = FALSE; + + while (match != NULL && !r3.i) + { + if (match->base + match->offset >= r1.i && + match->base + match->offset <= r2.i) + { + r3.i = TRUE; + } + + if (match->base + match->offset > r2.i) + break; + + match = match->next; + } + + push(r3); + break; + + case OP_COUNT: + pop(r1); + r1.i = r1.s->matches[tidx].count; + push(r1); + break; + + case OP_OFFSET: + pop(r2); + pop(r1); + + ensure_defined(r1); + + match = r2.s->matches[tidx].head; + i = 1; + r3.i = UNDEFINED; + + while (match != NULL && r3.i == UNDEFINED) + { + if (r1.i == i) + r3.i = match->base + match->offset; + + i++; + match = match->next; + } + + push(r3); + break; + + case OP_LENGTH: + pop(r2); + pop(r1); + + ensure_defined(r1); + + match = r2.s->matches[tidx].head; + i = 1; + r3.i = UNDEFINED; + + while (match != NULL && r3.i == UNDEFINED) + { + if (r1.i == i) + r3.i = match->match_length; + + i++; + match = match->next; + } + + push(r3); + break; + + case OP_OF: + found = 0; + count = 0; + pop(r1); + + while (!is_undef(r1)) + { + if (r1.s->matches[tidx].tail != NULL) + found++; + count++; + pop(r1); + } + + pop(r2); + + if (is_undef(r2)) + r1.i = found >= count ? 1 : 0; + else + r1.i = found >= r2.i ? 1 : 0; + + push(r1); + break; + + case OP_FILESIZE: + r1.i = context->file_size; + push(r1); + break; + + case OP_ENTRYPOINT: + r1.i = context->entry_point; + push(r1); + break; + + case OP_INT8: + pop(r1); + r1.i = read_int8_t_little_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_INT16: + pop(r1); + r1.i = read_int16_t_little_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_INT32: + pop(r1); + r1.i = read_int32_t_little_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_UINT8: + pop(r1); + r1.i = read_uint8_t_little_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_UINT16: + pop(r1); + r1.i = read_uint16_t_little_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_UINT32: + pop(r1); + r1.i = read_uint32_t_little_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_INT8BE: + pop(r1); + r1.i = read_int8_t_big_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_INT16BE: + pop(r1); + r1.i = read_int16_t_big_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_INT32BE: + pop(r1); + r1.i = read_int32_t_big_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_UINT8BE: + pop(r1); + r1.i = read_uint8_t_big_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_UINT16BE: + pop(r1); + r1.i = read_uint16_t_big_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_UINT32BE: + pop(r1); + r1.i = read_uint32_t_big_endian(context->iterator, (size_t) r1.i); + push(r1); + break; + + case OP_CONTAINS: + pop(r2); + pop(r1); + + ensure_defined(r1); + ensure_defined(r2); + + r1.i = memmem(r1.ss->c_string, r1.ss->length, + r2.ss->c_string, r2.ss->length) != NULL; + push(r1); + break; + + case OP_IMPORT: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + + result = yr_modules_load((char*) r1.p, context); + + if (result != ERROR_SUCCESS) + stop = TRUE; + + break; + + case OP_MATCHES: + + pop(r2); + pop(r1); + + ensure_defined(r2); + ensure_defined(r1); + + if (r1.ss->length == 0) + { + r1.i = FALSE; + push(r1); + break; + } + + result = yr_re_exec( + context, + (uint8_t*) r2.re->code, + (uint8_t*) r1.ss->c_string, + r1.ss->length, + 0, + r2.re->flags | RE_FLAGS_SCAN, + NULL, + NULL, + &found); + + if (result != ERROR_SUCCESS) + stop = TRUE; + + r1.i = found >= 0; + push(r1); + break; + + case OP_INT_TO_DBL: + r1.i = *(uint64_t*)(ip); + ip += sizeof(uint64_t); + r2 = stack[sp - r1.i]; + if (is_undef(r2)) + stack[sp - r1.i].i = UNDEFINED; + else + stack[sp - r1.i].d = (double) r2.i; + break; + + case OP_STR_TO_BOOL: + pop(r1); + ensure_defined(r1); + r1.i = r1.ss->length > 0; + push(r1); + break; + + case OP_INT_EQ: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i == r2.i; + push(r1); + break; + + case OP_INT_NEQ: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i != r2.i; + push(r1); + break; + + case OP_INT_LT: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i < r2.i; + push(r1); + break; + + case OP_INT_GT: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i > r2.i; + push(r1); + break; + + case OP_INT_LE: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i <= r2.i; + push(r1); + break; + + case OP_INT_GE: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i >= r2.i; + push(r1); + break; + + case OP_INT_ADD: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i + r2.i; + push(r1); + break; + + case OP_INT_SUB: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i - r2.i; + push(r1); + break; + + case OP_INT_MUL: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.i * r2.i; + push(r1); + break; + + case OP_INT_DIV: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + if (r2.i != 0) + r1.i = r1.i / r2.i; + else + r1.i = UNDEFINED; + push(r1); + break; + + case OP_INT_MINUS: + pop(r1); + ensure_defined(r1); + r1.i = -r1.i; + push(r1); + break; + + case OP_DBL_LT: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.d < r2.d; + push(r1); + break; + + case OP_DBL_GT: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.d > r2.d; + push(r1); + break; + + case OP_DBL_LE: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.d <= r2.d; + push(r1); + break; + + case OP_DBL_GE: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.d >= r2.d; + push(r1); + break; + + case OP_DBL_EQ: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.d == r2.d; + push(r1); + break; + + case OP_DBL_NEQ: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.i = r1.d != r2.d; + push(r1); + break; + + case OP_DBL_ADD: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.d = r1.d + r2.d; + push(r1); + break; + + case OP_DBL_SUB: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.d = r1.d - r2.d; + push(r1); + break; + + case OP_DBL_MUL: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.d = r1.d * r2.d; + push(r1); + break; + + case OP_DBL_DIV: + pop(r2); + pop(r1); + ensure_defined(r2); + ensure_defined(r1); + r1.d = r1.d / r2.d; + push(r1); + break; + + case OP_DBL_MINUS: + pop(r1); + ensure_defined(r1); + r1.d = -r1.d; + push(r1); + break; + + case OP_STR_EQ: + case OP_STR_NEQ: + case OP_STR_LT: + case OP_STR_LE: + case OP_STR_GT: + case OP_STR_GE: + + pop(r2); + pop(r1); + + ensure_defined(r1); + ensure_defined(r2); + + switch(opcode) + { + case OP_STR_EQ: + r1.i = (sized_string_cmp(r1.ss, r2.ss) == 0); + break; + case OP_STR_NEQ: + r1.i = (sized_string_cmp(r1.ss, r2.ss) != 0); + break; + case OP_STR_LT: + r1.i = (sized_string_cmp(r1.ss, r2.ss) < 0); + break; + case OP_STR_LE: + r1.i = (sized_string_cmp(r1.ss, r2.ss) <= 0); + break; + case OP_STR_GT: + r1.i = (sized_string_cmp(r1.ss, r2.ss) > 0); + break; + case OP_STR_GE: + r1.i = (sized_string_cmp(r1.ss, r2.ss) >= 0); + break; + } + + push(r1); + break; + + default: + // Unknown instruction, this shouldn't happen. + assert(FALSE); + } + + // Check for timeout every 10 instruction cycles. If timeout == 0 it means + // no timeout at all. + + if (context->timeout > 0L && ++cycle == 10) + { + elapsed_time = yr_stopwatch_elapsed_us(&context->stopwatch); + + if (elapsed_time > context->timeout) + { + #ifdef PROFILING_ENABLED + assert(current_rule != NULL); + current_rule->time_cost += elapsed_time - start_time; + #endif + result = ERROR_SCAN_TIMEOUT; + stop = TRUE; + } + + cycle = 0; + } + } + + obj_ptr = (YR_OBJECT**) yr_arena_base_address(obj_arena); + + while (obj_ptr != NULL) + { + yr_object_destroy(*obj_ptr); + + obj_ptr = (YR_OBJECT**) yr_arena_next_address( + obj_arena, obj_ptr, sizeof(YR_OBJECT*)); + } + + yr_arena_destroy(obj_arena); + yr_modules_unload_all(context); + yr_free(stack); + + return result; +} diff --git a/yara-master/libyara/exefiles.c b/yara-master/libyara/exefiles.c new file mode 100644 index 0000000..6216ab7 --- /dev/null +++ b/yara-master/libyara/exefiles.c @@ -0,0 +1,426 @@ +/* +Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#include +#include +#include +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef MIN +#define MIN(x,y) ((x < y)?(x):(y)) +#endif + + +PIMAGE_NT_HEADERS32 yr_get_pe_header( + const uint8_t* buffer, + size_t buffer_length) +{ + PIMAGE_DOS_HEADER mz_header; + PIMAGE_NT_HEADERS32 pe_header; + + size_t headers_size = 0; + + if (buffer_length < sizeof(IMAGE_DOS_HEADER)) + return NULL; + + mz_header = (PIMAGE_DOS_HEADER) buffer; + + if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE) + return NULL; + + if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0) + return NULL; + + headers_size = yr_le32toh(mz_header->e_lfanew) + \ + sizeof(pe_header->Signature) + \ + sizeof(IMAGE_FILE_HEADER); + + if (buffer_length < headers_size) + return NULL; + + pe_header = (PIMAGE_NT_HEADERS32) (buffer + yr_le32toh(mz_header->e_lfanew)); + + headers_size += sizeof(IMAGE_OPTIONAL_HEADER32); + + if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE && + (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 || + yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) && + buffer_length > headers_size) + { + return pe_header; + } + else + { + return NULL; + } +} + + +uint64_t yr_pe_rva_to_offset( + PIMAGE_NT_HEADERS32 pe_header, + uint64_t rva, + size_t buffer_length) +{ + int i = 0; + PIMAGE_SECTION_HEADER section; + DWORD section_rva; + DWORD section_offset; + + section = IMAGE_FIRST_SECTION(pe_header); + section_rva = 0; + section_offset = 0; + + while(i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60)) + { + if ((uint8_t*) section - \ + (uint8_t*) pe_header + sizeof(IMAGE_SECTION_HEADER) < buffer_length) + { + if (rva >= section->VirtualAddress && + section_rva <= yr_le32toh(section->VirtualAddress)) + { + section_rva = yr_le32toh(section->VirtualAddress); + section_offset = yr_le32toh(section->PointerToRawData); + } + + section++; + i++; + } + else + { + return 0; + } + } + + return section_offset + (rva - section_rva); +} + + +int yr_get_elf_type( + const uint8_t* buffer, + size_t buffer_length) +{ + elf_ident_t* elf_ident; + + if (buffer_length < sizeof(elf_ident_t)) + return 0; + + elf_ident = (elf_ident_t*) buffer; + + if (yr_le32toh(elf_ident->magic) != ELF_MAGIC) + { + return 0; + } + + switch (elf_ident->_class) { + case ELF_CLASS_32: + if (buffer_length < sizeof(elf32_header_t)) + { + return 0; + } + break; + case ELF_CLASS_64: + if (buffer_length < sizeof(elf64_header_t)) + { + return 0; + } + break; + default: + /* Unexpected class */ + return 0; + } + + return elf_ident->_class; +} + + +static uint64_t yr_elf_rva_to_offset_32( + elf32_header_t* elf_header, + uint64_t rva, + size_t buffer_length) +{ + // if the binary is an executable then prefer the program headers to resolve + // the offset + if (yr_le16toh(elf_header->type) == ELF_ET_EXEC) + { + int i; + elf32_program_header_t* program; + if (yr_le32toh(elf_header->ph_offset) == 0 || + yr_le16toh(elf_header->ph_entry_count == 0)) + return 0; + + // check to prevent integer wraps + if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) < + sizeof(elf32_program_header_t) * yr_le16toh(elf_header->ph_entry_count)) + return 0; + + // check that 'ph_offset' doesn't wrap when added to the + // size of entries. + if(ULONG_MAX - yr_le32toh(elf_header->ph_offset) < + sizeof(elf32_program_header_t) * yr_le16toh(elf_header->ph_entry_count)) + return 0; + + // ensure we don't exceed the buffer size + if (yr_le32toh(elf_header->ph_offset) + sizeof(elf32_program_header_t) * + yr_le16toh(elf_header->ph_entry_count) > buffer_length) + return 0; + + program = (elf32_program_header_t*) + ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset)); + + for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++) + { + if (rva >= yr_le32toh(program->virt_addr) && + rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size)) + { + return yr_le32toh(program->offset) + (rva - yr_le32toh(program->virt_addr)); + } + + program++; + } + } + else + { + int i; + elf32_section_header_t* section; + + if (yr_le32toh(elf_header->sh_offset) == 0 || + yr_le16toh(elf_header->sh_entry_count == 0)) + return 0; + + // check to prevent integer wraps + + if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) < + sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count)) + return 0; + + // check that 'sh_offset' doesn't wrap when added to the + // size of entries. + + if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) < + sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count)) + return 0; + + if (yr_le32toh(elf_header->sh_offset) + sizeof(elf32_section_header_t) * + yr_le16toh(elf_header->sh_entry_count) > buffer_length) + return 0; + + section = (elf32_section_header_t*) + ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset)); + + for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++) + { + if (yr_le32toh(section->type) != ELF_SHT_NULL && + yr_le32toh(section->type) != ELF_SHT_NOBITS && + rva >= yr_le32toh(section->addr) && + rva < yr_le32toh(section->addr) + yr_le32toh(section->size)) + { + // prevent integer wrapping with the return value + + if (ULONG_MAX - yr_le32toh(section->offset) < (rva - yr_le32toh(section->addr))) + return 0; + else + return yr_le32toh(section->offset) + (rva - yr_le32toh(section->addr)); + } + + section++; + } + } + + return 0; + +} + + +static uint64_t yr_elf_rva_to_offset_64( + elf64_header_t* elf_header, + uint64_t rva, + size_t buffer_length) +{ + // if the binary is an executable then prefer the program headers to resolve + // the offset + if (yr_le16toh(elf_header->type) == ELF_ET_EXEC) + { + int i; + elf64_program_header_t* program; + if (yr_le64toh(elf_header->ph_offset) == 0 || + yr_le16toh(elf_header->ph_entry_count == 0)) + return 0; + + // check that 'ph_offset' doesn't wrap when added to the + // size of entries. + if(ULONG_MAX - yr_le64toh(elf_header->ph_offset) < + sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count)) + return 0; + + // ensure we don't exceed the buffer size + if (yr_le64toh(elf_header->ph_offset) + sizeof(elf64_program_header_t) * + yr_le16toh(elf_header->ph_entry_count) > buffer_length) + return 0; + + program = (elf64_program_header_t*) + ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset)); + + for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++) + { + if (rva >= yr_le64toh(program->virt_addr) && + rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size)) + { + return yr_le64toh(program->offset) + (rva - yr_le64toh(program->virt_addr)); + } + + program++; + } + } + else + { + int i; + elf64_section_header_t* section; + + if (yr_le64toh(elf_header->sh_offset) == 0 || + yr_le16toh(elf_header->sh_entry_count) == 0) + return 0; + + // check that 'sh_offset' doesn't wrap when added to the + // size of entries. + if(ULONG_MAX - yr_le64toh(elf_header->sh_offset) < + sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count)) + return 0; + + if (yr_le64toh(elf_header->sh_offset) + sizeof(elf64_section_header_t) * + yr_le16toh(elf_header->sh_entry_count) > buffer_length) + return 0; + + section = (elf64_section_header_t*) + ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset)); + + for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++) + { + if (yr_le32toh(section->type) != ELF_SHT_NULL && + yr_le32toh(section->type) != ELF_SHT_NOBITS && + rva >= yr_le64toh(section->addr) && + rva < yr_le64toh(section->addr) + yr_le64toh(section->size)) + { + return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr)); + } + + section++; + } + } + + return 0; +} + + +uint64_t yr_get_entry_point_offset( + const uint8_t* buffer, + size_t buffer_length) +{ + PIMAGE_NT_HEADERS32 pe_header; + elf32_header_t* elf_header32; + elf64_header_t* elf_header64; + + pe_header = yr_get_pe_header(buffer, buffer_length); + + if (pe_header != NULL) + { + return yr_pe_rva_to_offset( + pe_header, + yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint), + buffer_length - ((uint8_t*) pe_header - buffer)); + } + + switch(yr_get_elf_type(buffer, buffer_length)) + { + case ELF_CLASS_32: + elf_header32 = (elf32_header_t*) buffer; + return yr_elf_rva_to_offset_32( + elf_header32, + yr_le32toh(elf_header32->entry), + buffer_length); + + case ELF_CLASS_64: + elf_header64 = (elf64_header_t*) buffer; + return yr_elf_rva_to_offset_64( + elf_header64, + yr_le64toh(elf_header64->entry), + buffer_length); + } + + return UNDEFINED; +} + + +uint64_t yr_get_entry_point_address( + const uint8_t* buffer, + size_t buffer_length, + uint64_t base_address) +{ + PIMAGE_NT_HEADERS32 pe_header; + + elf32_header_t* elf_header32; + elf64_header_t* elf_header64; + + pe_header = yr_get_pe_header(buffer, buffer_length); + + // If file is PE but not a DLL. + + if (pe_header != NULL && + !(pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) + return base_address + pe_header->OptionalHeader.AddressOfEntryPoint; + + // If file is executable ELF, not shared library. + + switch(yr_get_elf_type(buffer, buffer_length)) + { + case ELF_CLASS_32: + elf_header32 = (elf32_header_t*) buffer; + + if (elf_header32->type == ELF_ET_EXEC) + return elf_header32->entry; + + break; + + case ELF_CLASS_64: + elf_header64 = (elf64_header_t*) buffer; + + if (elf_header64->type == ELF_ET_EXEC) + return elf_header64->entry; + + break; + } + + return UNDEFINED; +} diff --git a/yara-master/libyara/filemap.c b/yara-master/libyara/filemap.c new file mode 100644 index 0000000..d11705c --- /dev/null +++ b/yara-master/libyara/filemap.c @@ -0,0 +1,386 @@ +/* +Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#else +#include +#include +#include +#endif + +#include +#include + + +// +// yr_filemap_map +// +// Maps a whole file into memory. +// +// Args: +// const char* file_path - Path of the file to map. +// YR_MAPPED_FILE* pmapped_file - Pointer to a YR_MAPPED_FILE that will be +// filled with information about the mapping. +// Returns: +// One of the following error codes: +// ERROR_SUCCESS +// ERROR_INVALID_ARGUMENT +// ERROR_COULD_NOT_OPEN_FILE +// ERROR_COULD_NOT_MAP_FILE +// + +YR_API int yr_filemap_map( + const char* file_path, + YR_MAPPED_FILE* pmapped_file) +{ + return yr_filemap_map_ex(file_path, 0, 0, pmapped_file); +} + +// +// yr_filemap_map_fd +// +// Maps a portion of a file (specified by descriptor) into memory. +// +// Args: +// YR_FILE_DESCRIPTOR file - File descriptor representing the file to +// map +// off_t offset - File offset where the mapping will begin. +// This offset must be multiple of 1MB and not +// greater than the actual file size. +// size_t size - Number of bytes that will be mapped. If +// zero or greater than the actual file size +// all content until the end of the file will +// be mapped. +// YR_MAPPED_FILE* pmapped_file - Pointer to a YR_MAPPED_FILE struct that +// will be filled with the new mapping. +// Returns: +// One of the following error codes: +// ERROR_SUCCESS +// ERROR_INVALID_ARGUMENT +// ERROR_COULD_NOT_OPEN_FILE +// ERROR_COULD_NOT_MAP_FILE +// + +#if defined(_WIN32) || defined(__CYGWIN__) + +YR_API int yr_filemap_map_fd( + YR_FILE_DESCRIPTOR file, + off_t offset, + size_t size, + YR_MAPPED_FILE* pmapped_file) +{ + LARGE_INTEGER fs; + size_t file_size; + + pmapped_file->file = file; + pmapped_file->mapping = NULL; + pmapped_file->data = NULL; + pmapped_file->size = 0; + + // Ensure that offset is aligned to 1MB + if (offset >> 20 << 20 != offset) + return ERROR_INVALID_ARGUMENT; + + if (GetFileSizeEx(pmapped_file->file, &fs)) + { + #ifdef _WIN64 + file_size = fs.QuadPart; + #else + file_size = fs.LowPart; + #endif + } + else + { + pmapped_file->file = INVALID_HANDLE_VALUE; + return ERROR_COULD_NOT_OPEN_FILE; + } + + if (offset > file_size) + return ERROR_COULD_NOT_MAP_FILE; + + if (size == 0) + size = (size_t) (file_size - offset); + + pmapped_file->size = yr_min(size, (size_t) (file_size - offset)); + + if (pmapped_file->size != 0) + { + pmapped_file->mapping = CreateFileMapping( + pmapped_file->file, + NULL, + PAGE_READONLY, + 0, + 0, + NULL); + + if (pmapped_file->mapping == NULL) + { + pmapped_file->file = INVALID_HANDLE_VALUE; + pmapped_file->size = 0; + return ERROR_COULD_NOT_MAP_FILE; + } + + pmapped_file->data = (const uint8_t*) MapViewOfFile( + pmapped_file->mapping, + FILE_MAP_READ, + offset >> 32, + offset & 0xFFFFFFFF, + pmapped_file->size); + + if (pmapped_file->data == NULL) + { + CloseHandle(pmapped_file->mapping); + pmapped_file->mapping = NULL; + pmapped_file->file = INVALID_HANDLE_VALUE; + pmapped_file->size = 0; + return ERROR_COULD_NOT_MAP_FILE; + } + } + else + { + pmapped_file->mapping = NULL; + pmapped_file->data = NULL; + } + + return ERROR_SUCCESS; +} + +#else // POSIX + +YR_API int yr_filemap_map_fd( + YR_FILE_DESCRIPTOR file, + off_t offset, + size_t size, + YR_MAPPED_FILE* pmapped_file) +{ + struct stat st; + + pmapped_file->file = file; + pmapped_file->data = NULL; + pmapped_file->size = 0; + + // Ensure that offset is aligned to 1MB + if (offset >> 20 << 20 != offset) + return ERROR_INVALID_ARGUMENT; + + if (fstat(file, &st) != 0 || S_ISDIR(st.st_mode)) + return ERROR_COULD_NOT_OPEN_FILE; + + if (offset > st.st_size) + return ERROR_COULD_NOT_MAP_FILE; + + if (size == 0) + size = (size_t) (st.st_size - offset); + + pmapped_file->size = yr_min(size, (size_t) (st.st_size - offset)); + + if (pmapped_file->size != 0) + { + pmapped_file->data = (const uint8_t*) mmap( + 0, + pmapped_file->size, + PROT_READ, + MAP_PRIVATE, + pmapped_file->file, + offset); + + if (pmapped_file->data == MAP_FAILED) + { + pmapped_file->data = NULL; + pmapped_file->size = 0; + pmapped_file->file = -1; + + return ERROR_COULD_NOT_MAP_FILE; + } + + madvise((void*) pmapped_file->data, pmapped_file->size, MADV_SEQUENTIAL); + } + else + { + pmapped_file->data = NULL; + } + + return ERROR_SUCCESS; +} + +#endif + +// +// yr_filemap_map_ex +// +// Maps a portion of a file (specified by path) into memory. +// +// Args: +// const char* file_path - Path of the file to map. +// off_t offset - File offset where the mapping will begin. +// This offset must be multiple of 1MB and not +// greater than the actual file size. +// size_t size - Number of bytes that will be mapped. If +// zero or greater than the actual file size +// all content until the end of the file will +// be mapped. +// YR_MAPPED_FILE* pmapped_file - Pointer to a YR_MAPPED_FILE struct that +// will be filled with the new mapping. +// Returns: +// One of the following error codes: +// ERROR_SUCCESS +// ERROR_INVALID_ARGUMENT +// ERROR_COULD_NOT_OPEN_FILE +// ERROR_COULD_NOT_MAP_FILE +// + +#if defined(_WIN32) || defined(__CYGWIN__) + +YR_API int yr_filemap_map_ex( + const char* file_path, + off_t offset, + size_t size, + YR_MAPPED_FILE* pmapped_file) +{ + YR_FILE_DESCRIPTOR fd; + int result; + + if (file_path == NULL) + return ERROR_INVALID_ARGUMENT; + + fd = CreateFileA( + file_path, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (fd == INVALID_HANDLE_VALUE) + return ERROR_COULD_NOT_OPEN_FILE; + + result = yr_filemap_map_fd(fd, offset, size, pmapped_file); + + if (result != ERROR_SUCCESS) + CloseHandle(fd); + + return result; +} + +#else // POSIX + +YR_API int yr_filemap_map_ex( + const char* file_path, + off_t offset, + size_t size, + YR_MAPPED_FILE* pmapped_file) +{ + YR_FILE_DESCRIPTOR fd; + int result; + + if (file_path == NULL) + return ERROR_INVALID_ARGUMENT; + + fd = open(file_path, O_RDONLY); + + if (fd == -1) + return ERROR_COULD_NOT_OPEN_FILE; + + result = yr_filemap_map_fd(fd, offset, size, pmapped_file); + + if (result != ERROR_SUCCESS) + close(fd); + + return result; +} + +#endif + + +// +// yr_filemap_unmap +// +// Unmaps a file mapping. +// +// Args: +// YR_MAPPED_FILE* pmapped_file - Pointer to a YR_MAPPED_FILE that struct. +// + +#ifdef WIN32 + +YR_API void yr_filemap_unmap_fd( + YR_MAPPED_FILE* pmapped_file) +{ + if (pmapped_file->data != NULL) + UnmapViewOfFile(pmapped_file->data); + + if (pmapped_file->mapping != NULL) + CloseHandle(pmapped_file->mapping); + + pmapped_file->mapping = NULL; + pmapped_file->data = NULL; + pmapped_file->size = 0; +} + +YR_API void yr_filemap_unmap( + YR_MAPPED_FILE* pmapped_file) +{ + yr_filemap_unmap_fd(pmapped_file); + + if (pmapped_file->file != INVALID_HANDLE_VALUE) + { + CloseHandle(pmapped_file->file); + pmapped_file->file = INVALID_HANDLE_VALUE; + } +} + +#else // POSIX + +YR_API void yr_filemap_unmap_fd( + YR_MAPPED_FILE* pmapped_file) +{ + if (pmapped_file->data != NULL) + munmap((void*) pmapped_file->data, pmapped_file->size); + + pmapped_file->data = NULL; + pmapped_file->size = 0; +} + +YR_API void yr_filemap_unmap( + YR_MAPPED_FILE* pmapped_file) +{ + yr_filemap_unmap_fd(pmapped_file); + + if (pmapped_file->file != -1) + { + close(pmapped_file->file); + pmapped_file->file = -1; + } +} + +#endif diff --git a/yara-master/libyara/grammar.c b/yara-master/libyara/grammar.c new file mode 100644 index 0000000..a54117e --- /dev/null +++ b/yara-master/libyara/grammar.c @@ -0,0 +1,4013 @@ +/* A Bison parser, made by GNU Bison 3.0.4.18-9674. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4.18-9674" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse yara_yyparse +#define yylex yara_yylex +#define yyerror yara_yyerror +#define yydebug yara_yydebug +#define yynerrs yara_yynerrs + + +/* Copy the first part of user declarations. */ +#line 30 "grammar.y" /* yacc.c:339 */ + + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#define llabs _abs64 +#endif + +#define YYERROR_VERBOSE + +#define YYMALLOC yr_malloc +#define YYFREE yr_free + +#define INTEGER_SET_ENUMERATION 1 +#define INTEGER_SET_RANGE 2 + +#define fail_if(x) \ + if (x) \ + { \ + yyerror(yyscanner, compiler, NULL); \ + YYERROR; \ + } \ + + +#define check_type_with_cleanup(expression, expected_type, op, cleanup) \ + if (((expression.type) & (expected_type)) == 0) \ + { \ + switch(expression.type) \ + { \ + case EXPRESSION_TYPE_INTEGER: \ + yr_compiler_set_error_extra_info( \ + compiler, "wrong type \"integer\" for " op " operator"); \ + break; \ + case EXPRESSION_TYPE_FLOAT: \ + yr_compiler_set_error_extra_info( \ + compiler, "wrong type \"float\" for " op " operator"); \ + break; \ + case EXPRESSION_TYPE_STRING: \ + yr_compiler_set_error_extra_info( \ + compiler, "wrong type \"string\" for " op " operator"); \ + break; \ + case EXPRESSION_TYPE_BOOLEAN: \ + yr_compiler_set_error_extra_info( \ + compiler, "wrong type \"boolean\" for " op " operator"); \ + break; \ + } \ + cleanup; \ + compiler->last_result = ERROR_WRONG_TYPE; \ + yyerror(yyscanner, compiler, NULL); \ + YYERROR; \ + } + + +#define check_type(expression, expected_type, op) \ + check_type_with_cleanup(expression, expected_type, op, ) + + +#line 148 "grammar.c" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "y.tab.h". */ +#ifndef YY_YARA_YY_GRAMMAR_H_INCLUDED +# define YY_YARA_YY_GRAMMAR_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yara_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + _DOT_DOT_ = 258, + _RULE_ = 259, + _PRIVATE_ = 260, + _GLOBAL_ = 261, + _META_ = 262, + _STRINGS_ = 263, + _CONDITION_ = 264, + _IDENTIFIER_ = 265, + _STRING_IDENTIFIER_ = 266, + _STRING_COUNT_ = 267, + _STRING_OFFSET_ = 268, + _STRING_LENGTH_ = 269, + _STRING_IDENTIFIER_WITH_WILDCARD_ = 270, + _NUMBER_ = 271, + _DOUBLE_ = 272, + _INTEGER_FUNCTION_ = 273, + _TEXT_STRING_ = 274, + _HEX_STRING_ = 275, + _REGEXP_ = 276, + _ASCII_ = 277, + _WIDE_ = 278, + _XOR_ = 279, + _NOCASE_ = 280, + _FULLWORD_ = 281, + _AT_ = 282, + _FILESIZE_ = 283, + _ENTRYPOINT_ = 284, + _ALL_ = 285, + _ANY_ = 286, + _IN_ = 287, + _OF_ = 288, + _FOR_ = 289, + _THEM_ = 290, + _MATCHES_ = 291, + _CONTAINS_ = 292, + _IMPORT_ = 293, + _TRUE_ = 294, + _FALSE_ = 295, + _OR_ = 296, + _AND_ = 297, + _EQ_ = 298, + _NEQ_ = 299, + _LT_ = 300, + _LE_ = 301, + _GT_ = 302, + _GE_ = 303, + _SHIFT_LEFT_ = 304, + _SHIFT_RIGHT_ = 305, + _NOT_ = 306, + UNARY_MINUS = 307 + }; +#endif +/* Tokens. */ +#define _DOT_DOT_ 258 +#define _RULE_ 259 +#define _PRIVATE_ 260 +#define _GLOBAL_ 261 +#define _META_ 262 +#define _STRINGS_ 263 +#define _CONDITION_ 264 +#define _IDENTIFIER_ 265 +#define _STRING_IDENTIFIER_ 266 +#define _STRING_COUNT_ 267 +#define _STRING_OFFSET_ 268 +#define _STRING_LENGTH_ 269 +#define _STRING_IDENTIFIER_WITH_WILDCARD_ 270 +#define _NUMBER_ 271 +#define _DOUBLE_ 272 +#define _INTEGER_FUNCTION_ 273 +#define _TEXT_STRING_ 274 +#define _HEX_STRING_ 275 +#define _REGEXP_ 276 +#define _ASCII_ 277 +#define _WIDE_ 278 +#define _XOR_ 279 +#define _NOCASE_ 280 +#define _FULLWORD_ 281 +#define _AT_ 282 +#define _FILESIZE_ 283 +#define _ENTRYPOINT_ 284 +#define _ALL_ 285 +#define _ANY_ 286 +#define _IN_ 287 +#define _OF_ 288 +#define _FOR_ 289 +#define _THEM_ 290 +#define _MATCHES_ 291 +#define _CONTAINS_ 292 +#define _IMPORT_ 293 +#define _TRUE_ 294 +#define _FALSE_ 295 +#define _OR_ 296 +#define _AND_ 297 +#define _EQ_ 298 +#define _NEQ_ 299 +#define _LT_ 300 +#define _LE_ 301 +#define _GT_ 302 +#define _GE_ 303 +#define _SHIFT_LEFT_ 304 +#define _SHIFT_RIGHT_ 305 +#define _NOT_ 306 +#define UNARY_MINUS 307 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 216 "grammar.y" /* yacc.c:355 */ + + EXPRESSION expression; + SIZED_STRING* sized_string; + char* c_string; + int64_t integer; + double double_; + YR_STRING* string; + YR_META* meta; + YR_RULE* rule; + +#line 303 "grammar.c" /* yacc.c:355 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int yara_yyparse (void *yyscanner, YR_COMPILER* compiler); + +#endif /* !YY_YARA_YY_GRAMMAR_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + +#line 319 "grammar.c" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 396 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 73 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 41 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 123 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 211 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 308 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 58, 45, 2, + 70, 71, 56, 54, 72, 55, 67, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 65, 2, + 2, 66, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 68, 57, 69, 44, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 63, 43, 64, 60, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 46, 47, + 48, 49, 50, 51, 52, 53, 59, 61, 62 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 230, 230, 232, 233, 234, 235, 236, 241, 254, + 263, 253, 286, 289, 317, 320, 347, 352, 353, 358, + 359, 365, 368, 386, 399, 436, 437, 442, 458, 471, + 484, 497, 514, 515, 521, 520, 536, 535, 551, 565, + 566, 571, 572, 573, 574, 575, 580, 665, 711, 769, + 814, 815, 819, 846, 884, 926, 948, 957, 966, 981, + 993, 1007, 1020, 1031, 1042, 1072, 1041, 1186, 1185, 1264, + 1270, 1277, 1276, 1330, 1329, 1381, 1390, 1399, 1408, 1417, + 1426, 1435, 1439, 1447, 1448, 1453, 1475, 1487, 1503, 1502, + 1508, 1519, 1520, 1525, 1532, 1543, 1544, 1548, 1556, 1560, + 1570, 1584, 1600, 1610, 1619, 1644, 1656, 1668, 1684, 1696, + 1712, 1757, 1776, 1811, 1846, 1880, 1905, 1923, 1933, 1943, + 1953, 1963, 1981, 1999 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "_DOT_DOT_", "_RULE_", "_PRIVATE_", + "_GLOBAL_", "_META_", "_STRINGS_", "_CONDITION_", "_IDENTIFIER_", + "_STRING_IDENTIFIER_", "_STRING_COUNT_", "_STRING_OFFSET_", + "_STRING_LENGTH_", "_STRING_IDENTIFIER_WITH_WILDCARD_", "_NUMBER_", + "_DOUBLE_", "_INTEGER_FUNCTION_", "_TEXT_STRING_", "_HEX_STRING_", + "_REGEXP_", "_ASCII_", "_WIDE_", "_XOR_", "_NOCASE_", "_FULLWORD_", + "_AT_", "_FILESIZE_", "_ENTRYPOINT_", "_ALL_", "_ANY_", "_IN_", "_OF_", + "_FOR_", "_THEM_", "_MATCHES_", "_CONTAINS_", "_IMPORT_", "_TRUE_", + "_FALSE_", "_OR_", "_AND_", "'|'", "'^'", "'&'", "_EQ_", "_NEQ_", "_LT_", + "_LE_", "_GT_", "_GE_", "_SHIFT_LEFT_", "_SHIFT_RIGHT_", "'+'", "'-'", + "'*'", "'\\\\'", "'%'", "_NOT_", "'~'", "UNARY_MINUS", "\"include\"", + "'{'", "'}'", "':'", "'='", "'.'", "'['", "']'", "'('", "')'", "','", + "$accept", "rules", "import", "rule", "@1", "$@2", "meta", "strings", + "condition", "rule_modifiers", "rule_modifier", "tags", "tag_list", + "meta_declarations", "meta_declaration", "string_declarations", + "string_declaration", "$@3", "$@4", "string_modifiers", + "string_modifier", "identifier", "arguments", "arguments_list", "regexp", + "boolean_expression", "expression", "$@5", "$@6", "$@7", "$@8", "$@9", + "integer_set", "range", "integer_enumeration", "string_set", "$@10", + "string_enumeration", "string_enumeration_item", "for_expression", + "primary_expression", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 124, 94, 38, 298, 299, 300, 301, + 302, 303, 304, 305, 43, 45, 42, 92, 37, 306, + 126, 307, 308, 123, 125, 58, 61, 46, 91, 93, + 40, 41, 44 +}; +# endif + +#define YYPACT_NINF -73 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-73))) + +#define YYTABLE_NINF -96 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + -73, 90, -73, -33, -16, -73, -73, 69, -73, -73, + -73, -73, 5, -73, -73, -73, -73, -42, 44, -38, + -73, 60, 61, -73, 21, 72, 79, 41, -73, 64, + 79, -73, 129, 141, 16, -73, 85, 129, -73, 80, + 96, -73, -73, -73, -73, 145, 81, -73, 48, -73, + -73, -73, 143, 150, -73, -10, -73, 104, 111, -73, + -73, 114, -73, -73, -73, -73, -73, -73, 103, -73, + -73, 125, 48, 125, 48, -34, -73, 68, -73, 148, + 293, -73, -73, 125, 116, 125, 125, 125, 125, 71, + 309, -73, -73, -73, 68, 133, 170, 172, 125, 48, + -73, -73, -7, 184, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 152, 152, 309, 125, -73, 230, 248, 112, 190, + -73, 176, -7, -73, -73, -73, 266, 138, 139, 70, + 48, 48, -73, -73, -73, -73, 309, 324, 338, -44, + 309, 309, 309, 309, 309, 309, 136, 136, 27, 27, + -73, -73, -73, -73, -73, -73, -73, -73, -73, 144, + -73, -73, -73, -73, 147, -73, -73, 48, 168, -73, + 15, 125, 159, -73, 70, -73, -73, 54, -73, 210, + 125, 165, -73, 161, -73, 15, -73, 77, 144, -73, + 48, -73, -73, 125, 162, 56, 309, 48, -73, 58, + -73 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 2, 0, 1, 17, 0, 4, 3, 0, 7, 6, + 5, 8, 0, 19, 20, 18, 9, 21, 0, 0, + 23, 22, 12, 24, 0, 14, 0, 0, 10, 0, + 13, 25, 0, 0, 0, 26, 0, 15, 32, 0, + 0, 28, 27, 30, 31, 0, 34, 33, 0, 11, + 29, 38, 0, 0, 46, 60, 105, 107, 109, 102, + 103, 0, 104, 54, 99, 100, 96, 97, 0, 56, + 57, 0, 0, 0, 0, 110, 123, 16, 55, 0, + 81, 39, 39, 0, 0, 0, 0, 0, 0, 0, + 95, 111, 70, 120, 0, 55, 81, 0, 0, 50, + 73, 71, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 35, 37, 61, 0, 62, 0, 0, 0, 0, + 63, 0, 0, 82, 98, 47, 0, 0, 51, 52, + 0, 0, 90, 88, 69, 58, 59, 119, 117, 118, + 79, 80, 75, 77, 76, 78, 121, 122, 112, 113, + 114, 115, 116, 42, 41, 45, 43, 44, 40, 0, + 106, 108, 101, 64, 0, 48, 49, 0, 74, 72, + 0, 0, 0, 67, 53, 93, 94, 0, 91, 0, + 0, 0, 84, 0, 89, 0, 85, 0, 86, 65, + 0, 92, 83, 0, 0, 0, 87, 0, 68, 0, + 66 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -73, -73, 233, 234, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, 208, -73, 202, -73, -73, 158, + -73, -73, -73, -73, 146, -48, -72, -73, -73, -73, + -73, -73, -73, 74, -73, 118, -73, -73, 57, 183, + -67 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 5, 6, 17, 33, 25, 28, 40, 7, + 15, 19, 21, 30, 31, 37, 38, 52, 53, 121, + 168, 75, 137, 138, 76, 94, 78, 182, 204, 193, + 141, 140, 191, 125, 197, 144, 180, 187, 188, 79, + 80 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 77, 90, 95, 11, 91, 4, 93, 96, 114, 115, + 116, 117, 118, 119, 120, 16, 123, 83, 126, 127, + 128, 129, 84, 18, 92, 22, 185, 139, 142, 8, + 186, 136, 41, 97, 98, 42, 99, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 20, 43, 44, 169, 54, 55, + 56, 57, 58, 143, 59, 60, 61, 62, 24, 63, + 23, 45, 130, 12, 13, 14, 64, 65, 66, 67, + 27, 131, 68, 118, 119, 120, 26, 69, 70, 29, + 2, 3, 178, 179, -17, -17, -17, 100, 101, 100, + 101, 51, -36, 71, 132, 184, 32, 72, 73, 100, + 101, -55, -55, 54, 189, 56, 57, 58, 74, 59, + 60, 61, 62, 198, 63, 194, 195, 208, 4, 210, + 34, 64, 65, 66, 67, 54, 206, 56, 57, 58, + 36, 59, 60, 61, 62, 48, 63, 181, 202, 203, + 39, 46, 205, 64, 65, 105, 106, 107, 71, 209, + 49, 50, 81, 73, 114, 115, 116, 117, 118, 119, + 120, 82, 85, 88, 163, 164, 165, 166, 167, 86, + 71, 102, 135, 172, 87, 73, 124, 105, 106, 107, + 116, 117, 118, 119, 120, 88, 114, 115, 116, 117, + 118, 119, 120, -95, 133, 63, 103, 104, 173, 176, + 101, 177, 183, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 190, + 199, 200, 207, 105, 106, 107, 9, 10, 35, 47, + 122, 134, 114, 115, 116, 117, 118, 119, 120, 145, + 174, 89, 201, 105, 106, 107, 192, 0, 0, 0, + 0, 134, 114, 115, 116, 117, 118, 119, 120, 0, + 0, 0, 0, 105, 106, 107, 0, 0, 0, 0, + 0, 196, 114, 115, 116, 117, 118, 119, 120, 0, + 0, 105, 106, 107, 0, 0, 0, 0, 0, 170, + 114, 115, 116, 117, 118, 119, 120, 0, 0, 105, + 106, 107, 0, 0, 0, 0, 0, 171, 114, 115, + 116, 117, 118, 119, 120, 0, -95, 0, 0, 103, + 104, 0, 0, 0, 0, 175, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 105, 106, 107, 0, 0, 0, 0, 0, + 0, 114, 115, 116, 117, 118, 119, 120, 106, 107, + 0, 0, 0, 0, 0, 0, 114, 115, 116, 117, + 118, 119, 120, 107, 0, 0, 0, 0, 0, 0, + 114, 115, 116, 117, 118, 119, 120 +}; + +static const yytype_int16 yycheck[] = +{ + 48, 68, 74, 19, 71, 38, 73, 74, 52, 53, + 54, 55, 56, 57, 58, 10, 83, 27, 85, 86, + 87, 88, 32, 65, 72, 63, 11, 99, 35, 62, + 15, 98, 16, 67, 68, 19, 70, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 10, 39, 40, 124, 10, 11, + 12, 13, 14, 70, 16, 17, 18, 19, 7, 21, + 10, 55, 1, 4, 5, 6, 28, 29, 30, 31, + 8, 10, 34, 56, 57, 58, 65, 39, 40, 10, + 0, 1, 140, 141, 4, 5, 6, 41, 42, 41, + 42, 20, 21, 55, 33, 177, 65, 59, 60, 41, + 42, 41, 42, 10, 181, 12, 13, 14, 70, 16, + 17, 18, 19, 190, 21, 71, 72, 71, 38, 71, + 66, 28, 29, 30, 31, 10, 203, 12, 13, 14, + 11, 16, 17, 18, 19, 65, 21, 3, 71, 72, + 9, 66, 200, 28, 29, 43, 44, 45, 55, 207, + 64, 16, 19, 60, 52, 53, 54, 55, 56, 57, + 58, 21, 68, 70, 22, 23, 24, 25, 26, 68, + 55, 33, 10, 71, 70, 60, 70, 43, 44, 45, + 54, 55, 56, 57, 58, 70, 52, 53, 54, 55, + 56, 57, 58, 33, 71, 21, 36, 37, 32, 71, + 42, 72, 65, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 70, + 65, 70, 70, 43, 44, 45, 3, 3, 30, 37, + 82, 71, 52, 53, 54, 55, 56, 57, 58, 103, + 132, 68, 195, 43, 44, 45, 182, -1, -1, -1, + -1, 71, 52, 53, 54, 55, 56, 57, 58, -1, + -1, -1, -1, 43, 44, 45, -1, -1, -1, -1, + -1, 71, 52, 53, 54, 55, 56, 57, 58, -1, + -1, 43, 44, 45, -1, -1, -1, -1, -1, 69, + 52, 53, 54, 55, 56, 57, 58, -1, -1, 43, + 44, 45, -1, -1, -1, -1, -1, 69, 52, 53, + 54, 55, 56, 57, 58, -1, 33, -1, -1, 36, + 37, -1, -1, -1, -1, 69, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 43, 44, 45, -1, -1, -1, -1, -1, + -1, 52, 53, 54, 55, 56, 57, 58, 44, 45, + -1, -1, -1, -1, -1, -1, 52, 53, 54, 55, + 56, 57, 58, 45, -1, -1, -1, -1, -1, -1, + 52, 53, 54, 55, 56, 57, 58 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 74, 0, 1, 38, 75, 76, 82, 62, 75, + 76, 19, 4, 5, 6, 83, 10, 77, 65, 84, + 10, 85, 63, 10, 7, 79, 65, 8, 80, 10, + 86, 87, 65, 78, 66, 87, 11, 88, 89, 9, + 81, 16, 19, 39, 40, 55, 66, 89, 65, 64, + 16, 20, 90, 91, 10, 11, 12, 13, 14, 16, + 17, 18, 19, 21, 28, 29, 30, 31, 34, 39, + 40, 55, 59, 60, 70, 94, 97, 98, 99, 112, + 113, 19, 21, 27, 32, 68, 68, 70, 70, 112, + 113, 113, 98, 113, 98, 99, 113, 67, 68, 70, + 41, 42, 33, 36, 37, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 92, 92, 113, 70, 106, 113, 113, 113, 113, + 1, 10, 33, 71, 71, 10, 113, 95, 96, 99, + 104, 103, 35, 70, 108, 97, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 22, 23, 24, 25, 26, 93, 113, + 69, 69, 71, 32, 108, 69, 71, 72, 98, 98, + 109, 3, 100, 65, 99, 11, 15, 110, 111, 113, + 70, 105, 106, 102, 71, 72, 71, 107, 113, 65, + 70, 111, 71, 72, 101, 98, 113, 70, 71, 98, + 71 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 73, 74, 74, 74, 74, 74, 74, 75, 77, + 78, 76, 79, 79, 80, 80, 81, 82, 82, 83, + 83, 84, 84, 85, 85, 86, 86, 87, 87, 87, + 87, 87, 88, 88, 90, 89, 91, 89, 89, 92, + 92, 93, 93, 93, 93, 93, 94, 94, 94, 94, + 95, 95, 96, 96, 97, 98, 99, 99, 99, 99, + 99, 99, 99, 99, 100, 101, 99, 102, 99, 99, + 99, 103, 99, 104, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 105, 105, 106, 107, 107, 109, 108, + 108, 110, 110, 111, 111, 112, 112, 112, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 2, 2, 3, 3, 3, 2, 0, + 0, 11, 0, 3, 0, 3, 3, 0, 2, 1, + 1, 0, 2, 1, 2, 1, 2, 3, 3, 4, + 3, 3, 1, 2, 0, 5, 0, 5, 3, 0, + 2, 1, 1, 1, 1, 1, 1, 3, 4, 4, + 0, 1, 1, 3, 1, 1, 1, 1, 3, 3, + 1, 3, 3, 3, 0, 0, 11, 0, 9, 3, + 2, 0, 4, 0, 4, 3, 3, 3, 3, 3, + 3, 1, 3, 3, 1, 5, 1, 3, 0, 4, + 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, + 1, 4, 1, 1, 1, 1, 4, 1, 4, 1, + 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 3, 3, 1 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (yyscanner, compiler, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, yyscanner, compiler); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *yyscanner, YR_COMPILER* compiler) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (yyscanner); + YYUSE (compiler); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *yyscanner, YR_COMPILER* compiler) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yyscanner, compiler); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, void *yyscanner, YR_COMPILER* compiler) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , yyscanner, compiler); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, yyscanner, compiler); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *yyscanner, YR_COMPILER* compiler) +{ + YYUSE (yyvaluep); + YYUSE (yyscanner); + YYUSE (compiler); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + switch (yytype) + { + case 10: /* _IDENTIFIER_ */ +#line 203 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } +#line 1351 "grammar.c" /* yacc.c:1257 */ + break; + + case 11: /* _STRING_IDENTIFIER_ */ +#line 207 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } +#line 1357 "grammar.c" /* yacc.c:1257 */ + break; + + case 12: /* _STRING_COUNT_ */ +#line 204 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } +#line 1363 "grammar.c" /* yacc.c:1257 */ + break; + + case 13: /* _STRING_OFFSET_ */ +#line 205 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } +#line 1369 "grammar.c" /* yacc.c:1257 */ + break; + + case 14: /* _STRING_LENGTH_ */ +#line 206 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } +#line 1375 "grammar.c" /* yacc.c:1257 */ + break; + + case 15: /* _STRING_IDENTIFIER_WITH_WILDCARD_ */ +#line 208 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } +#line 1381 "grammar.c" /* yacc.c:1257 */ + break; + + case 19: /* _TEXT_STRING_ */ +#line 209 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).sized_string)); ((*yyvaluep).sized_string) = NULL; } +#line 1387 "grammar.c" /* yacc.c:1257 */ + break; + + case 20: /* _HEX_STRING_ */ +#line 210 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).sized_string)); ((*yyvaluep).sized_string) = NULL; } +#line 1393 "grammar.c" /* yacc.c:1257 */ + break; + + case 21: /* _REGEXP_ */ +#line 211 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).sized_string)); ((*yyvaluep).sized_string) = NULL; } +#line 1399 "grammar.c" /* yacc.c:1257 */ + break; + + case 95: /* arguments */ +#line 213 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } +#line 1405 "grammar.c" /* yacc.c:1257 */ + break; + + case 96: /* arguments_list */ +#line 214 "grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } +#line 1411 "grammar.c" /* yacc.c:1257 */ + break; + + + default: + break; + } + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void *yyscanner, YR_COMPILER* compiler) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, yyscanner, compiler); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 8: +#line 242 "grammar.y" /* yacc.c:1662 */ + { + int result = yr_parser_reduce_import(yyscanner, (yyvsp[0].sized_string)); + + yr_free((yyvsp[0].sized_string)); + + fail_if(result != ERROR_SUCCESS); + } +#line 1685 "grammar.c" /* yacc.c:1662 */ + break; + + case 9: +#line 254 "grammar.y" /* yacc.c:1662 */ + { + YR_RULE* rule = yr_parser_reduce_rule_declaration_phase_1( + yyscanner, (int32_t) (yyvsp[-2].integer), (yyvsp[0].c_string)); + + fail_if(rule == NULL); + + (yyval.rule) = rule; + } +#line 1698 "grammar.c" /* yacc.c:1662 */ + break; + + case 10: +#line 263 "grammar.y" /* yacc.c:1662 */ + { + YR_RULE* rule = (yyvsp[-4].rule); // rule created in phase 1 + + rule->tags = (yyvsp[-3].c_string); + rule->metas = (yyvsp[-1].meta); + rule->strings = (yyvsp[0].string); + } +#line 1710 "grammar.c" /* yacc.c:1662 */ + break; + + case 11: +#line 271 "grammar.y" /* yacc.c:1662 */ + { + YR_RULE* rule = (yyvsp[-7].rule); // rule created in phase 1 + + compiler->last_result = yr_parser_reduce_rule_declaration_phase_2( + yyscanner, rule); + + yr_free((yyvsp[-8].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 1725 "grammar.c" /* yacc.c:1662 */ + break; + + case 12: +#line 286 "grammar.y" /* yacc.c:1662 */ + { + (yyval.meta) = NULL; + } +#line 1733 "grammar.c" /* yacc.c:1662 */ + break; + + case 13: +#line 290 "grammar.y" /* yacc.c:1662 */ + { + // Each rule have a list of meta-data info, consisting in a + // sequence of YR_META structures. The last YR_META structure does + // not represent a real meta-data, it's just a end-of-list marker + // identified by a specific type (META_TYPE_NULL). Here we + // write the end-of-list marker. + + YR_META null_meta; + + memset(&null_meta, 0xFF, sizeof(YR_META)); + null_meta.type = META_TYPE_NULL; + + compiler->last_result = yr_arena_write_data( + compiler->metas_arena, + &null_meta, + sizeof(YR_META), + NULL); + + (yyval.meta) = (yyvsp[0].meta); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 1760 "grammar.c" /* yacc.c:1662 */ + break; + + case 14: +#line 317 "grammar.y" /* yacc.c:1662 */ + { + (yyval.string) = NULL; + } +#line 1768 "grammar.c" /* yacc.c:1662 */ + break; + + case 15: +#line 321 "grammar.y" /* yacc.c:1662 */ + { + // Each rule have a list of strings, consisting in a sequence + // of YR_STRING structures. The last YR_STRING structure does not + // represent a real string, it's just a end-of-list marker + // identified by a specific flag (STRING_FLAGS_NULL). Here we + // write the end-of-list marker. + + YR_STRING null_string; + + memset(&null_string, 0xFF, sizeof(YR_STRING)); + null_string.g_flags = STRING_GFLAGS_NULL; + + compiler->last_result = yr_arena_write_data( + compiler->strings_arena, + &null_string, + sizeof(YR_STRING), + NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.string) = (yyvsp[0].string); + } +#line 1795 "grammar.c" /* yacc.c:1662 */ + break; + + case 17: +#line 352 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = 0; } +#line 1801 "grammar.c" /* yacc.c:1662 */ + break; + + case 18: +#line 353 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = (yyvsp[-1].integer) | (yyvsp[0].integer); } +#line 1807 "grammar.c" /* yacc.c:1662 */ + break; + + case 19: +#line 358 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = RULE_GFLAGS_PRIVATE; } +#line 1813 "grammar.c" /* yacc.c:1662 */ + break; + + case 20: +#line 359 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = RULE_GFLAGS_GLOBAL; } +#line 1819 "grammar.c" /* yacc.c:1662 */ + break; + + case 21: +#line 365 "grammar.y" /* yacc.c:1662 */ + { + (yyval.c_string) = NULL; + } +#line 1827 "grammar.c" /* yacc.c:1662 */ + break; + + case 22: +#line 369 "grammar.y" /* yacc.c:1662 */ + { + // Tags list is represented in the arena as a sequence + // of null-terminated strings, the sequence ends with an + // additional null character. Here we write the ending null + //character. Example: tag1\0tag2\0tag3\0\0 + + compiler->last_result = yr_arena_write_string( + yyget_extra(yyscanner)->sz_arena, "", NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.c_string) = (yyvsp[0].c_string); + } +#line 1845 "grammar.c" /* yacc.c:1662 */ + break; + + case 23: +#line 387 "grammar.y" /* yacc.c:1662 */ + { + char* identifier; + + compiler->last_result = yr_arena_write_string( + yyget_extra(yyscanner)->sz_arena, (yyvsp[0].c_string), &identifier); + + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.c_string) = identifier; + } +#line 1862 "grammar.c" /* yacc.c:1662 */ + break; + + case 24: +#line 400 "grammar.y" /* yacc.c:1662 */ + { + char* tag_name = (yyvsp[-1].c_string); + size_t tag_length = tag_name != NULL ? strlen(tag_name) : 0; + + while (tag_length > 0) + { + if (strcmp(tag_name, (yyvsp[0].c_string)) == 0) + { + yr_compiler_set_error_extra_info(compiler, tag_name); + compiler->last_result = ERROR_DUPLICATED_TAG_IDENTIFIER; + break; + } + + tag_name = (char*) yr_arena_next_address( + yyget_extra(yyscanner)->sz_arena, + tag_name, + tag_length + 1); + + tag_length = tag_name != NULL ? strlen(tag_name) : 0; + } + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_arena_write_string( + yyget_extra(yyscanner)->sz_arena, (yyvsp[0].c_string), NULL); + + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.c_string) = (yyvsp[-1].c_string); + } +#line 1898 "grammar.c" /* yacc.c:1662 */ + break; + + case 25: +#line 436 "grammar.y" /* yacc.c:1662 */ + { (yyval.meta) = (yyvsp[0].meta); } +#line 1904 "grammar.c" /* yacc.c:1662 */ + break; + + case 26: +#line 437 "grammar.y" /* yacc.c:1662 */ + { (yyval.meta) = (yyvsp[-1].meta); } +#line 1910 "grammar.c" /* yacc.c:1662 */ + break; + + case 27: +#line 443 "grammar.y" /* yacc.c:1662 */ + { + SIZED_STRING* sized_string = (yyvsp[0].sized_string); + + (yyval.meta) = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_STRING, + (yyvsp[-2].c_string), + sized_string->c_string, + 0); + + yr_free((yyvsp[-2].c_string)); + yr_free((yyvsp[0].sized_string)); + + fail_if((yyval.meta) == NULL); + } +#line 1930 "grammar.c" /* yacc.c:1662 */ + break; + + case 28: +#line 459 "grammar.y" /* yacc.c:1662 */ + { + (yyval.meta) = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_INTEGER, + (yyvsp[-2].c_string), + NULL, + (yyvsp[0].integer)); + + yr_free((yyvsp[-2].c_string)); + + fail_if((yyval.meta) == NULL); + } +#line 1947 "grammar.c" /* yacc.c:1662 */ + break; + + case 29: +#line 472 "grammar.y" /* yacc.c:1662 */ + { + (yyval.meta) = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_INTEGER, + (yyvsp[-3].c_string), + NULL, + -(yyvsp[0].integer)); + + yr_free((yyvsp[-3].c_string)); + + fail_if((yyval.meta) == NULL); + } +#line 1964 "grammar.c" /* yacc.c:1662 */ + break; + + case 30: +#line 485 "grammar.y" /* yacc.c:1662 */ + { + (yyval.meta) = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_BOOLEAN, + (yyvsp[-2].c_string), + NULL, + TRUE); + + yr_free((yyvsp[-2].c_string)); + + fail_if((yyval.meta) == NULL); + } +#line 1981 "grammar.c" /* yacc.c:1662 */ + break; + + case 31: +#line 498 "grammar.y" /* yacc.c:1662 */ + { + (yyval.meta) = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_BOOLEAN, + (yyvsp[-2].c_string), + NULL, + FALSE); + + yr_free((yyvsp[-2].c_string)); + + fail_if((yyval.meta) == NULL); + } +#line 1998 "grammar.c" /* yacc.c:1662 */ + break; + + case 32: +#line 514 "grammar.y" /* yacc.c:1662 */ + { (yyval.string) = (yyvsp[0].string); } +#line 2004 "grammar.c" /* yacc.c:1662 */ + break; + + case 33: +#line 515 "grammar.y" /* yacc.c:1662 */ + { (yyval.string) = (yyvsp[-1].string); } +#line 2010 "grammar.c" /* yacc.c:1662 */ + break; + + case 34: +#line 521 "grammar.y" /* yacc.c:1662 */ + { + compiler->current_line = yyget_lineno(yyscanner); + } +#line 2018 "grammar.c" /* yacc.c:1662 */ + break; + + case 35: +#line 525 "grammar.y" /* yacc.c:1662 */ + { + (yyval.string) = yr_parser_reduce_string_declaration( + yyscanner, (int32_t) (yyvsp[0].integer), (yyvsp[-4].c_string), (yyvsp[-1].sized_string)); + + yr_free((yyvsp[-4].c_string)); + yr_free((yyvsp[-1].sized_string)); + + fail_if((yyval.string) == NULL); + compiler->current_line = 0; + } +#line 2033 "grammar.c" /* yacc.c:1662 */ + break; + + case 36: +#line 536 "grammar.y" /* yacc.c:1662 */ + { + compiler->current_line = yyget_lineno(yyscanner); + } +#line 2041 "grammar.c" /* yacc.c:1662 */ + break; + + case 37: +#line 540 "grammar.y" /* yacc.c:1662 */ + { + (yyval.string) = yr_parser_reduce_string_declaration( + yyscanner, (int32_t) (yyvsp[0].integer) | STRING_GFLAGS_REGEXP, (yyvsp[-4].c_string), (yyvsp[-1].sized_string)); + + yr_free((yyvsp[-4].c_string)); + yr_free((yyvsp[-1].sized_string)); + + fail_if((yyval.string) == NULL); + + compiler->current_line = 0; + } +#line 2057 "grammar.c" /* yacc.c:1662 */ + break; + + case 38: +#line 552 "grammar.y" /* yacc.c:1662 */ + { + (yyval.string) = yr_parser_reduce_string_declaration( + yyscanner, STRING_GFLAGS_HEXADECIMAL, (yyvsp[-2].c_string), (yyvsp[0].sized_string)); + + yr_free((yyvsp[-2].c_string)); + yr_free((yyvsp[0].sized_string)); + + fail_if((yyval.string) == NULL); + } +#line 2071 "grammar.c" /* yacc.c:1662 */ + break; + + case 39: +#line 565 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = 0; } +#line 2077 "grammar.c" /* yacc.c:1662 */ + break; + + case 40: +#line 566 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = (yyvsp[-1].integer) | (yyvsp[0].integer); } +#line 2083 "grammar.c" /* yacc.c:1662 */ + break; + + case 41: +#line 571 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = STRING_GFLAGS_WIDE; } +#line 2089 "grammar.c" /* yacc.c:1662 */ + break; + + case 42: +#line 572 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = STRING_GFLAGS_ASCII; } +#line 2095 "grammar.c" /* yacc.c:1662 */ + break; + + case 43: +#line 573 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = STRING_GFLAGS_NO_CASE; } +#line 2101 "grammar.c" /* yacc.c:1662 */ + break; + + case 44: +#line 574 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = STRING_GFLAGS_FULL_WORD; } +#line 2107 "grammar.c" /* yacc.c:1662 */ + break; + + case 45: +#line 575 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = STRING_GFLAGS_XOR; } +#line 2113 "grammar.c" /* yacc.c:1662 */ + break; + + case 46: +#line 581 "grammar.y" /* yacc.c:1662 */ + { + int var_index = yr_parser_lookup_loop_variable(yyscanner, (yyvsp[0].c_string)); + + if (var_index >= 0) + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, + OP_PUSH_M, + LOOP_LOCAL_VARS * var_index, + NULL, + NULL); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + (yyval.expression).identifier = compiler->loop_identifier[var_index]; + } + else + { + // Search for identifier within the global namespace, where the + // externals variables reside. + + YR_OBJECT* object = (YR_OBJECT*) yr_hash_table_lookup( + compiler->objects_table, (yyvsp[0].c_string), NULL); + + if (object == NULL) + { + // If not found, search within the current namespace. + char* ns = compiler->current_namespace->name; + + object = (YR_OBJECT*) yr_hash_table_lookup( + compiler->objects_table, (yyvsp[0].c_string), ns); + } + + if (object != NULL) + { + char* id; + + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, (yyvsp[0].c_string), &id); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_OBJ_LOAD, + id, + NULL, + NULL); + + (yyval.expression).type = EXPRESSION_TYPE_OBJECT; + (yyval.expression).value.object = object; + (yyval.expression).identifier = object->identifier; + } + else + { + YR_RULE* rule = (YR_RULE*) yr_hash_table_lookup( + compiler->rules_table, + (yyvsp[0].c_string), + compiler->current_namespace->name); + + if (rule != NULL) + { + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_PUSH_RULE, + rule, + NULL, + NULL); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + (yyval.expression).value.integer = UNDEFINED; + (yyval.expression).identifier = rule->identifier; + } + else + { + yr_compiler_set_error_extra_info(compiler, (yyvsp[0].c_string)); + compiler->last_result = ERROR_UNDEFINED_IDENTIFIER; + } + } + } + + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 2202 "grammar.c" /* yacc.c:1662 */ + break; + + case 47: +#line 666 "grammar.y" /* yacc.c:1662 */ + { + YR_OBJECT* field = NULL; + + if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_OBJECT && + (yyvsp[-2].expression).value.object->type == OBJECT_TYPE_STRUCTURE) + { + field = yr_object_lookup_field((yyvsp[-2].expression).value.object, (yyvsp[0].c_string)); + + if (field != NULL) + { + char* ident; + + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, (yyvsp[0].c_string), &ident); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_OBJ_FIELD, + ident, + NULL, + NULL); + + (yyval.expression).type = EXPRESSION_TYPE_OBJECT; + (yyval.expression).value.object = field; + (yyval.expression).identifier = field->identifier; + } + else + { + yr_compiler_set_error_extra_info(compiler, (yyvsp[0].c_string)); + compiler->last_result = ERROR_INVALID_FIELD_NAME; + } + } + else + { + yr_compiler_set_error_extra_info( + compiler, (yyvsp[-2].expression).identifier); + + compiler->last_result = ERROR_NOT_A_STRUCTURE; + } + + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 2252 "grammar.c" /* yacc.c:1662 */ + break; + + case 48: +#line 712 "grammar.y" /* yacc.c:1662 */ + { + YR_OBJECT_ARRAY* array; + YR_OBJECT_DICTIONARY* dict; + + if ((yyvsp[-3].expression).type == EXPRESSION_TYPE_OBJECT && + (yyvsp[-3].expression).value.object->type == OBJECT_TYPE_ARRAY) + { + if ((yyvsp[-1].expression).type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "array indexes must be of integer type"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + + compiler->last_result = yr_parser_emit( + yyscanner, OP_INDEX_ARRAY, NULL); + + array = object_as_array((yyvsp[-3].expression).value.object); + + (yyval.expression).type = EXPRESSION_TYPE_OBJECT; + (yyval.expression).value.object = array->prototype_item; + (yyval.expression).identifier = array->identifier; + } + else if ((yyvsp[-3].expression).type == EXPRESSION_TYPE_OBJECT && + (yyvsp[-3].expression).value.object->type == OBJECT_TYPE_DICTIONARY) + { + if ((yyvsp[-1].expression).type != EXPRESSION_TYPE_STRING) + { + yr_compiler_set_error_extra_info( + compiler, "dictionary keys must be of string type"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + + compiler->last_result = yr_parser_emit( + yyscanner, OP_LOOKUP_DICT, NULL); + + dict = object_as_dictionary((yyvsp[-3].expression).value.object); + + (yyval.expression).type = EXPRESSION_TYPE_OBJECT; + (yyval.expression).value.object = dict->prototype_item; + (yyval.expression).identifier = dict->identifier; + } + else + { + yr_compiler_set_error_extra_info( + compiler, (yyvsp[-3].expression).identifier); + + compiler->last_result = ERROR_NOT_INDEXABLE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 2313 "grammar.c" /* yacc.c:1662 */ + break; + + case 49: +#line 770 "grammar.y" /* yacc.c:1662 */ + { + YR_OBJECT_FUNCTION* function; + char* args_fmt; + + if ((yyvsp[-3].expression).type == EXPRESSION_TYPE_OBJECT && + (yyvsp[-3].expression).value.object->type == OBJECT_TYPE_FUNCTION) + { + compiler->last_result = yr_parser_check_types( + compiler, object_as_function((yyvsp[-3].expression).value.object), (yyvsp[-1].c_string)); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, (yyvsp[-1].c_string), &args_fmt); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_CALL, + args_fmt, + NULL, + NULL); + + function = object_as_function((yyvsp[-3].expression).value.object); + + (yyval.expression).type = EXPRESSION_TYPE_OBJECT; + (yyval.expression).value.object = function->return_obj; + (yyval.expression).identifier = function->identifier; + } + else + { + yr_compiler_set_error_extra_info( + compiler, (yyvsp[-3].expression).identifier); + + compiler->last_result = ERROR_NOT_A_FUNCTION; + } + + yr_free((yyvsp[-1].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 2358 "grammar.c" /* yacc.c:1662 */ + break; + + case 50: +#line 814 "grammar.y" /* yacc.c:1662 */ + { (yyval.c_string) = yr_strdup(""); } +#line 2364 "grammar.c" /* yacc.c:1662 */ + break; + + case 51: +#line 815 "grammar.y" /* yacc.c:1662 */ + { (yyval.c_string) = (yyvsp[0].c_string); } +#line 2370 "grammar.c" /* yacc.c:1662 */ + break; + + case 52: +#line 820 "grammar.y" /* yacc.c:1662 */ + { + (yyval.c_string) = (char*) yr_malloc(MAX_FUNCTION_ARGS + 1); + + switch((yyvsp[0].expression).type) + { + case EXPRESSION_TYPE_INTEGER: + strlcpy((yyval.c_string), "i", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_FLOAT: + strlcpy((yyval.c_string), "f", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_BOOLEAN: + strlcpy((yyval.c_string), "b", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_STRING: + strlcpy((yyval.c_string), "s", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_REGEXP: + strlcpy((yyval.c_string), "r", MAX_FUNCTION_ARGS); + break; + default: + assert(FALSE); + } + + fail_if((yyval.c_string) == NULL); + } +#line 2401 "grammar.c" /* yacc.c:1662 */ + break; + + case 53: +#line 847 "grammar.y" /* yacc.c:1662 */ + { + if (strlen((yyvsp[-2].c_string)) == MAX_FUNCTION_ARGS) + { + compiler->last_result = ERROR_TOO_MANY_ARGUMENTS; + } + else + { + switch((yyvsp[0].expression).type) + { + case EXPRESSION_TYPE_INTEGER: + strlcat((yyvsp[-2].c_string), "i", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_FLOAT: + strlcat((yyvsp[-2].c_string), "f", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_BOOLEAN: + strlcat((yyvsp[-2].c_string), "b", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_STRING: + strlcat((yyvsp[-2].c_string), "s", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_REGEXP: + strlcat((yyvsp[-2].c_string), "r", MAX_FUNCTION_ARGS); + break; + default: + assert(FALSE); + } + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.c_string) = (yyvsp[-2].c_string); + } +#line 2439 "grammar.c" /* yacc.c:1662 */ + break; + + case 54: +#line 885 "grammar.y" /* yacc.c:1662 */ + { + SIZED_STRING* sized_string = (yyvsp[0].sized_string); + RE* re; + RE_ERROR error; + + int re_flags = 0; + + if (sized_string->flags & SIZED_STRING_FLAGS_NO_CASE) + re_flags |= RE_FLAGS_NO_CASE; + + if (sized_string->flags & SIZED_STRING_FLAGS_DOT_ALL) + re_flags |= RE_FLAGS_DOT_ALL; + + compiler->last_result = yr_re_compile( + sized_string->c_string, + re_flags, + compiler->re_code_arena, + &re, + &error); + + yr_free((yyvsp[0].sized_string)); + + if (compiler->last_result == ERROR_INVALID_REGULAR_EXPRESSION) + yr_compiler_set_error_extra_info(compiler, error.message); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_PUSH, + re, + NULL, + NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_REGEXP; + } +#line 2481 "grammar.c" /* yacc.c:1662 */ + break; + + case 55: +#line 927 "grammar.y" /* yacc.c:1662 */ + { + if ((yyvsp[0].expression).type == EXPRESSION_TYPE_STRING) + { + if ((yyvsp[0].expression).value.sized_string != NULL) + { + yywarning(yyscanner, + "Using literal string \"%s\" in a boolean operation.", + (yyvsp[0].expression).value.sized_string->c_string); + } + + compiler->last_result = yr_parser_emit( + yyscanner, OP_STR_TO_BOOL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2504 "grammar.c" /* yacc.c:1662 */ + break; + + case 56: +#line 949 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, 1, NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2517 "grammar.c" /* yacc.c:1662 */ + break; + + case 57: +#line 958 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, 0, NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2530 "grammar.c" /* yacc.c:1662 */ + break; + + case 58: +#line 967 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "matches"); + check_type((yyvsp[0].expression), EXPRESSION_TYPE_REGEXP, "matches"); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit( + yyscanner, + OP_MATCHES, + NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2549 "grammar.c" /* yacc.c:1662 */ + break; + + case 59: +#line 982 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "contains"); + check_type((yyvsp[0].expression), EXPRESSION_TYPE_STRING, "contains"); + + compiler->last_result = yr_parser_emit( + yyscanner, OP_CONTAINS, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2565 "grammar.c" /* yacc.c:1662 */ + break; + + case 60: +#line 994 "grammar.y" /* yacc.c:1662 */ + { + int result = yr_parser_reduce_string_identifier( + yyscanner, + (yyvsp[0].c_string), + OP_FOUND, + UNDEFINED); + + yr_free((yyvsp[0].c_string)); + + fail_if(result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2583 "grammar.c" /* yacc.c:1662 */ + break; + + case 61: +#line 1008 "grammar.y" /* yacc.c:1662 */ + { + check_type_with_cleanup((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "at", yr_free((yyvsp[-2].c_string))); + + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, (yyvsp[-2].c_string), OP_FOUND_AT, (yyvsp[0].expression).value.integer); + + yr_free((yyvsp[-2].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2600 "grammar.c" /* yacc.c:1662 */ + break; + + case 62: +#line 1021 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, (yyvsp[-2].c_string), OP_FOUND_IN, UNDEFINED); + + yr_free((yyvsp[-2].c_string)); + + fail_if(compiler->last_result!= ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2615 "grammar.c" /* yacc.c:1662 */ + break; + + case 63: +#line 1032 "grammar.y" /* yacc.c:1662 */ + { + if (compiler->loop_depth > 0) + { + compiler->loop_depth--; + compiler->loop_identifier[compiler->loop_depth] = NULL; + } + + YYERROR; + } +#line 2629 "grammar.c" /* yacc.c:1662 */ + break; + + case 64: +#line 1042 "grammar.y" /* yacc.c:1662 */ + { + int var_index; + + if (compiler->loop_depth == MAX_LOOP_NESTING) + compiler->last_result = \ + ERROR_LOOP_NESTING_LIMIT_EXCEEDED; + + fail_if(compiler->last_result != ERROR_SUCCESS); + + var_index = yr_parser_lookup_loop_variable( + yyscanner, (yyvsp[-1].c_string)); + + if (var_index >= 0) + { + yr_compiler_set_error_extra_info( + compiler, (yyvsp[-1].c_string)); + + compiler->last_result = \ + ERROR_DUPLICATED_LOOP_IDENTIFIER; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + + // Push end-of-list marker + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, UNDEFINED, NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 2663 "grammar.c" /* yacc.c:1662 */ + break; + + case 65: +#line 1072 "grammar.y" /* yacc.c:1662 */ + { + int mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth; + uint8_t* addr; + + // Clear counter for number of expressions evaluating + // to TRUE. + yr_parser_emit_with_arg( + yyscanner, OP_CLEAR_M, mem_offset + 1, NULL, NULL); + + // Clear iterations counter + yr_parser_emit_with_arg( + yyscanner, OP_CLEAR_M, mem_offset + 2, NULL, NULL); + + if ((yyvsp[-1].integer) == INTEGER_SET_ENUMERATION) + { + // Pop the first integer + yr_parser_emit_with_arg( + yyscanner, OP_POP_M, mem_offset, &addr, NULL); + } + else // INTEGER_SET_RANGE + { + // Pop higher bound of set range + yr_parser_emit_with_arg( + yyscanner, OP_POP_M, mem_offset + 3, &addr, NULL); + + // Pop lower bound of set range + yr_parser_emit_with_arg( + yyscanner, OP_POP_M, mem_offset, NULL, NULL); + } + + compiler->loop_address[compiler->loop_depth] = addr; + compiler->loop_identifier[compiler->loop_depth] = (yyvsp[-4].c_string); + compiler->loop_depth++; + } +#line 2702 "grammar.c" /* yacc.c:1662 */ + break; + + case 66: +#line 1107 "grammar.y" /* yacc.c:1662 */ + { + int mem_offset; + + compiler->loop_depth--; + mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth; + + // The value at the top of the stack is the result of + // evaluating the boolean expression, so it could be + // 0, 1 or UNDEFINED. Add this value to a counter + // keeping the number of expressions evaluating to true. + // If the value is UNDEFINED instruction OP_ADD_M + // does nothing. + + yr_parser_emit_with_arg( + yyscanner, OP_ADD_M, mem_offset + 1, NULL, NULL); + + // Increment iterations counter + yr_parser_emit_with_arg( + yyscanner, OP_INCR_M, mem_offset + 2, NULL, NULL); + + if ((yyvsp[-5].integer) == INTEGER_SET_ENUMERATION) + { + yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JNUNDEF, + compiler->loop_address[compiler->loop_depth], + NULL, + NULL); + } + else // INTEGER_SET_RANGE + { + // Increment lower bound of integer set + yr_parser_emit_with_arg( + yyscanner, OP_INCR_M, mem_offset, NULL, NULL); + + // Push lower bound of integer set + yr_parser_emit_with_arg( + yyscanner, OP_PUSH_M, mem_offset, NULL, NULL); + + // Push higher bound of integer set + yr_parser_emit_with_arg( + yyscanner, OP_PUSH_M, mem_offset + 3, NULL, NULL); + + // Compare higher bound with lower bound, do loop again + // if lower bound is still lower or equal than higher bound + yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JLE, + compiler->loop_address[compiler->loop_depth], + NULL, + NULL); + + yr_parser_emit(yyscanner, OP_POP, NULL); + yr_parser_emit(yyscanner, OP_POP, NULL); + } + + // Pop end-of-list marker. + yr_parser_emit(yyscanner, OP_POP, NULL); + + // At this point the loop quantifier (any, all, 1, 2,..) + // is at the top of the stack. Check if the quantifier + // is undefined (meaning "all") and replace it with the + // iterations counter in that case. + yr_parser_emit_with_arg( + yyscanner, OP_SWAPUNDEF, mem_offset + 2, NULL, NULL); + + // Compare the loop quantifier with the number of + // expressions evaluating to TRUE. + yr_parser_emit_with_arg( + yyscanner, OP_PUSH_M, mem_offset + 1, NULL, NULL); + + yr_parser_emit(yyscanner, OP_INT_LE, NULL); + + compiler->loop_identifier[compiler->loop_depth] = NULL; + yr_free((yyvsp[-8].c_string)); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2785 "grammar.c" /* yacc.c:1662 */ + break; + + case 67: +#line 1186 "grammar.y" /* yacc.c:1662 */ + { + int mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth; + uint8_t* addr; + + if (compiler->loop_depth == MAX_LOOP_NESTING) + compiler->last_result = \ + ERROR_LOOP_NESTING_LIMIT_EXCEEDED; + + if (compiler->loop_for_of_mem_offset != -1) + compiler->last_result = \ + ERROR_NESTED_FOR_OF_LOOP; + + fail_if(compiler->last_result != ERROR_SUCCESS); + + yr_parser_emit_with_arg( + yyscanner, OP_CLEAR_M, mem_offset + 1, NULL, NULL); + + yr_parser_emit_with_arg( + yyscanner, OP_CLEAR_M, mem_offset + 2, NULL, NULL); + + // Pop the first string. + yr_parser_emit_with_arg( + yyscanner, OP_POP_M, mem_offset, &addr, NULL); + + compiler->loop_for_of_mem_offset = mem_offset; + compiler->loop_address[compiler->loop_depth] = addr; + compiler->loop_identifier[compiler->loop_depth] = NULL; + compiler->loop_depth++; + } +#line 2819 "grammar.c" /* yacc.c:1662 */ + break; + + case 68: +#line 1216 "grammar.y" /* yacc.c:1662 */ + { + int mem_offset; + + compiler->loop_depth--; + compiler->loop_for_of_mem_offset = -1; + + mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth; + + // Increment counter by the value returned by the + // boolean expression (0 or 1). If the boolean expression + // returned UNDEFINED the OP_ADD_M won't do anything. + + yr_parser_emit_with_arg( + yyscanner, OP_ADD_M, mem_offset + 1, NULL, NULL); + + // Increment iterations counter. + yr_parser_emit_with_arg( + yyscanner, OP_INCR_M, mem_offset + 2, NULL, NULL); + + // If next string is not undefined, go back to the + // beginning of the loop. + yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JNUNDEF, + compiler->loop_address[compiler->loop_depth], + NULL, + NULL); + + // Pop end-of-list marker. + yr_parser_emit(yyscanner, OP_POP, NULL); + + // At this point the loop quantifier (any, all, 1, 2,..) + // is at top of the stack. Check if the quantifier is + // undefined (meaning "all") and replace it with the + // iterations counter in that case. + yr_parser_emit_with_arg( + yyscanner, OP_SWAPUNDEF, mem_offset + 2, NULL, NULL); + + // Compare the loop quantifier with the number of + // expressions evaluating to TRUE. + yr_parser_emit_with_arg( + yyscanner, OP_PUSH_M, mem_offset + 1, NULL, NULL); + + yr_parser_emit(yyscanner, OP_INT_LE, NULL); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + + } +#line 2872 "grammar.c" /* yacc.c:1662 */ + break; + + case 69: +#line 1265 "grammar.y" /* yacc.c:1662 */ + { + yr_parser_emit(yyscanner, OP_OF, NULL); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2882 "grammar.c" /* yacc.c:1662 */ + break; + + case 70: +#line 1271 "grammar.y" /* yacc.c:1662 */ + { + yr_parser_emit(yyscanner, OP_NOT, NULL); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2892 "grammar.c" /* yacc.c:1662 */ + break; + + case 71: +#line 1277 "grammar.y" /* yacc.c:1662 */ + { + YR_FIXUP* fixup; + void* jmp_destination_addr; + + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JFALSE, + 0, // still don't know the jump destination + NULL, + &jmp_destination_addr); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + // create a fixup entry for the jump and push it in the stack + fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); + + if (fixup == NULL) + compiler->last_error = ERROR_INSUFFICIENT_MEMORY; + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup->address = jmp_destination_addr; + fixup->next = compiler->fixup_stack_head; + compiler->fixup_stack_head = fixup; + } +#line 2922 "grammar.c" /* yacc.c:1662 */ + break; + + case 72: +#line 1303 "grammar.y" /* yacc.c:1662 */ + { + YR_FIXUP* fixup; + uint8_t* nop_addr; + + compiler->last_result = yr_parser_emit(yyscanner, OP_AND, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + // Generate a do-nothing instruction (NOP) in order to get its address + // and use it as the destination for the OP_JFALSE. We can not simply + // use the address of the OP_AND instruction +1 because we can't be + // sure that the instruction following the OP_AND is going to be in + // the same arena page. As we don't have a reliable way of getting the + // address of the next instruction we generate the OP_NOP. + + compiler->last_result = yr_parser_emit(yyscanner, OP_NOP, &nop_addr); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup = compiler->fixup_stack_head; + *(void**)(fixup->address) = (void*) nop_addr; + compiler->fixup_stack_head = fixup->next; + yr_free(fixup); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 2953 "grammar.c" /* yacc.c:1662 */ + break; + + case 73: +#line 1330 "grammar.y" /* yacc.c:1662 */ + { + YR_FIXUP* fixup; + void* jmp_destination_addr; + + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JTRUE, + 0, // still don't know the jump destination + NULL, + &jmp_destination_addr); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); + + if (fixup == NULL) + compiler->last_error = ERROR_INSUFFICIENT_MEMORY; + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup->address = jmp_destination_addr; + fixup->next = compiler->fixup_stack_head; + compiler->fixup_stack_head = fixup; + } +#line 2982 "grammar.c" /* yacc.c:1662 */ + break; + + case 74: +#line 1355 "grammar.y" /* yacc.c:1662 */ + { + YR_FIXUP* fixup; + uint8_t* nop_addr; + + compiler->last_result = yr_parser_emit(yyscanner, OP_OR, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + // Generate a do-nothing instruction (NOP) in order to get its address + // and use it as the destination for the OP_JFALSE. We can not simply + // use the address of the OP_OR instruction +1 because we can't be + // sure that the instruction following the OP_AND is going to be in + // the same arena page. As we don't have a reliable way of getting the + // address of the next instruction we generate the OP_NOP. + + compiler->last_result = yr_parser_emit(yyscanner, OP_NOP, &nop_addr); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup = compiler->fixup_stack_head; + *(void**)(fixup->address) = (void*)(nop_addr); + compiler->fixup_stack_head = fixup->next; + yr_free(fixup); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 3013 "grammar.c" /* yacc.c:1662 */ + break; + + case 75: +#line 1382 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "<", (yyvsp[-2].expression), (yyvsp[0].expression)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 3026 "grammar.c" /* yacc.c:1662 */ + break; + + case 76: +#line 1391 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, ">", (yyvsp[-2].expression), (yyvsp[0].expression)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 3039 "grammar.c" /* yacc.c:1662 */ + break; + + case 77: +#line 1400 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "<=", (yyvsp[-2].expression), (yyvsp[0].expression)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 3052 "grammar.c" /* yacc.c:1662 */ + break; + + case 78: +#line 1409 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, ">=", (yyvsp[-2].expression), (yyvsp[0].expression)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 3065 "grammar.c" /* yacc.c:1662 */ + break; + + case 79: +#line 1418 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "==", (yyvsp[-2].expression), (yyvsp[0].expression)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 3078 "grammar.c" /* yacc.c:1662 */ + break; + + case 80: +#line 1427 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "!=", (yyvsp[-2].expression), (yyvsp[0].expression)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + } +#line 3091 "grammar.c" /* yacc.c:1662 */ + break; + + case 81: +#line 1436 "grammar.y" /* yacc.c:1662 */ + { + (yyval.expression) = (yyvsp[0].expression); + } +#line 3099 "grammar.c" /* yacc.c:1662 */ + break; + + case 82: +#line 1440 "grammar.y" /* yacc.c:1662 */ + { + (yyval.expression) = (yyvsp[-1].expression); + } +#line 3107 "grammar.c" /* yacc.c:1662 */ + break; + + case 83: +#line 1447 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = INTEGER_SET_ENUMERATION; } +#line 3113 "grammar.c" /* yacc.c:1662 */ + break; + + case 84: +#line 1448 "grammar.y" /* yacc.c:1662 */ + { (yyval.integer) = INTEGER_SET_RANGE; } +#line 3119 "grammar.c" /* yacc.c:1662 */ + break; + + case 85: +#line 1454 "grammar.y" /* yacc.c:1662 */ + { + if ((yyvsp[-3].expression).type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "wrong type for range's lower bound"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + if ((yyvsp[-1].expression).type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "wrong type for range's upper bound"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3141 "grammar.c" /* yacc.c:1662 */ + break; + + case 86: +#line 1476 "grammar.y" /* yacc.c:1662 */ + { + if ((yyvsp[0].expression).type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "wrong type for enumeration item"); + compiler->last_result = ERROR_WRONG_TYPE; + + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3157 "grammar.c" /* yacc.c:1662 */ + break; + + case 87: +#line 1488 "grammar.y" /* yacc.c:1662 */ + { + if ((yyvsp[0].expression).type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "wrong type for enumeration item"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3172 "grammar.c" /* yacc.c:1662 */ + break; + + case 88: +#line 1503 "grammar.y" /* yacc.c:1662 */ + { + // Push end-of-list marker + yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL, NULL); + } +#line 3181 "grammar.c" /* yacc.c:1662 */ + break; + + case 90: +#line 1509 "grammar.y" /* yacc.c:1662 */ + { + yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL, NULL); + yr_parser_emit_pushes_for_strings(yyscanner, "$*"); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3192 "grammar.c" /* yacc.c:1662 */ + break; + + case 93: +#line 1526 "grammar.y" /* yacc.c:1662 */ + { + yr_parser_emit_pushes_for_strings(yyscanner, (yyvsp[0].c_string)); + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3203 "grammar.c" /* yacc.c:1662 */ + break; + + case 94: +#line 1533 "grammar.y" /* yacc.c:1662 */ + { + yr_parser_emit_pushes_for_strings(yyscanner, (yyvsp[0].c_string)); + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3214 "grammar.c" /* yacc.c:1662 */ + break; + + case 96: +#line 1545 "grammar.y" /* yacc.c:1662 */ + { + yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL, NULL); + } +#line 3222 "grammar.c" /* yacc.c:1662 */ + break; + + case 97: +#line 1549 "grammar.y" /* yacc.c:1662 */ + { + yr_parser_emit_with_arg(yyscanner, OP_PUSH, 1, NULL, NULL); + } +#line 3230 "grammar.c" /* yacc.c:1662 */ + break; + + case 98: +#line 1557 "grammar.y" /* yacc.c:1662 */ + { + (yyval.expression) = (yyvsp[-1].expression); + } +#line 3238 "grammar.c" /* yacc.c:1662 */ + break; + + case 99: +#line 1561 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_emit( + yyscanner, OP_FILESIZE, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } +#line 3252 "grammar.c" /* yacc.c:1662 */ + break; + + case 100: +#line 1571 "grammar.y" /* yacc.c:1662 */ + { + yywarning(yyscanner, + "Using deprecated \"entrypoint\" keyword. Use the \"entry_point\" " + "function from PE module instead."); + + compiler->last_result = yr_parser_emit( + yyscanner, OP_ENTRYPOINT, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } +#line 3270 "grammar.c" /* yacc.c:1662 */ + break; + + case 101: +#line 1585 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-1].expression), EXPRESSION_TYPE_INTEGER, "intXXXX or uintXXXX"); + + // _INTEGER_FUNCTION_ could be any of int8, int16, int32, uint8, + // uint32, etc. $1 contains an index that added to OP_READ_INT results + // in the proper OP_INTXX opcode. + + compiler->last_result = yr_parser_emit( + yyscanner, (uint8_t) (OP_READ_INT + (yyvsp[-3].integer)), NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } +#line 3290 "grammar.c" /* yacc.c:1662 */ + break; + + case 102: +#line 1601 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, (yyvsp[0].integer), NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = (yyvsp[0].integer); + } +#line 3304 "grammar.c" /* yacc.c:1662 */ + break; + + case 103: +#line 1611 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_emit_with_arg_double( + yyscanner, OP_PUSH, (yyvsp[0].double_), NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_FLOAT; + } +#line 3317 "grammar.c" /* yacc.c:1662 */ + break; + + case 104: +#line 1620 "grammar.y" /* yacc.c:1662 */ + { + SIZED_STRING* sized_string; + + compiler->last_result = yr_arena_write_data( + compiler->sz_arena, + (yyvsp[0].sized_string), + (yyvsp[0].sized_string)->length + sizeof(SIZED_STRING), + (void**) &sized_string); + + yr_free((yyvsp[0].sized_string)); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_PUSH, + sized_string, + NULL, + NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_STRING; + (yyval.expression).value.sized_string = sized_string; + } +#line 3346 "grammar.c" /* yacc.c:1662 */ + break; + + case 105: +#line 1645 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, (yyvsp[0].c_string), OP_COUNT, UNDEFINED); + + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } +#line 3362 "grammar.c" /* yacc.c:1662 */ + break; + + case 106: +#line 1657 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, (yyvsp[-3].c_string), OP_OFFSET, UNDEFINED); + + yr_free((yyvsp[-3].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } +#line 3378 "grammar.c" /* yacc.c:1662 */ + break; + + case 107: +#line 1669 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, 1, NULL, NULL); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, (yyvsp[0].c_string), OP_OFFSET, UNDEFINED); + + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } +#line 3398 "grammar.c" /* yacc.c:1662 */ + break; + + case 108: +#line 1685 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, (yyvsp[-3].c_string), OP_LENGTH, UNDEFINED); + + yr_free((yyvsp[-3].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } +#line 3414 "grammar.c" /* yacc.c:1662 */ + break; + + case 109: +#line 1697 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, 1, NULL, NULL); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, (yyvsp[0].c_string), OP_LENGTH, UNDEFINED); + + yr_free((yyvsp[0].c_string)); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } +#line 3434 "grammar.c" /* yacc.c:1662 */ + break; + + case 110: +#line 1713 "grammar.y" /* yacc.c:1662 */ + { + if ((yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) // loop identifier + { + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + } + else if ((yyvsp[0].expression).type == EXPRESSION_TYPE_BOOLEAN) // rule identifier + { + (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; + (yyval.expression).value.integer = UNDEFINED; + } + else if ((yyvsp[0].expression).type == EXPRESSION_TYPE_OBJECT) + { + compiler->last_result = yr_parser_emit( + yyscanner, OP_OBJ_VALUE, NULL); + + switch((yyvsp[0].expression).value.object->type) + { + case OBJECT_TYPE_INTEGER: + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = UNDEFINED; + break; + case OBJECT_TYPE_FLOAT: + (yyval.expression).type = EXPRESSION_TYPE_FLOAT; + break; + case OBJECT_TYPE_STRING: + (yyval.expression).type = EXPRESSION_TYPE_STRING; + (yyval.expression).value.sized_string = NULL; + break; + default: + yr_compiler_set_error_extra_info_fmt( + compiler, + "wrong usage of identifier \"%s\"", + (yyvsp[0].expression).identifier); + compiler->last_result = ERROR_WRONG_TYPE; + } + } + else + { + assert(FALSE); + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3483 "grammar.c" /* yacc.c:1662 */ + break; + + case 111: +#line 1758 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT, "-"); + + if ((yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) + { + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = ((yyvsp[0].expression).value.integer == UNDEFINED) ? + UNDEFINED : -((yyvsp[0].expression).value.integer); + compiler->last_result = yr_parser_emit(yyscanner, OP_INT_MINUS, NULL); + } + else if ((yyvsp[0].expression).type == EXPRESSION_TYPE_FLOAT) + { + (yyval.expression).type = EXPRESSION_TYPE_FLOAT; + compiler->last_result = yr_parser_emit(yyscanner, OP_DBL_MINUS, NULL); + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3506 "grammar.c" /* yacc.c:1662 */ + break; + + case 112: +#line 1777 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "+", (yyvsp[-2].expression), (yyvsp[0].expression)); + + if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && + (yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) + { + int64_t i1 = (yyvsp[-2].expression).value.integer; + int64_t i2 = (yyvsp[0].expression).value.integer; + + if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && + ( + (i2 > 0 && i1 > INT64_MAX - i2) || + (i2 < 0 && i1 < INT64_MIN - i2) + )) + { + yr_compiler_set_error_extra_info_fmt( + compiler, "%" PRId64 " + %" PRId64, i1, i2); + + compiler->last_result = ERROR_INTEGER_OVERFLOW; + } + else + { + (yyval.expression).value.integer = OPERATION(+, i1, i2); + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + } + } + else + { + (yyval.expression).type = EXPRESSION_TYPE_FLOAT; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3545 "grammar.c" /* yacc.c:1662 */ + break; + + case 113: +#line 1812 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "-", (yyvsp[-2].expression), (yyvsp[0].expression)); + + if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && + (yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) + { + int64_t i1 = (yyvsp[-2].expression).value.integer; + int64_t i2 = (yyvsp[0].expression).value.integer; + + if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && + ( + (i2 < 0 && i1 > INT64_MAX + i2) || + (i2 > 0 && i1 < INT64_MIN + i2) + )) + { + yr_compiler_set_error_extra_info_fmt( + compiler, "%" PRId64 " - %" PRId64, i1, i2); + + compiler->last_result = ERROR_INTEGER_OVERFLOW; + } + else + { + (yyval.expression).value.integer = OPERATION(-, i1, i2); + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + } + } + else + { + (yyval.expression).type = EXPRESSION_TYPE_FLOAT; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3584 "grammar.c" /* yacc.c:1662 */ + break; + + case 114: +#line 1847 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "*", (yyvsp[-2].expression), (yyvsp[0].expression)); + + if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && + (yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) + { + int64_t i1 = (yyvsp[-2].expression).value.integer; + int64_t i2 = (yyvsp[0].expression).value.integer; + + if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && + ( + i2 != 0 && llabs(i1) > INT64_MAX / llabs(i2) + )) + { + yr_compiler_set_error_extra_info_fmt( + compiler, "%" PRId64 " * %" PRId64, i1, i2); + + compiler->last_result = ERROR_INTEGER_OVERFLOW; + } + else + { + (yyval.expression).value.integer = OPERATION(*, i1, i2); + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + } + } + else + { + (yyval.expression).type = EXPRESSION_TYPE_FLOAT; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3622 "grammar.c" /* yacc.c:1662 */ + break; + + case 115: +#line 1881 "grammar.y" /* yacc.c:1662 */ + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "\\", (yyvsp[-2].expression), (yyvsp[0].expression)); + + if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && + (yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) + { + if ((yyvsp[0].expression).value.integer != 0) + { + (yyval.expression).value.integer = OPERATION(/, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + } + else + { + compiler->last_result = ERROR_DIVISION_BY_ZERO; + } + } + else + { + (yyval.expression).type = EXPRESSION_TYPE_FLOAT; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3651 "grammar.c" /* yacc.c:1662 */ + break; + + case 116: +#line 1906 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "%"); + check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "%"); + + yr_parser_emit(yyscanner, OP_MOD, NULL); + + if ((yyvsp[0].expression).value.integer != 0) + { + (yyval.expression).value.integer = OPERATION(%, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + } + else + { + compiler->last_result = ERROR_DIVISION_BY_ZERO; + fail_if(compiler->last_result != ERROR_SUCCESS); + } + } +#line 3673 "grammar.c" /* yacc.c:1662 */ + break; + + case 117: +#line 1924 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "^"); + check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "^"); + + yr_parser_emit(yyscanner, OP_BITWISE_XOR, NULL); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = OPERATION(^, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); + } +#line 3687 "grammar.c" /* yacc.c:1662 */ + break; + + case 118: +#line 1934 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "^"); + check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "^"); + + yr_parser_emit(yyscanner, OP_BITWISE_AND, NULL); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = OPERATION(&, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); + } +#line 3701 "grammar.c" /* yacc.c:1662 */ + break; + + case 119: +#line 1944 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "|"); + check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "|"); + + yr_parser_emit(yyscanner, OP_BITWISE_OR, NULL); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = OPERATION(|, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); + } +#line 3715 "grammar.c" /* yacc.c:1662 */ + break; + + case 120: +#line 1954 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "~"); + + yr_parser_emit(yyscanner, OP_BITWISE_NOT, NULL); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + (yyval.expression).value.integer = ((yyvsp[0].expression).value.integer == UNDEFINED) ? + UNDEFINED : ~((yyvsp[0].expression).value.integer); + } +#line 3729 "grammar.c" /* yacc.c:1662 */ + break; + + case 121: +#line 1964 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "<<"); + check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "<<"); + + yr_parser_emit(yyscanner, OP_SHL, NULL); + + if (!IS_UNDEFINED((yyvsp[0].expression).value.integer) && (yyvsp[0].expression).value.integer < 0) + compiler->last_result = ERROR_INVALID_OPERAND; + else if (!IS_UNDEFINED((yyvsp[0].expression).value.integer) && (yyvsp[0].expression).value.integer >= 64) + (yyval.expression).value.integer = 0; + else + (yyval.expression).value.integer = OPERATION(<<, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3751 "grammar.c" /* yacc.c:1662 */ + break; + + case 122: +#line 1982 "grammar.y" /* yacc.c:1662 */ + { + check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, ">>"); + check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, ">>"); + + yr_parser_emit(yyscanner, OP_SHR, NULL); + + if (!IS_UNDEFINED((yyvsp[0].expression).value.integer) && (yyvsp[0].expression).value.integer < 0) + compiler->last_result = ERROR_INVALID_OPERAND; + else if (!IS_UNDEFINED((yyvsp[0].expression).value.integer) && (yyvsp[0].expression).value.integer >= 64) + (yyval.expression).value.integer = 0; + else + (yyval.expression).value.integer = OPERATION(<<, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); + + (yyval.expression).type = EXPRESSION_TYPE_INTEGER; + + fail_if(compiler->last_result != ERROR_SUCCESS); + } +#line 3773 "grammar.c" /* yacc.c:1662 */ + break; + + case 123: +#line 2000 "grammar.y" /* yacc.c:1662 */ + { + (yyval.expression) = (yyvsp[0].expression); + } +#line 3781 "grammar.c" /* yacc.c:1662 */ + break; + + +#line 3785 "grammar.c" /* yacc.c:1662 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (yyscanner, compiler, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yyscanner, compiler, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, yyscanner, compiler); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yyscanner, compiler); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (yyscanner, compiler, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, yyscanner, compiler); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yyscanner, compiler); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 2005 "grammar.y" /* yacc.c:1906 */ + diff --git a/yara-master/libyara/grammar.h b/yara-master/libyara/grammar.h new file mode 100644 index 0000000..dd1949c --- /dev/null +++ b/yara-master/libyara/grammar.h @@ -0,0 +1,180 @@ +/* A Bison parser, made by GNU Bison 3.0.4.18-9674. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_YARA_YY_GRAMMAR_H_INCLUDED +# define YY_YARA_YY_GRAMMAR_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yara_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + _DOT_DOT_ = 258, + _RULE_ = 259, + _PRIVATE_ = 260, + _GLOBAL_ = 261, + _META_ = 262, + _STRINGS_ = 263, + _CONDITION_ = 264, + _IDENTIFIER_ = 265, + _STRING_IDENTIFIER_ = 266, + _STRING_COUNT_ = 267, + _STRING_OFFSET_ = 268, + _STRING_LENGTH_ = 269, + _STRING_IDENTIFIER_WITH_WILDCARD_ = 270, + _NUMBER_ = 271, + _DOUBLE_ = 272, + _INTEGER_FUNCTION_ = 273, + _TEXT_STRING_ = 274, + _HEX_STRING_ = 275, + _REGEXP_ = 276, + _ASCII_ = 277, + _WIDE_ = 278, + _XOR_ = 279, + _NOCASE_ = 280, + _FULLWORD_ = 281, + _AT_ = 282, + _FILESIZE_ = 283, + _ENTRYPOINT_ = 284, + _ALL_ = 285, + _ANY_ = 286, + _IN_ = 287, + _OF_ = 288, + _FOR_ = 289, + _THEM_ = 290, + _MATCHES_ = 291, + _CONTAINS_ = 292, + _IMPORT_ = 293, + _TRUE_ = 294, + _FALSE_ = 295, + _OR_ = 296, + _AND_ = 297, + _EQ_ = 298, + _NEQ_ = 299, + _LT_ = 300, + _LE_ = 301, + _GT_ = 302, + _GE_ = 303, + _SHIFT_LEFT_ = 304, + _SHIFT_RIGHT_ = 305, + _NOT_ = 306, + UNARY_MINUS = 307 + }; +#endif +/* Tokens. */ +#define _DOT_DOT_ 258 +#define _RULE_ 259 +#define _PRIVATE_ 260 +#define _GLOBAL_ 261 +#define _META_ 262 +#define _STRINGS_ 263 +#define _CONDITION_ 264 +#define _IDENTIFIER_ 265 +#define _STRING_IDENTIFIER_ 266 +#define _STRING_COUNT_ 267 +#define _STRING_OFFSET_ 268 +#define _STRING_LENGTH_ 269 +#define _STRING_IDENTIFIER_WITH_WILDCARD_ 270 +#define _NUMBER_ 271 +#define _DOUBLE_ 272 +#define _INTEGER_FUNCTION_ 273 +#define _TEXT_STRING_ 274 +#define _HEX_STRING_ 275 +#define _REGEXP_ 276 +#define _ASCII_ 277 +#define _WIDE_ 278 +#define _XOR_ 279 +#define _NOCASE_ 280 +#define _FULLWORD_ 281 +#define _AT_ 282 +#define _FILESIZE_ 283 +#define _ENTRYPOINT_ 284 +#define _ALL_ 285 +#define _ANY_ 286 +#define _IN_ 287 +#define _OF_ 288 +#define _FOR_ 289 +#define _THEM_ 290 +#define _MATCHES_ 291 +#define _CONTAINS_ 292 +#define _IMPORT_ 293 +#define _TRUE_ 294 +#define _FALSE_ 295 +#define _OR_ 296 +#define _AND_ 297 +#define _EQ_ 298 +#define _NEQ_ 299 +#define _LT_ 300 +#define _LE_ 301 +#define _GT_ 302 +#define _GE_ 303 +#define _SHIFT_LEFT_ 304 +#define _SHIFT_RIGHT_ 305 +#define _NOT_ 306 +#define UNARY_MINUS 307 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 216 "grammar.y" /* yacc.c:1915 */ + + EXPRESSION expression; + SIZED_STRING* sized_string; + char* c_string; + int64_t integer; + double double_; + YR_STRING* string; + YR_META* meta; + YR_RULE* rule; + +#line 169 "grammar.h" /* yacc.c:1915 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int yara_yyparse (void *yyscanner, YR_COMPILER* compiler); + +#endif /* !YY_YARA_YY_GRAMMAR_H_INCLUDED */ diff --git a/yara-master/libyara/grammar.y b/yara-master/libyara/grammar.y new file mode 100644 index 0000000..45e4167 --- /dev/null +++ b/yara-master/libyara/grammar.y @@ -0,0 +1,2005 @@ +/* +Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +%{ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#define llabs _abs64 +#endif + +#define YYERROR_VERBOSE + +#define YYMALLOC yr_malloc +#define YYFREE yr_free + +#define INTEGER_SET_ENUMERATION 1 +#define INTEGER_SET_RANGE 2 + +#define fail_if(x) \ + if (x) \ + { \ + yyerror(yyscanner, compiler, NULL); \ + YYERROR; \ + } \ + + +#define check_type_with_cleanup(expression, expected_type, op, cleanup) \ + if (((expression.type) & (expected_type)) == 0) \ + { \ + switch(expression.type) \ + { \ + case EXPRESSION_TYPE_INTEGER: \ + yr_compiler_set_error_extra_info( \ + compiler, "wrong type \"integer\" for " op " operator"); \ + break; \ + case EXPRESSION_TYPE_FLOAT: \ + yr_compiler_set_error_extra_info( \ + compiler, "wrong type \"float\" for " op " operator"); \ + break; \ + case EXPRESSION_TYPE_STRING: \ + yr_compiler_set_error_extra_info( \ + compiler, "wrong type \"string\" for " op " operator"); \ + break; \ + case EXPRESSION_TYPE_BOOLEAN: \ + yr_compiler_set_error_extra_info( \ + compiler, "wrong type \"boolean\" for " op " operator"); \ + break; \ + } \ + cleanup; \ + compiler->last_result = ERROR_WRONG_TYPE; \ + yyerror(yyscanner, compiler, NULL); \ + YYERROR; \ + } + + +#define check_type(expression, expected_type, op) \ + check_type_with_cleanup(expression, expected_type, op, ) + +%} + + +%expect 1 // expect 1 shift/reduce conflicts + +// Uncomment this line to print parsing information that can be useful to +// debug YARA's grammar. + +// %debug + +%name-prefix "yara_yy" +%pure-parser +%parse-param {void *yyscanner} +%parse-param {YR_COMPILER* compiler} +%lex-param {yyscan_t yyscanner} +%lex-param {YR_COMPILER* compiler} + +%token _DOT_DOT_ +%token _RULE_ +%token _PRIVATE_ +%token _GLOBAL_ +%token _META_ +%token _STRINGS_ +%token _CONDITION_ +%token _IDENTIFIER_ +%token _STRING_IDENTIFIER_ +%token _STRING_COUNT_ +%token _STRING_OFFSET_ +%token _STRING_LENGTH_ +%token _STRING_IDENTIFIER_WITH_WILDCARD_ +%token _NUMBER_ +%token _DOUBLE_ +%token _INTEGER_FUNCTION_ +%token _TEXT_STRING_ +%token _HEX_STRING_ +%token _REGEXP_ +%token _ASCII_ +%token _WIDE_ +%token _XOR_ +%token _NOCASE_ +%token _FULLWORD_ +%token _AT_ +%token _FILESIZE_ +%token _ENTRYPOINT_ +%token _ALL_ +%token _ANY_ +%token _IN_ +%token _OF_ +%token _FOR_ +%token _THEM_ +%token _MATCHES_ +%token _CONTAINS_ +%token _IMPORT_ + +%token _TRUE_ +%token _FALSE_ + +%left _OR_ +%left _AND_ +%left '|' +%left '^' +%left '&' +%left _EQ_ _NEQ_ +%left _LT_ _LE_ _GT_ _GE_ +%left _SHIFT_LEFT_ _SHIFT_RIGHT_ +%left '+' '-' +%left '*' '\\' '%' +%right _NOT_ '~' UNARY_MINUS + +%type rule + +%type strings +%type string_declaration +%type string_declarations + +%type meta +%type meta_declaration +%type meta_declarations + +%type tags +%type tag_list + +%type string_modifier +%type string_modifiers + +%type integer_set + +%type rule_modifier +%type rule_modifiers + +%type primary_expression +%type boolean_expression +%type expression +%type identifier +%type regexp + +%type arguments +%type arguments_list + +%destructor { yr_free($$); $$ = NULL; } _IDENTIFIER_ +%destructor { yr_free($$); $$ = NULL; } _STRING_COUNT_ +%destructor { yr_free($$); $$ = NULL; } _STRING_OFFSET_ +%destructor { yr_free($$); $$ = NULL; } _STRING_LENGTH_ +%destructor { yr_free($$); $$ = NULL; } _STRING_IDENTIFIER_ +%destructor { yr_free($$); $$ = NULL; } _STRING_IDENTIFIER_WITH_WILDCARD_ +%destructor { yr_free($$); $$ = NULL; } _TEXT_STRING_ +%destructor { yr_free($$); $$ = NULL; } _HEX_STRING_ +%destructor { yr_free($$); $$ = NULL; } _REGEXP_ + +%destructor { yr_free($$); $$ = NULL; } arguments +%destructor { yr_free($$); $$ = NULL; } arguments_list + +%union { + EXPRESSION expression; + SIZED_STRING* sized_string; + char* c_string; + int64_t integer; + double double_; + YR_STRING* string; + YR_META* meta; + YR_RULE* rule; +} + + +%% + +rules + : /* empty */ + | rules rule + | rules import + | rules error rule /* on error skip until next rule..*/ + | rules error import /* .. or import statement */ + | rules error "include" /* .. or include statement */ + ; + + +import + : _IMPORT_ _TEXT_STRING_ + { + int result = yr_parser_reduce_import(yyscanner, $2); + + yr_free($2); + + fail_if(result != ERROR_SUCCESS); + } + ; + + +rule + : rule_modifiers _RULE_ _IDENTIFIER_ + { + YR_RULE* rule = yr_parser_reduce_rule_declaration_phase_1( + yyscanner, (int32_t) $1, $3); + + fail_if(rule == NULL); + + $$ = rule; + } + tags '{' meta strings + { + YR_RULE* rule = $4; // rule created in phase 1 + + rule->tags = $5; + rule->metas = $7; + rule->strings = $8; + } + condition '}' + { + YR_RULE* rule = $4; // rule created in phase 1 + + compiler->last_result = yr_parser_reduce_rule_declaration_phase_2( + yyscanner, rule); + + yr_free($3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + ; + + +meta + : /* empty */ + { + $$ = NULL; + } + | _META_ ':' meta_declarations + { + // Each rule have a list of meta-data info, consisting in a + // sequence of YR_META structures. The last YR_META structure does + // not represent a real meta-data, it's just a end-of-list marker + // identified by a specific type (META_TYPE_NULL). Here we + // write the end-of-list marker. + + YR_META null_meta; + + memset(&null_meta, 0xFF, sizeof(YR_META)); + null_meta.type = META_TYPE_NULL; + + compiler->last_result = yr_arena_write_data( + compiler->metas_arena, + &null_meta, + sizeof(YR_META), + NULL); + + $$ = $3; + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + ; + + +strings + : /* empty */ + { + $$ = NULL; + } + | _STRINGS_ ':' string_declarations + { + // Each rule have a list of strings, consisting in a sequence + // of YR_STRING structures. The last YR_STRING structure does not + // represent a real string, it's just a end-of-list marker + // identified by a specific flag (STRING_FLAGS_NULL). Here we + // write the end-of-list marker. + + YR_STRING null_string; + + memset(&null_string, 0xFF, sizeof(YR_STRING)); + null_string.g_flags = STRING_GFLAGS_NULL; + + compiler->last_result = yr_arena_write_data( + compiler->strings_arena, + &null_string, + sizeof(YR_STRING), + NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$ = $3; + } + ; + + +condition + : _CONDITION_ ':' boolean_expression + ; + + +rule_modifiers + : /* empty */ { $$ = 0; } + | rule_modifiers rule_modifier { $$ = $1 | $2; } + ; + + +rule_modifier + : _PRIVATE_ { $$ = RULE_GFLAGS_PRIVATE; } + | _GLOBAL_ { $$ = RULE_GFLAGS_GLOBAL; } + ; + + +tags + : /* empty */ + { + $$ = NULL; + } + | ':' tag_list + { + // Tags list is represented in the arena as a sequence + // of null-terminated strings, the sequence ends with an + // additional null character. Here we write the ending null + //character. Example: tag1\0tag2\0tag3\0\0 + + compiler->last_result = yr_arena_write_string( + yyget_extra(yyscanner)->sz_arena, "", NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$ = $2; + } + ; + + +tag_list + : _IDENTIFIER_ + { + char* identifier; + + compiler->last_result = yr_arena_write_string( + yyget_extra(yyscanner)->sz_arena, $1, &identifier); + + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$ = identifier; + } + | tag_list _IDENTIFIER_ + { + char* tag_name = $1; + size_t tag_length = tag_name != NULL ? strlen(tag_name) : 0; + + while (tag_length > 0) + { + if (strcmp(tag_name, $2) == 0) + { + yr_compiler_set_error_extra_info(compiler, tag_name); + compiler->last_result = ERROR_DUPLICATED_TAG_IDENTIFIER; + break; + } + + tag_name = (char*) yr_arena_next_address( + yyget_extra(yyscanner)->sz_arena, + tag_name, + tag_length + 1); + + tag_length = tag_name != NULL ? strlen(tag_name) : 0; + } + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_arena_write_string( + yyget_extra(yyscanner)->sz_arena, $2, NULL); + + yr_free($2); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$ = $1; + } + ; + + + +meta_declarations + : meta_declaration { $$ = $1; } + | meta_declarations meta_declaration { $$ = $1; } + ; + + +meta_declaration + : _IDENTIFIER_ '=' _TEXT_STRING_ + { + SIZED_STRING* sized_string = $3; + + $$ = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_STRING, + $1, + sized_string->c_string, + 0); + + yr_free($1); + yr_free($3); + + fail_if($$ == NULL); + } + | _IDENTIFIER_ '=' _NUMBER_ + { + $$ = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_INTEGER, + $1, + NULL, + $3); + + yr_free($1); + + fail_if($$ == NULL); + } + | _IDENTIFIER_ '=' '-' _NUMBER_ + { + $$ = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_INTEGER, + $1, + NULL, + -$4); + + yr_free($1); + + fail_if($$ == NULL); + } + | _IDENTIFIER_ '=' _TRUE_ + { + $$ = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_BOOLEAN, + $1, + NULL, + TRUE); + + yr_free($1); + + fail_if($$ == NULL); + } + | _IDENTIFIER_ '=' _FALSE_ + { + $$ = yr_parser_reduce_meta_declaration( + yyscanner, + META_TYPE_BOOLEAN, + $1, + NULL, + FALSE); + + yr_free($1); + + fail_if($$ == NULL); + } + ; + + +string_declarations + : string_declaration { $$ = $1; } + | string_declarations string_declaration { $$ = $1; } + ; + + +string_declaration + : _STRING_IDENTIFIER_ '=' + { + compiler->current_line = yyget_lineno(yyscanner); + } + _TEXT_STRING_ string_modifiers + { + $$ = yr_parser_reduce_string_declaration( + yyscanner, (int32_t) $5, $1, $4); + + yr_free($1); + yr_free($4); + + fail_if($$ == NULL); + compiler->current_line = 0; + } + | _STRING_IDENTIFIER_ '=' + { + compiler->current_line = yyget_lineno(yyscanner); + } + _REGEXP_ string_modifiers + { + $$ = yr_parser_reduce_string_declaration( + yyscanner, (int32_t) $5 | STRING_GFLAGS_REGEXP, $1, $4); + + yr_free($1); + yr_free($4); + + fail_if($$ == NULL); + + compiler->current_line = 0; + } + | _STRING_IDENTIFIER_ '=' _HEX_STRING_ + { + $$ = yr_parser_reduce_string_declaration( + yyscanner, STRING_GFLAGS_HEXADECIMAL, $1, $3); + + yr_free($1); + yr_free($3); + + fail_if($$ == NULL); + } + ; + + +string_modifiers + : /* empty */ { $$ = 0; } + | string_modifiers string_modifier { $$ = $1 | $2; } + ; + + +string_modifier + : _WIDE_ { $$ = STRING_GFLAGS_WIDE; } + | _ASCII_ { $$ = STRING_GFLAGS_ASCII; } + | _NOCASE_ { $$ = STRING_GFLAGS_NO_CASE; } + | _FULLWORD_ { $$ = STRING_GFLAGS_FULL_WORD; } + | _XOR_ { $$ = STRING_GFLAGS_XOR; } + ; + + +identifier + : _IDENTIFIER_ + { + int var_index = yr_parser_lookup_loop_variable(yyscanner, $1); + + if (var_index >= 0) + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, + OP_PUSH_M, + LOOP_LOCAL_VARS * var_index, + NULL, + NULL); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + $$.identifier = compiler->loop_identifier[var_index]; + } + else + { + // Search for identifier within the global namespace, where the + // externals variables reside. + + YR_OBJECT* object = (YR_OBJECT*) yr_hash_table_lookup( + compiler->objects_table, $1, NULL); + + if (object == NULL) + { + // If not found, search within the current namespace. + char* ns = compiler->current_namespace->name; + + object = (YR_OBJECT*) yr_hash_table_lookup( + compiler->objects_table, $1, ns); + } + + if (object != NULL) + { + char* id; + + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, $1, &id); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_OBJ_LOAD, + id, + NULL, + NULL); + + $$.type = EXPRESSION_TYPE_OBJECT; + $$.value.object = object; + $$.identifier = object->identifier; + } + else + { + YR_RULE* rule = (YR_RULE*) yr_hash_table_lookup( + compiler->rules_table, + $1, + compiler->current_namespace->name); + + if (rule != NULL) + { + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_PUSH_RULE, + rule, + NULL, + NULL); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + $$.value.integer = UNDEFINED; + $$.identifier = rule->identifier; + } + else + { + yr_compiler_set_error_extra_info(compiler, $1); + compiler->last_result = ERROR_UNDEFINED_IDENTIFIER; + } + } + } + + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | identifier '.' _IDENTIFIER_ + { + YR_OBJECT* field = NULL; + + if ($1.type == EXPRESSION_TYPE_OBJECT && + $1.value.object->type == OBJECT_TYPE_STRUCTURE) + { + field = yr_object_lookup_field($1.value.object, $3); + + if (field != NULL) + { + char* ident; + + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, $3, &ident); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_OBJ_FIELD, + ident, + NULL, + NULL); + + $$.type = EXPRESSION_TYPE_OBJECT; + $$.value.object = field; + $$.identifier = field->identifier; + } + else + { + yr_compiler_set_error_extra_info(compiler, $3); + compiler->last_result = ERROR_INVALID_FIELD_NAME; + } + } + else + { + yr_compiler_set_error_extra_info( + compiler, $1.identifier); + + compiler->last_result = ERROR_NOT_A_STRUCTURE; + } + + yr_free($3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | identifier '[' primary_expression ']' + { + YR_OBJECT_ARRAY* array; + YR_OBJECT_DICTIONARY* dict; + + if ($1.type == EXPRESSION_TYPE_OBJECT && + $1.value.object->type == OBJECT_TYPE_ARRAY) + { + if ($3.type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "array indexes must be of integer type"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + + compiler->last_result = yr_parser_emit( + yyscanner, OP_INDEX_ARRAY, NULL); + + array = object_as_array($1.value.object); + + $$.type = EXPRESSION_TYPE_OBJECT; + $$.value.object = array->prototype_item; + $$.identifier = array->identifier; + } + else if ($1.type == EXPRESSION_TYPE_OBJECT && + $1.value.object->type == OBJECT_TYPE_DICTIONARY) + { + if ($3.type != EXPRESSION_TYPE_STRING) + { + yr_compiler_set_error_extra_info( + compiler, "dictionary keys must be of string type"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + + compiler->last_result = yr_parser_emit( + yyscanner, OP_LOOKUP_DICT, NULL); + + dict = object_as_dictionary($1.value.object); + + $$.type = EXPRESSION_TYPE_OBJECT; + $$.value.object = dict->prototype_item; + $$.identifier = dict->identifier; + } + else + { + yr_compiler_set_error_extra_info( + compiler, $1.identifier); + + compiler->last_result = ERROR_NOT_INDEXABLE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + + | identifier '(' arguments ')' + { + YR_OBJECT_FUNCTION* function; + char* args_fmt; + + if ($1.type == EXPRESSION_TYPE_OBJECT && + $1.value.object->type == OBJECT_TYPE_FUNCTION) + { + compiler->last_result = yr_parser_check_types( + compiler, object_as_function($1.value.object), $3); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, $3, &args_fmt); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_CALL, + args_fmt, + NULL, + NULL); + + function = object_as_function($1.value.object); + + $$.type = EXPRESSION_TYPE_OBJECT; + $$.value.object = function->return_obj; + $$.identifier = function->identifier; + } + else + { + yr_compiler_set_error_extra_info( + compiler, $1.identifier); + + compiler->last_result = ERROR_NOT_A_FUNCTION; + } + + yr_free($3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + ; + + +arguments + : /* empty */ { $$ = yr_strdup(""); } + | arguments_list { $$ = $1; } + + +arguments_list + : expression + { + $$ = (char*) yr_malloc(MAX_FUNCTION_ARGS + 1); + + switch($1.type) + { + case EXPRESSION_TYPE_INTEGER: + strlcpy($$, "i", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_FLOAT: + strlcpy($$, "f", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_BOOLEAN: + strlcpy($$, "b", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_STRING: + strlcpy($$, "s", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_REGEXP: + strlcpy($$, "r", MAX_FUNCTION_ARGS); + break; + default: + assert(FALSE); + } + + fail_if($$ == NULL); + } + | arguments_list ',' expression + { + if (strlen($1) == MAX_FUNCTION_ARGS) + { + compiler->last_result = ERROR_TOO_MANY_ARGUMENTS; + } + else + { + switch($3.type) + { + case EXPRESSION_TYPE_INTEGER: + strlcat($1, "i", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_FLOAT: + strlcat($1, "f", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_BOOLEAN: + strlcat($1, "b", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_STRING: + strlcat($1, "s", MAX_FUNCTION_ARGS); + break; + case EXPRESSION_TYPE_REGEXP: + strlcat($1, "r", MAX_FUNCTION_ARGS); + break; + default: + assert(FALSE); + } + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$ = $1; + } + ; + + +regexp + : _REGEXP_ + { + SIZED_STRING* sized_string = $1; + RE* re; + RE_ERROR error; + + int re_flags = 0; + + if (sized_string->flags & SIZED_STRING_FLAGS_NO_CASE) + re_flags |= RE_FLAGS_NO_CASE; + + if (sized_string->flags & SIZED_STRING_FLAGS_DOT_ALL) + re_flags |= RE_FLAGS_DOT_ALL; + + compiler->last_result = yr_re_compile( + sized_string->c_string, + re_flags, + compiler->re_code_arena, + &re, + &error); + + yr_free($1); + + if (compiler->last_result == ERROR_INVALID_REGULAR_EXPRESSION) + yr_compiler_set_error_extra_info(compiler, error.message); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_PUSH, + re, + NULL, + NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_REGEXP; + } + ; + + +boolean_expression + : expression + { + if ($1.type == EXPRESSION_TYPE_STRING) + { + if ($1.value.sized_string != NULL) + { + yywarning(yyscanner, + "Using literal string \"%s\" in a boolean operation.", + $1.value.sized_string->c_string); + } + + compiler->last_result = yr_parser_emit( + yyscanner, OP_STR_TO_BOOL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + ; + +expression + : _TRUE_ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, 1, NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | _FALSE_ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, 0, NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression _MATCHES_ regexp + { + check_type($1, EXPRESSION_TYPE_STRING, "matches"); + check_type($3, EXPRESSION_TYPE_REGEXP, "matches"); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit( + yyscanner, + OP_MATCHES, + NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression _CONTAINS_ primary_expression + { + check_type($1, EXPRESSION_TYPE_STRING, "contains"); + check_type($3, EXPRESSION_TYPE_STRING, "contains"); + + compiler->last_result = yr_parser_emit( + yyscanner, OP_CONTAINS, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | _STRING_IDENTIFIER_ + { + int result = yr_parser_reduce_string_identifier( + yyscanner, + $1, + OP_FOUND, + UNDEFINED); + + yr_free($1); + + fail_if(result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | _STRING_IDENTIFIER_ _AT_ primary_expression + { + check_type_with_cleanup($3, EXPRESSION_TYPE_INTEGER, "at", yr_free($1)); + + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, $1, OP_FOUND_AT, $3.value.integer); + + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | _STRING_IDENTIFIER_ _IN_ range + { + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, $1, OP_FOUND_IN, UNDEFINED); + + yr_free($1); + + fail_if(compiler->last_result!= ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | _FOR_ for_expression error + { + if (compiler->loop_depth > 0) + { + compiler->loop_depth--; + compiler->loop_identifier[compiler->loop_depth] = NULL; + } + + YYERROR; + } + | _FOR_ for_expression _IDENTIFIER_ _IN_ + { + int var_index; + + if (compiler->loop_depth == MAX_LOOP_NESTING) + compiler->last_result = \ + ERROR_LOOP_NESTING_LIMIT_EXCEEDED; + + fail_if(compiler->last_result != ERROR_SUCCESS); + + var_index = yr_parser_lookup_loop_variable( + yyscanner, $3); + + if (var_index >= 0) + { + yr_compiler_set_error_extra_info( + compiler, $3); + + compiler->last_result = \ + ERROR_DUPLICATED_LOOP_IDENTIFIER; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + + // Push end-of-list marker + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, UNDEFINED, NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + integer_set ':' + { + int mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth; + uint8_t* addr; + + // Clear counter for number of expressions evaluating + // to TRUE. + yr_parser_emit_with_arg( + yyscanner, OP_CLEAR_M, mem_offset + 1, NULL, NULL); + + // Clear iterations counter + yr_parser_emit_with_arg( + yyscanner, OP_CLEAR_M, mem_offset + 2, NULL, NULL); + + if ($6 == INTEGER_SET_ENUMERATION) + { + // Pop the first integer + yr_parser_emit_with_arg( + yyscanner, OP_POP_M, mem_offset, &addr, NULL); + } + else // INTEGER_SET_RANGE + { + // Pop higher bound of set range + yr_parser_emit_with_arg( + yyscanner, OP_POP_M, mem_offset + 3, &addr, NULL); + + // Pop lower bound of set range + yr_parser_emit_with_arg( + yyscanner, OP_POP_M, mem_offset, NULL, NULL); + } + + compiler->loop_address[compiler->loop_depth] = addr; + compiler->loop_identifier[compiler->loop_depth] = $3; + compiler->loop_depth++; + } + '(' boolean_expression ')' + { + int mem_offset; + + compiler->loop_depth--; + mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth; + + // The value at the top of the stack is the result of + // evaluating the boolean expression, so it could be + // 0, 1 or UNDEFINED. Add this value to a counter + // keeping the number of expressions evaluating to true. + // If the value is UNDEFINED instruction OP_ADD_M + // does nothing. + + yr_parser_emit_with_arg( + yyscanner, OP_ADD_M, mem_offset + 1, NULL, NULL); + + // Increment iterations counter + yr_parser_emit_with_arg( + yyscanner, OP_INCR_M, mem_offset + 2, NULL, NULL); + + if ($6 == INTEGER_SET_ENUMERATION) + { + yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JNUNDEF, + compiler->loop_address[compiler->loop_depth], + NULL, + NULL); + } + else // INTEGER_SET_RANGE + { + // Increment lower bound of integer set + yr_parser_emit_with_arg( + yyscanner, OP_INCR_M, mem_offset, NULL, NULL); + + // Push lower bound of integer set + yr_parser_emit_with_arg( + yyscanner, OP_PUSH_M, mem_offset, NULL, NULL); + + // Push higher bound of integer set + yr_parser_emit_with_arg( + yyscanner, OP_PUSH_M, mem_offset + 3, NULL, NULL); + + // Compare higher bound with lower bound, do loop again + // if lower bound is still lower or equal than higher bound + yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JLE, + compiler->loop_address[compiler->loop_depth], + NULL, + NULL); + + yr_parser_emit(yyscanner, OP_POP, NULL); + yr_parser_emit(yyscanner, OP_POP, NULL); + } + + // Pop end-of-list marker. + yr_parser_emit(yyscanner, OP_POP, NULL); + + // At this point the loop quantifier (any, all, 1, 2,..) + // is at the top of the stack. Check if the quantifier + // is undefined (meaning "all") and replace it with the + // iterations counter in that case. + yr_parser_emit_with_arg( + yyscanner, OP_SWAPUNDEF, mem_offset + 2, NULL, NULL); + + // Compare the loop quantifier with the number of + // expressions evaluating to TRUE. + yr_parser_emit_with_arg( + yyscanner, OP_PUSH_M, mem_offset + 1, NULL, NULL); + + yr_parser_emit(yyscanner, OP_INT_LE, NULL); + + compiler->loop_identifier[compiler->loop_depth] = NULL; + yr_free($3); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | _FOR_ for_expression _OF_ string_set ':' + { + int mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth; + uint8_t* addr; + + if (compiler->loop_depth == MAX_LOOP_NESTING) + compiler->last_result = \ + ERROR_LOOP_NESTING_LIMIT_EXCEEDED; + + if (compiler->loop_for_of_mem_offset != -1) + compiler->last_result = \ + ERROR_NESTED_FOR_OF_LOOP; + + fail_if(compiler->last_result != ERROR_SUCCESS); + + yr_parser_emit_with_arg( + yyscanner, OP_CLEAR_M, mem_offset + 1, NULL, NULL); + + yr_parser_emit_with_arg( + yyscanner, OP_CLEAR_M, mem_offset + 2, NULL, NULL); + + // Pop the first string. + yr_parser_emit_with_arg( + yyscanner, OP_POP_M, mem_offset, &addr, NULL); + + compiler->loop_for_of_mem_offset = mem_offset; + compiler->loop_address[compiler->loop_depth] = addr; + compiler->loop_identifier[compiler->loop_depth] = NULL; + compiler->loop_depth++; + } + '(' boolean_expression ')' + { + int mem_offset; + + compiler->loop_depth--; + compiler->loop_for_of_mem_offset = -1; + + mem_offset = LOOP_LOCAL_VARS * compiler->loop_depth; + + // Increment counter by the value returned by the + // boolean expression (0 or 1). If the boolean expression + // returned UNDEFINED the OP_ADD_M won't do anything. + + yr_parser_emit_with_arg( + yyscanner, OP_ADD_M, mem_offset + 1, NULL, NULL); + + // Increment iterations counter. + yr_parser_emit_with_arg( + yyscanner, OP_INCR_M, mem_offset + 2, NULL, NULL); + + // If next string is not undefined, go back to the + // beginning of the loop. + yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JNUNDEF, + compiler->loop_address[compiler->loop_depth], + NULL, + NULL); + + // Pop end-of-list marker. + yr_parser_emit(yyscanner, OP_POP, NULL); + + // At this point the loop quantifier (any, all, 1, 2,..) + // is at top of the stack. Check if the quantifier is + // undefined (meaning "all") and replace it with the + // iterations counter in that case. + yr_parser_emit_with_arg( + yyscanner, OP_SWAPUNDEF, mem_offset + 2, NULL, NULL); + + // Compare the loop quantifier with the number of + // expressions evaluating to TRUE. + yr_parser_emit_with_arg( + yyscanner, OP_PUSH_M, mem_offset + 1, NULL, NULL); + + yr_parser_emit(yyscanner, OP_INT_LE, NULL); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + + } + | for_expression _OF_ string_set + { + yr_parser_emit(yyscanner, OP_OF, NULL); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | _NOT_ boolean_expression + { + yr_parser_emit(yyscanner, OP_NOT, NULL); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | boolean_expression _AND_ + { + YR_FIXUP* fixup; + void* jmp_destination_addr; + + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JFALSE, + 0, // still don't know the jump destination + NULL, + &jmp_destination_addr); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + // create a fixup entry for the jump and push it in the stack + fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); + + if (fixup == NULL) + compiler->last_error = ERROR_INSUFFICIENT_MEMORY; + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup->address = jmp_destination_addr; + fixup->next = compiler->fixup_stack_head; + compiler->fixup_stack_head = fixup; + } + boolean_expression + { + YR_FIXUP* fixup; + uint8_t* nop_addr; + + compiler->last_result = yr_parser_emit(yyscanner, OP_AND, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + // Generate a do-nothing instruction (NOP) in order to get its address + // and use it as the destination for the OP_JFALSE. We can not simply + // use the address of the OP_AND instruction +1 because we can't be + // sure that the instruction following the OP_AND is going to be in + // the same arena page. As we don't have a reliable way of getting the + // address of the next instruction we generate the OP_NOP. + + compiler->last_result = yr_parser_emit(yyscanner, OP_NOP, &nop_addr); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup = compiler->fixup_stack_head; + *(void**)(fixup->address) = (void*) nop_addr; + compiler->fixup_stack_head = fixup->next; + yr_free(fixup); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | boolean_expression _OR_ + { + YR_FIXUP* fixup; + void* jmp_destination_addr; + + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_JTRUE, + 0, // still don't know the jump destination + NULL, + &jmp_destination_addr); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); + + if (fixup == NULL) + compiler->last_error = ERROR_INSUFFICIENT_MEMORY; + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup->address = jmp_destination_addr; + fixup->next = compiler->fixup_stack_head; + compiler->fixup_stack_head = fixup; + } + boolean_expression + { + YR_FIXUP* fixup; + uint8_t* nop_addr; + + compiler->last_result = yr_parser_emit(yyscanner, OP_OR, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + // Generate a do-nothing instruction (NOP) in order to get its address + // and use it as the destination for the OP_JFALSE. We can not simply + // use the address of the OP_OR instruction +1 because we can't be + // sure that the instruction following the OP_AND is going to be in + // the same arena page. As we don't have a reliable way of getting the + // address of the next instruction we generate the OP_NOP. + + compiler->last_result = yr_parser_emit(yyscanner, OP_NOP, &nop_addr); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + fixup = compiler->fixup_stack_head; + *(void**)(fixup->address) = (void*)(nop_addr); + compiler->fixup_stack_head = fixup->next; + yr_free(fixup); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression _LT_ primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "<", $1, $3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression _GT_ primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, ">", $1, $3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression _LE_ primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "<=", $1, $3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression _GE_ primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, ">=", $1, $3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression _EQ_ primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "==", $1, $3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression _NEQ_ primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "!=", $1, $3); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_BOOLEAN; + } + | primary_expression + { + $$ = $1; + } + |'(' expression ')' + { + $$ = $2; + } + ; + + +integer_set + : '(' integer_enumeration ')' { $$ = INTEGER_SET_ENUMERATION; } + | range { $$ = INTEGER_SET_RANGE; } + ; + + +range + : '(' primary_expression _DOT_DOT_ primary_expression ')' + { + if ($2.type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "wrong type for range's lower bound"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + if ($4.type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "wrong type for range's upper bound"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + ; + + +integer_enumeration + : primary_expression + { + if ($1.type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "wrong type for enumeration item"); + compiler->last_result = ERROR_WRONG_TYPE; + + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | integer_enumeration ',' primary_expression + { + if ($3.type != EXPRESSION_TYPE_INTEGER) + { + yr_compiler_set_error_extra_info( + compiler, "wrong type for enumeration item"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + ; + + +string_set + : '(' + { + // Push end-of-list marker + yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL, NULL); + } + string_enumeration ')' + | _THEM_ + { + yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL, NULL); + yr_parser_emit_pushes_for_strings(yyscanner, "$*"); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + ; + + +string_enumeration + : string_enumeration_item + | string_enumeration ',' string_enumeration_item + ; + + +string_enumeration_item + : _STRING_IDENTIFIER_ + { + yr_parser_emit_pushes_for_strings(yyscanner, $1); + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | _STRING_IDENTIFIER_WITH_WILDCARD_ + { + yr_parser_emit_pushes_for_strings(yyscanner, $1); + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + ; + + +for_expression + : primary_expression + | _ALL_ + { + yr_parser_emit_with_arg(yyscanner, OP_PUSH, UNDEFINED, NULL, NULL); + } + | _ANY_ + { + yr_parser_emit_with_arg(yyscanner, OP_PUSH, 1, NULL, NULL); + } + ; + + +primary_expression + : '(' primary_expression ')' + { + $$ = $2; + } + | _FILESIZE_ + { + compiler->last_result = yr_parser_emit( + yyscanner, OP_FILESIZE, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + | _ENTRYPOINT_ + { + yywarning(yyscanner, + "Using deprecated \"entrypoint\" keyword. Use the \"entry_point\" " + "function from PE module instead."); + + compiler->last_result = yr_parser_emit( + yyscanner, OP_ENTRYPOINT, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + | _INTEGER_FUNCTION_ '(' primary_expression ')' + { + check_type($3, EXPRESSION_TYPE_INTEGER, "intXXXX or uintXXXX"); + + // _INTEGER_FUNCTION_ could be any of int8, int16, int32, uint8, + // uint32, etc. $1 contains an index that added to OP_READ_INT results + // in the proper OP_INTXX opcode. + + compiler->last_result = yr_parser_emit( + yyscanner, (uint8_t) (OP_READ_INT + $1), NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + | _NUMBER_ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, $1, NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = $1; + } + | _DOUBLE_ + { + compiler->last_result = yr_parser_emit_with_arg_double( + yyscanner, OP_PUSH, $1, NULL, NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_FLOAT; + } + | _TEXT_STRING_ + { + SIZED_STRING* sized_string; + + compiler->last_result = yr_arena_write_data( + compiler->sz_arena, + $1, + $1->length + sizeof(SIZED_STRING), + (void**) &sized_string); + + yr_free($1); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_PUSH, + sized_string, + NULL, + NULL); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_STRING; + $$.value.sized_string = sized_string; + } + | _STRING_COUNT_ + { + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, $1, OP_COUNT, UNDEFINED); + + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + | _STRING_OFFSET_ '[' primary_expression ']' + { + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, $1, OP_OFFSET, UNDEFINED); + + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + | _STRING_OFFSET_ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, 1, NULL, NULL); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, $1, OP_OFFSET, UNDEFINED); + + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + | _STRING_LENGTH_ '[' primary_expression ']' + { + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, $1, OP_LENGTH, UNDEFINED); + + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + | _STRING_LENGTH_ + { + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, OP_PUSH, 1, NULL, NULL); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_reduce_string_identifier( + yyscanner, $1, OP_LENGTH, UNDEFINED); + + yr_free($1); + + fail_if(compiler->last_result != ERROR_SUCCESS); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + | identifier + { + if ($1.type == EXPRESSION_TYPE_INTEGER) // loop identifier + { + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + } + else if ($1.type == EXPRESSION_TYPE_BOOLEAN) // rule identifier + { + $$.type = EXPRESSION_TYPE_BOOLEAN; + $$.value.integer = UNDEFINED; + } + else if ($1.type == EXPRESSION_TYPE_OBJECT) + { + compiler->last_result = yr_parser_emit( + yyscanner, OP_OBJ_VALUE, NULL); + + switch($1.value.object->type) + { + case OBJECT_TYPE_INTEGER: + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = UNDEFINED; + break; + case OBJECT_TYPE_FLOAT: + $$.type = EXPRESSION_TYPE_FLOAT; + break; + case OBJECT_TYPE_STRING: + $$.type = EXPRESSION_TYPE_STRING; + $$.value.sized_string = NULL; + break; + default: + yr_compiler_set_error_extra_info_fmt( + compiler, + "wrong usage of identifier \"%s\"", + $1.identifier); + compiler->last_result = ERROR_WRONG_TYPE; + } + } + else + { + assert(FALSE); + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | '-' primary_expression %prec UNARY_MINUS + { + check_type($2, EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT, "-"); + + if ($2.type == EXPRESSION_TYPE_INTEGER) + { + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = ($2.value.integer == UNDEFINED) ? + UNDEFINED : -($2.value.integer); + compiler->last_result = yr_parser_emit(yyscanner, OP_INT_MINUS, NULL); + } + else if ($2.type == EXPRESSION_TYPE_FLOAT) + { + $$.type = EXPRESSION_TYPE_FLOAT; + compiler->last_result = yr_parser_emit(yyscanner, OP_DBL_MINUS, NULL); + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | primary_expression '+' primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "+", $1, $3); + + if ($1.type == EXPRESSION_TYPE_INTEGER && + $3.type == EXPRESSION_TYPE_INTEGER) + { + int64_t i1 = $1.value.integer; + int64_t i2 = $3.value.integer; + + if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && + ( + (i2 > 0 && i1 > INT64_MAX - i2) || + (i2 < 0 && i1 < INT64_MIN - i2) + )) + { + yr_compiler_set_error_extra_info_fmt( + compiler, "%" PRId64 " + %" PRId64, i1, i2); + + compiler->last_result = ERROR_INTEGER_OVERFLOW; + } + else + { + $$.value.integer = OPERATION(+, i1, i2); + $$.type = EXPRESSION_TYPE_INTEGER; + } + } + else + { + $$.type = EXPRESSION_TYPE_FLOAT; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | primary_expression '-' primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "-", $1, $3); + + if ($1.type == EXPRESSION_TYPE_INTEGER && + $3.type == EXPRESSION_TYPE_INTEGER) + { + int64_t i1 = $1.value.integer; + int64_t i2 = $3.value.integer; + + if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && + ( + (i2 < 0 && i1 > INT64_MAX + i2) || + (i2 > 0 && i1 < INT64_MIN + i2) + )) + { + yr_compiler_set_error_extra_info_fmt( + compiler, "%" PRId64 " - %" PRId64, i1, i2); + + compiler->last_result = ERROR_INTEGER_OVERFLOW; + } + else + { + $$.value.integer = OPERATION(-, i1, i2); + $$.type = EXPRESSION_TYPE_INTEGER; + } + } + else + { + $$.type = EXPRESSION_TYPE_FLOAT; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | primary_expression '*' primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "*", $1, $3); + + if ($1.type == EXPRESSION_TYPE_INTEGER && + $3.type == EXPRESSION_TYPE_INTEGER) + { + int64_t i1 = $1.value.integer; + int64_t i2 = $3.value.integer; + + if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && + ( + i2 != 0 && llabs(i1) > INT64_MAX / llabs(i2) + )) + { + yr_compiler_set_error_extra_info_fmt( + compiler, "%" PRId64 " * %" PRId64, i1, i2); + + compiler->last_result = ERROR_INTEGER_OVERFLOW; + } + else + { + $$.value.integer = OPERATION(*, i1, i2); + $$.type = EXPRESSION_TYPE_INTEGER; + } + } + else + { + $$.type = EXPRESSION_TYPE_FLOAT; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | primary_expression '\\' primary_expression + { + compiler->last_result = yr_parser_reduce_operation( + yyscanner, "\\", $1, $3); + + if ($1.type == EXPRESSION_TYPE_INTEGER && + $3.type == EXPRESSION_TYPE_INTEGER) + { + if ($3.value.integer != 0) + { + $$.value.integer = OPERATION(/, $1.value.integer, $3.value.integer); + $$.type = EXPRESSION_TYPE_INTEGER; + } + else + { + compiler->last_result = ERROR_DIVISION_BY_ZERO; + } + } + else + { + $$.type = EXPRESSION_TYPE_FLOAT; + } + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | primary_expression '%' primary_expression + { + check_type($1, EXPRESSION_TYPE_INTEGER, "%"); + check_type($3, EXPRESSION_TYPE_INTEGER, "%"); + + yr_parser_emit(yyscanner, OP_MOD, NULL); + + if ($3.value.integer != 0) + { + $$.value.integer = OPERATION(%, $1.value.integer, $3.value.integer); + $$.type = EXPRESSION_TYPE_INTEGER; + } + else + { + compiler->last_result = ERROR_DIVISION_BY_ZERO; + fail_if(compiler->last_result != ERROR_SUCCESS); + } + } + | primary_expression '^' primary_expression + { + check_type($1, EXPRESSION_TYPE_INTEGER, "^"); + check_type($3, EXPRESSION_TYPE_INTEGER, "^"); + + yr_parser_emit(yyscanner, OP_BITWISE_XOR, NULL); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = OPERATION(^, $1.value.integer, $3.value.integer); + } + | primary_expression '&' primary_expression + { + check_type($1, EXPRESSION_TYPE_INTEGER, "^"); + check_type($3, EXPRESSION_TYPE_INTEGER, "^"); + + yr_parser_emit(yyscanner, OP_BITWISE_AND, NULL); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = OPERATION(&, $1.value.integer, $3.value.integer); + } + | primary_expression '|' primary_expression + { + check_type($1, EXPRESSION_TYPE_INTEGER, "|"); + check_type($3, EXPRESSION_TYPE_INTEGER, "|"); + + yr_parser_emit(yyscanner, OP_BITWISE_OR, NULL); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = OPERATION(|, $1.value.integer, $3.value.integer); + } + | '~' primary_expression + { + check_type($2, EXPRESSION_TYPE_INTEGER, "~"); + + yr_parser_emit(yyscanner, OP_BITWISE_NOT, NULL); + + $$.type = EXPRESSION_TYPE_INTEGER; + $$.value.integer = ($2.value.integer == UNDEFINED) ? + UNDEFINED : ~($2.value.integer); + } + | primary_expression _SHIFT_LEFT_ primary_expression + { + check_type($1, EXPRESSION_TYPE_INTEGER, "<<"); + check_type($3, EXPRESSION_TYPE_INTEGER, "<<"); + + yr_parser_emit(yyscanner, OP_SHL, NULL); + + if (!IS_UNDEFINED($3.value.integer) && $3.value.integer < 0) + compiler->last_result = ERROR_INVALID_OPERAND; + else if (!IS_UNDEFINED($3.value.integer) && $3.value.integer >= 64) + $$.value.integer = 0; + else + $$.value.integer = OPERATION(<<, $1.value.integer, $3.value.integer); + + $$.type = EXPRESSION_TYPE_INTEGER; + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | primary_expression _SHIFT_RIGHT_ primary_expression + { + check_type($1, EXPRESSION_TYPE_INTEGER, ">>"); + check_type($3, EXPRESSION_TYPE_INTEGER, ">>"); + + yr_parser_emit(yyscanner, OP_SHR, NULL); + + if (!IS_UNDEFINED($3.value.integer) && $3.value.integer < 0) + compiler->last_result = ERROR_INVALID_OPERAND; + else if (!IS_UNDEFINED($3.value.integer) && $3.value.integer >= 64) + $$.value.integer = 0; + else + $$.value.integer = OPERATION(<<, $1.value.integer, $3.value.integer); + + $$.type = EXPRESSION_TYPE_INTEGER; + + fail_if(compiler->last_result != ERROR_SUCCESS); + } + | regexp + { + $$ = $1; + } + ; + +%% diff --git a/yara-master/libyara/hash.c b/yara-master/libyara/hash.c new file mode 100644 index 0000000..79dac10 --- /dev/null +++ b/yara-master/libyara/hash.c @@ -0,0 +1,365 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#include +#include +#include +#include + +// Constant-time left rotate that does not invoke undefined behavior. +// http://blog.regehr.org/archives/1063 +static uint32_t rotl32(uint32_t x, uint32_t shift) { + assert(shift < 32); + return (x << shift) | (x >> (-shift & 31)); +} + +#define ROTATE_INT32(x, shift) \ + rotl32(x, shift % 32) + +uint32_t byte_to_int32[] = +{ + 0xC3113E7F,0x4C353C5F,0x7423810B,0x258D264E,0xDAD39DED,0x75D0B694,0x98CE1216, + 0x93334482,0xC5C48EA5,0xF57E0E8B,0x5D7F3723,0x396B1B24,0xA8883D9F,0xB2A74A00, + 0xF8E171AE,0x3F01FBAB,0x5C1840CB,0xDDD833C4,0x8D8CCA34,0x32EF223A,0x1A05B871, + 0x9A9B6BFC,0x50406A0C,0xE7E1FC04,0x5E07D7F6,0x80B83660,0x20892A62,0xB2C6FEA6, + 0x6CEC7CAA,0x182F764B,0x3B0353E7,0x57FC2520,0x4B6812D4,0xACB654E4,0x23C75C04, + 0xB1DCD731,0xE3AF0733,0xF2366D39,0xC729671B,0xFF3BE6F2,0xABA37E34,0x3CDAFA38, + 0xAAD18D03,0xA8D35345,0x08E9A92C,0xF9324059,0x42D821BE,0x1BC152DD,0x5588811C, + 0x874A1F9A,0x6E83E9CD,0xDA6F3AF8,0x965D4670,0xA7A565C0,0x68D8A9AF,0xFC8FD8FD, + 0x8FF99FF9,0x4C9B42AE,0x2D066A8D,0x4D1802F7,0x557032B2,0x12BCF371,0xDC29D5AE, + 0x72EA361F,0xE2835B0B,0xDFC58966,0x13B0F34D,0x3FA02BCD,0xBF282E3D,0x7DC877F5, + 0xF4848A32,0x861E35F5,0x7FFA0D7F,0x515F2E4E,0x6B235D5C,0x55F46E24,0x35AD2C99, + 0x072654A8,0x05163F0F,0x9317B11A,0xAED1FC10,0x989444F0,0xDB3E1814,0x446C0CF1, + 0x660BF511,0x2F227D3A,0xFDBA0539,0xC649E621,0x5204D7CE,0x5FA386D0,0xE5F22005, + 0x97B6C8A1,0x4AB69EC2,0x5C7CA70D,0x39A48EC6,0x7BACF378,0x8D0ED3D1,0xE39DE582, + 0xC5FBE2AB,0x37E3D2D0,0x06F44724,0x73144144,0xBA57E905,0xB05B4307,0xAEED8D97, + 0xA68CCAC4,0xE30DA57E,0xED0F194B,0x8C2B9B7A,0x814575D5,0x79588493,0x81D3712A, + 0x3FA892F2,0x80F0BB94,0x44EAF51A,0x4E05F1D4,0xFC69F858,0x775E8D60,0x22B20DD7, + 0x170A87EA,0x1077DE52,0x3D5EC9FB,0x0B6EB1E5,0xF2F9CCAF,0xA76C7DEB,0xD8C2D873, + 0xF438C592,0x6239FEEC,0x26D3D2A9,0x30F6FADF,0x4B2984CC,0x6257F3DA,0x0E0583E2, + 0x143E5E61,0xBB2732BF,0x9653217A,0x027A84EA,0x95C9AE8B,0x89B8B82B,0x9F286485, + 0x29F622FE,0x52A3196B,0x8392D95F,0x33A79167,0xF5DEE92A,0x6E397DB9,0x11931C01, + 0x8DD2CD3B,0xF9E6003D,0xAB955AF4,0xD38725F9,0xDCF6F8AE,0x7667A958,0xE67AD995, + 0xB7CF979A,0xD88EBE5B,0x5BA889F0,0x078BDD90,0x447238F9,0x3135F672,0x187B95A8, + 0x0B7D5751,0xACD59D2A,0x9C5D1929,0x579E5022,0xEA90499B,0x59901800,0x82237DB5, + 0x7A375509,0xACA9A22A,0xEC96E649,0x69339DB0,0x081D0D9B,0xD72FB8B9,0xA4184653, + 0xC057321D,0xED19CAB9,0xB48F1E3E,0xB9DAC51E,0xDAED2FC7,0x7598CBBD,0x208DF346, + 0x044BE6EC,0x1C63E6EB,0xA15F64C1,0xE024A061,0x68309584,0x0758A68D,0xF274E9AE, + 0x0ABEA0CC,0xED4FB267,0x63D6EC46,0x9F28E026,0xF0694A17,0x9D6E9115,0xC4600FAD, + 0x5B121E99,0xD6B4A13B,0xF5364B8A,0x8514B254,0x0182F8DD,0xDB09F90B,0x78C70B32, + 0xD8EC3B02,0x8CD7084D,0xA4439838,0x72F35A3D,0x200B48A5,0xE2351444,0xA5552F5F, + 0xD8C1E746,0x0FE5EF3C,0xB6A47063,0x61F4E68B,0x08FED99B,0x7E461445,0x43CB8380, + 0x28BA03C8,0x21A7A2E2,0x43437ED6,0x2A9E6670,0x89B4A106,0xC6C2F4EE,0x9C4063CC, + 0x2FA0DF6C,0xB54DC409,0xCF01538F,0x616431D7,0x02CB0E4D,0x44FFF425,0xAAD5188E, + 0x0742E9BC,0xFFF41353,0x130F0A15,0x787BDC10,0x4A327B72,0x702989F7,0x5F704798, + 0x8156A1BB,0x2BCA3E74,0x1911A8C4,0x5E1F27D3,0x07949DC7,0xF24C2056,0xB4299EE6, + 0x9C7045D9,0xA8BF6307,0x7454AAD2,0x256425E5,0xD87DEF67,0xCFE95452,0xE7548DF7, + 0xA84956C7,0xD8402C60,0xCFBD0373,0x6B6CDAFE +}; + + +uint32_t yr_hash( + uint32_t seed, + const void* buffer, + size_t len) +{ + const uint8_t* b = (uint8_t*) buffer; + + uint32_t result = seed; + size_t i; + + assert(len > 0); + + for (i = len - 1; i > 0; i--) + { + result ^= ROTATE_INT32(byte_to_int32[*b], i); + b++; + } + + result ^= byte_to_int32[*b]; + return result; +} + +// _yr_hash_table_lookup +// +// Return the value associated to a given key and optionally remove it from +// the hash table. Key can be any byte sequence, namespace is a null-terminated +// string, and remove is a boolean. + +static void* _yr_hash_table_lookup( + YR_HASH_TABLE* table, + const void* key, + size_t key_length, + const char* ns, + int remove) +{ + YR_HASH_TABLE_ENTRY* entry; + YR_HASH_TABLE_ENTRY* prev_entry; + + void* result; + + uint32_t bucket_index = yr_hash(0, key, key_length); + + if (ns != NULL) + bucket_index = yr_hash(bucket_index, (uint8_t*) ns, strlen(ns)); + + bucket_index = bucket_index % table->size; + prev_entry = NULL; + entry = table->buckets[bucket_index]; + + while (entry != NULL) + { + int key_match = ( + (entry->key_length == key_length) && + (memcmp(entry->key, key, key_length) == 0)); + + int ns_match = ( + (entry->ns == ns) || + (entry->ns != NULL && ns != NULL && strcmp(entry->ns, ns) == 0)); + + if (key_match && ns_match) + { + result = entry->value; + + if (remove) + { + if (prev_entry == NULL) + table->buckets[bucket_index] = entry->next; + else + prev_entry->next = entry->next; + + if (entry->ns != NULL) + yr_free(entry->ns); + + yr_free(entry->key); + yr_free(entry); + } + + return result; + } + + prev_entry = entry; + entry = entry->next; + } + + return NULL; +} + + +YR_API int yr_hash_table_create( + int size, + YR_HASH_TABLE** table) +{ + YR_HASH_TABLE* new_table; + int i; + + new_table = (YR_HASH_TABLE*) yr_malloc( + sizeof(YR_HASH_TABLE) + size * sizeof(YR_HASH_TABLE_ENTRY*)); + + if (new_table == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + new_table->size = size; + + for (i = 0; i < size; i++) + new_table->buckets[i] = NULL; + + *table = new_table; + + return ERROR_SUCCESS; +} + + +YR_API void yr_hash_table_clean( + YR_HASH_TABLE* table, + YR_HASH_TABLE_FREE_VALUE_FUNC free_value) +{ + YR_HASH_TABLE_ENTRY* entry; + YR_HASH_TABLE_ENTRY* next_entry; + + int i; + + if (table == NULL) + return; + + for (i = 0; i < table->size; i++) + { + entry = table->buckets[i]; + + while (entry != NULL) + { + next_entry = entry->next; + + if (free_value != NULL) + free_value(entry->value); + + if (entry->ns != NULL) + yr_free(entry->ns); + + yr_free(entry->key); + yr_free(entry); + + entry = next_entry; + } + + table->buckets[i] = NULL; + } +} + + +YR_API void yr_hash_table_destroy( + YR_HASH_TABLE* table, + YR_HASH_TABLE_FREE_VALUE_FUNC free_value) +{ + yr_hash_table_clean(table, free_value); + yr_free(table); +} + + +YR_API void* yr_hash_table_lookup_raw_key( + YR_HASH_TABLE* table, + const void* key, + size_t key_length, + const char* ns) +{ + return _yr_hash_table_lookup(table, key, key_length, ns, FALSE); +} + + +YR_API void* yr_hash_table_remove_raw_key( + YR_HASH_TABLE* table, + const void* key, + size_t key_length, + const char* ns) +{ + return _yr_hash_table_lookup(table, key, key_length, ns, TRUE); +} + + +YR_API int yr_hash_table_add_raw_key( + YR_HASH_TABLE* table, + const void* key, + size_t key_length, + const char* ns, + void* value) +{ + YR_HASH_TABLE_ENTRY* entry; + uint32_t bucket_index; + + entry = (YR_HASH_TABLE_ENTRY*) yr_malloc(sizeof(YR_HASH_TABLE_ENTRY)); + + if (entry == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + entry->key = yr_malloc(key_length); + + if (entry->key == NULL) + { + yr_free(entry); + return ERROR_INSUFFICIENT_MEMORY; + } + + if (ns != NULL) + { + entry->ns = yr_strdup(ns); + + if (entry->ns == NULL) + { + yr_free(entry->key); + yr_free(entry); + + return ERROR_INSUFFICIENT_MEMORY; + } + } + else + { + entry->ns = NULL; + } + + entry->key_length = key_length; + entry->value = value; + + memcpy(entry->key, key, key_length); + + bucket_index = yr_hash(0, key, key_length); + + if (ns != NULL) + bucket_index = yr_hash(bucket_index, (uint8_t*) ns, strlen(ns)); + + bucket_index = bucket_index % table->size; + + entry->next = table->buckets[bucket_index]; + table->buckets[bucket_index] = entry; + + return ERROR_SUCCESS; +} + + +YR_API void* yr_hash_table_lookup( + YR_HASH_TABLE* table, + const char* key, + const char* ns) +{ + return yr_hash_table_lookup_raw_key( + table, + (void*) key, + strlen(key), + ns); +} + + +YR_API void* yr_hash_table_remove( + YR_HASH_TABLE* table, + const char* key, + const char* ns) +{ + return yr_hash_table_remove_raw_key( + table, + (void*) key, + strlen(key), + ns); +} + + +YR_API int yr_hash_table_add( + YR_HASH_TABLE* table, + const char* key, + const char* ns, + void* value) +{ + return yr_hash_table_add_raw_key( + table, + (void*) key, + strlen(key), + ns, + value); +} diff --git a/yara-master/libyara/hex_grammar.c b/yara-master/libyara/hex_grammar.c new file mode 100644 index 0000000..1f5a5b8 --- /dev/null +++ b/yara-master/libyara/hex_grammar.c @@ -0,0 +1,1904 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse hex_yyparse +#define yylex hex_yylex +#define yyerror hex_yyerror +#define yydebug hex_yydebug +#define yynerrs hex_yynerrs + + +/* Copy the first part of user declarations. */ +#line 30 "hex_grammar.y" /* yacc.c:339 */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define STR_EXPAND(tok) #tok +#define STR(tok) STR_EXPAND(tok) + +#define YYERROR_VERBOSE + +#define YYMALLOC yr_malloc +#define YYFREE yr_free + +#define mark_as_not_fast_regexp() \ + ((RE_AST*) yyget_extra(yyscanner))->flags &= ~RE_FLAGS_FAST_REGEXP + +#define fail_if_too_many_ast_levels(cleanup_code) \ + if (((RE_AST*) yyget_extra(yyscanner))->levels++ > RE_MAX_AST_LEVELS) \ + { \ + { cleanup_code } \ + yyerror(yyscanner, lex_env, "string too long"); \ + YYABORT; \ + } + +#define fail_if(x, error) \ + if (x) \ + { \ + lex_env->last_error_code = error; \ + YYABORT; \ + } \ + +#define destroy_node_if(x, node) \ + if (x) \ + { \ + yr_re_node_destroy(node); \ + } \ + + +#line 119 "hex_grammar.c" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "y.tab.h". */ +#ifndef YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED +# define YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int hex_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + _BYTE_ = 258, + _MASKED_BYTE_ = 259, + _NUMBER_ = 260 + }; +#endif +/* Tokens. */ +#define _BYTE_ 258 +#define _MASKED_BYTE_ 259 +#define _NUMBER_ 260 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 86 "hex_grammar.y" /* yacc.c:355 */ + + int64_t integer; + RE_NODE *re_node; + +#line 174 "hex_grammar.c" /* yacc.c:355 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int hex_yyparse (void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env); + +#endif /* !YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + +#line 190 "hex_grammar.c" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 9 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 30 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 14 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 10 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 20 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 32 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 260 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 8, 9, 2, 2, 2, 12, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 10, 2, 11, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 6, 13, 7, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 113, 113, 122, 126, 140, 208, 212, 230, 234, + 243, 248, 247, 260, 283, 315, 337, 357, 361, 380, + 388 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "_BYTE_", "_MASKED_BYTE_", "_NUMBER_", + "'{'", "'}'", "'('", "')'", "'['", "']'", "'-'", "'|'", "$accept", + "hex_string", "tokens", "token_sequence", "token_or_range", "token", + "$@1", "range", "alternatives", "byte", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 123, 125, 40, 41, + 91, 93, 45, 124 +}; +# endif + +#define YYPACT_NINF -11 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-11))) + +#define YYTABLE_NINF -6 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int8 yypact[] = +{ + 20, 14, 27, -11, -11, -11, 21, -2, -11, -11, + 14, -11, -1, -2, -11, -4, -11, -11, 10, 13, + 9, -11, 3, -11, 14, -11, 2, -11, -11, 18, + -11, -11 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 0, 19, 20, 11, 0, 3, 10, 1, + 0, 2, 0, 0, 6, 8, 9, 17, 0, 0, + 0, 7, 8, 12, 0, 13, 0, 16, 18, 0, + 15, 14 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -11, -11, -10, -11, 17, 8, -11, -11, -11, -11 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 2, 6, 13, 14, 7, 10, 16, 18, 8 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int8 yytable[] = +{ + 17, 3, 4, -4, 19, -4, 5, 29, 12, -4, + -5, 20, -5, 30, 28, 15, -5, 3, 4, 23, + 27, 22, 5, 24, 25, 26, 1, 9, 11, 31, + 21 +}; + +static const yytype_uint8 yycheck[] = +{ + 10, 3, 4, 7, 5, 9, 8, 5, 10, 13, + 7, 12, 9, 11, 24, 7, 13, 3, 4, 9, + 11, 13, 8, 13, 11, 12, 6, 0, 7, 11, + 13 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 6, 15, 3, 4, 8, 16, 19, 23, 0, + 20, 7, 10, 17, 18, 19, 21, 16, 22, 5, + 12, 18, 19, 9, 13, 11, 12, 11, 16, 5, + 11, 11 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 14, 15, 16, 16, 16, 17, 17, 18, 18, + 19, 20, 19, 21, 21, 21, 21, 22, 22, 23, + 23 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 3, 1, 2, 3, 1, 2, 1, 1, + 1, 0, 4, 3, 5, 4, 3, 1, 3, 1, + 1 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (yyscanner, lex_env, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, yyscanner, lex_env); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (yyscanner); + YYUSE (lex_env); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yyscanner, lex_env); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , yyscanner, lex_env); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, yyscanner, lex_env); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) +{ + YYUSE (yyvaluep); + YYUSE (yyscanner); + YYUSE (lex_env); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + switch (yytype) + { + case 16: /* tokens */ +#line 102 "hex_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1031 "hex_grammar.c" /* yacc.c:1257 */ + break; + + case 17: /* token_sequence */ +#line 103 "hex_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1037 "hex_grammar.c" /* yacc.c:1257 */ + break; + + case 18: /* token_or_range */ +#line 104 "hex_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1043 "hex_grammar.c" /* yacc.c:1257 */ + break; + + case 19: /* token */ +#line 105 "hex_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1049 "hex_grammar.c" /* yacc.c:1257 */ + break; + + case 21: /* range */ +#line 108 "hex_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1055 "hex_grammar.c" /* yacc.c:1257 */ + break; + + case 22: /* alternatives */ +#line 107 "hex_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1061 "hex_grammar.c" /* yacc.c:1257 */ + break; + + case 23: /* byte */ +#line 106 "hex_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1067 "hex_grammar.c" /* yacc.c:1257 */ + break; + + + default: + break; + } + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, yyscanner, lex_env); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 114 "hex_grammar.y" /* yacc.c:1661 */ + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->root_node = (yyvsp[-1].re_node); + } +#line 1338 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 3: +#line 123 "hex_grammar.y" /* yacc.c:1661 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + } +#line 1346 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 4: +#line 127 "hex_grammar.y" /* yacc.c:1661 */ + { + fail_if_too_many_ast_levels({ + yr_re_node_destroy((yyvsp[-1].re_node)); + yr_re_node_destroy((yyvsp[0].re_node)); + }); + + (yyval.re_node) = yr_re_node_create(RE_NODE_CONCAT, (yyvsp[-1].re_node), (yyvsp[0].re_node)); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1364 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 5: +#line 141 "hex_grammar.y" /* yacc.c:1661 */ + { + RE_NODE* new_concat; + RE_NODE* leftmost_concat = NULL; + RE_NODE* leftmost_node = (yyvsp[-1].re_node); + + fail_if_too_many_ast_levels({ + yr_re_node_destroy((yyvsp[-2].re_node)); + yr_re_node_destroy((yyvsp[-1].re_node)); + yr_re_node_destroy((yyvsp[0].re_node)); + }); + + (yyval.re_node) = NULL; + + /* + Some portions of the code (i.e: yr_re_split_at_chaining_point) + expect a left-unbalanced tree where the right child of a concat node + can't be another concat node. A concat node must be always the left + child of its parent if the parent is also a concat. For this reason + the can't simply create two new concat nodes arranged like this: + + concat + / \ + / \ + token's \ + subtree concat + / \ + / \ + / \ + token_sequence's token's + subtree subtree + + Instead we must insert the subtree for the first token as the + leftmost node of the token_sequence subtree. + */ + + while (leftmost_node->type == RE_NODE_CONCAT) + { + leftmost_concat = leftmost_node; + leftmost_node = leftmost_node->left; + } + + new_concat = yr_re_node_create( + RE_NODE_CONCAT, (yyvsp[-2].re_node), leftmost_node); + + if (new_concat != NULL) + { + if (leftmost_concat != NULL) + { + leftmost_concat->left = new_concat; + (yyval.re_node) = yr_re_node_create(RE_NODE_CONCAT, (yyvsp[-1].re_node), (yyvsp[0].re_node)); + } + else + { + (yyval.re_node) = yr_re_node_create(RE_NODE_CONCAT, new_concat, (yyvsp[0].re_node)); + } + } + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1432 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 6: +#line 209 "hex_grammar.y" /* yacc.c:1661 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + } +#line 1440 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 7: +#line 213 "hex_grammar.y" /* yacc.c:1661 */ + { + fail_if_too_many_ast_levels({ + yr_re_node_destroy((yyvsp[-1].re_node)); + yr_re_node_destroy((yyvsp[0].re_node)); + }); + + (yyval.re_node) = yr_re_node_create(RE_NODE_CONCAT, (yyvsp[-1].re_node), (yyvsp[0].re_node)); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1458 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 8: +#line 231 "hex_grammar.y" /* yacc.c:1661 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + } +#line 1466 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 9: +#line 235 "hex_grammar.y" /* yacc.c:1661 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + (yyval.re_node)->greedy = FALSE; + } +#line 1475 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 10: +#line 244 "hex_grammar.y" /* yacc.c:1661 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + } +#line 1483 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 11: +#line 248 "hex_grammar.y" /* yacc.c:1661 */ + { + lex_env->inside_or++; + } +#line 1491 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 12: +#line 252 "hex_grammar.y" /* yacc.c:1661 */ + { + (yyval.re_node) = (yyvsp[-1].re_node); + lex_env->inside_or--; + } +#line 1500 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 13: +#line 261 "hex_grammar.y" /* yacc.c:1661 */ + { + if ((yyvsp[-1].integer) <= 0) + { + yyerror(yyscanner, lex_env, "invalid jump length"); + YYABORT; + } + + if (lex_env->inside_or && (yyvsp[-1].integer) > STRING_CHAINING_THRESHOLD) + { + yyerror(yyscanner, lex_env, "jumps over " + STR(STRING_CHAINING_THRESHOLD) + " now allowed inside alternation (|)"); + YYABORT; + } + + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->start = (int) (yyvsp[-1].integer); + (yyval.re_node)->end = (int) (yyvsp[-1].integer); + } +#line 1527 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 14: +#line 284 "hex_grammar.y" /* yacc.c:1661 */ + { + if (lex_env->inside_or && + ((yyvsp[-3].integer) > STRING_CHAINING_THRESHOLD || + (yyvsp[-1].integer) > STRING_CHAINING_THRESHOLD) ) + { + yyerror(yyscanner, lex_env, "jumps over " + STR(STRING_CHAINING_THRESHOLD) + " now allowed inside alternation (|)"); + + YYABORT; + } + + if ((yyvsp[-3].integer) < 0 || (yyvsp[-1].integer) < 0) + { + yyerror(yyscanner, lex_env, "invalid negative jump length"); + YYABORT; + } + + if ((yyvsp[-3].integer) > (yyvsp[-1].integer)) + { + yyerror(yyscanner, lex_env, "invalid jump range"); + YYABORT; + } + + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->start = (int) (yyvsp[-3].integer); + (yyval.re_node)->end = (int) (yyvsp[-1].integer); + } +#line 1563 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 15: +#line 316 "hex_grammar.y" /* yacc.c:1661 */ + { + if (lex_env->inside_or) + { + yyerror(yyscanner, lex_env, + "unbounded jumps not allowed inside alternation (|)"); + YYABORT; + } + + if ((yyvsp[-2].integer) < 0) + { + yyerror(yyscanner, lex_env, "invalid negative jump length"); + YYABORT; + } + + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->start = (int) (yyvsp[-2].integer); + (yyval.re_node)->end = INT_MAX; + } +#line 1589 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 16: +#line 338 "hex_grammar.y" /* yacc.c:1661 */ + { + if (lex_env->inside_or) + { + yyerror(yyscanner, lex_env, + "unbounded jumps not allowed inside alternation (|)"); + YYABORT; + } + + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->start = 0; + (yyval.re_node)->end = INT_MAX; + } +#line 1609 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 17: +#line 358 "hex_grammar.y" /* yacc.c:1661 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + } +#line 1617 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 18: +#line 362 "hex_grammar.y" /* yacc.c:1661 */ + { + mark_as_not_fast_regexp(); + + fail_if_too_many_ast_levels({ + yr_re_node_destroy((yyvsp[-2].re_node)); + yr_re_node_destroy((yyvsp[0].re_node)); + }); + + (yyval.re_node) = yr_re_node_create(RE_NODE_ALT, (yyvsp[-2].re_node), (yyvsp[0].re_node)); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1637 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 19: +#line 381 "hex_grammar.y" /* yacc.c:1661 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_LITERAL, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->value = (int) (yyvsp[0].integer); + } +#line 1649 "hex_grammar.c" /* yacc.c:1661 */ + break; + + case 20: +#line 389 "hex_grammar.y" /* yacc.c:1661 */ + { + uint8_t mask = (uint8_t) ((yyvsp[0].integer) >> 8); + + if (mask == 0x00) + { + (yyval.re_node) = yr_re_node_create(RE_NODE_ANY, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } + else + { + (yyval.re_node) = yr_re_node_create(RE_NODE_MASKED_LITERAL, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->value = (yyvsp[0].integer) & 0xFF; + (yyval.re_node)->mask = mask; + } + } +#line 1673 "hex_grammar.c" /* yacc.c:1661 */ + break; + + +#line 1677 "hex_grammar.c" /* yacc.c:1661 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (yyscanner, lex_env, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yyscanner, lex_env, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, yyscanner, lex_env); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yyscanner, lex_env); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (yyscanner, lex_env, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, yyscanner, lex_env); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yyscanner, lex_env); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 410 "hex_grammar.y" /* yacc.c:1906 */ diff --git a/yara-master/libyara/hex_grammar.h b/yara-master/libyara/hex_grammar.h new file mode 100644 index 0000000..a7254a1 --- /dev/null +++ b/yara-master/libyara/hex_grammar.h @@ -0,0 +1,80 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED +# define YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int hex_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + _BYTE_ = 258, + _MASKED_BYTE_ = 259, + _NUMBER_ = 260 + }; +#endif +/* Tokens. */ +#define _BYTE_ 258 +#define _MASKED_BYTE_ 259 +#define _NUMBER_ 260 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 86 "hex_grammar.y" /* yacc.c:1915 */ + + int64_t integer; + RE_NODE *re_node; + +#line 69 "hex_grammar.h" /* yacc.c:1915 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int hex_yyparse (void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env); + +#endif /* !YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED */ diff --git a/yara-master/libyara/hex_grammar.y b/yara-master/libyara/hex_grammar.y new file mode 100644 index 0000000..6fa0cf0 --- /dev/null +++ b/yara-master/libyara/hex_grammar.y @@ -0,0 +1,410 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +%{ + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define STR_EXPAND(tok) #tok +#define STR(tok) STR_EXPAND(tok) + +#define YYERROR_VERBOSE + +#define YYMALLOC yr_malloc +#define YYFREE yr_free + +#define mark_as_not_fast_regexp() \ + ((RE_AST*) yyget_extra(yyscanner))->flags &= ~RE_FLAGS_FAST_REGEXP + +#define fail_if_too_many_ast_levels(cleanup_code) \ + if (((RE_AST*) yyget_extra(yyscanner))->levels++ > RE_MAX_AST_LEVELS) \ + { \ + { cleanup_code } \ + yyerror(yyscanner, lex_env, "string too long"); \ + YYABORT; \ + } + +#define fail_if(x, error) \ + if (x) \ + { \ + lex_env->last_error_code = error; \ + YYABORT; \ + } \ + +#define destroy_node_if(x, node) \ + if (x) \ + { \ + yr_re_node_destroy(node); \ + } \ + +%} + +%name-prefix "hex_yy" +%pure-parser + +%parse-param {void *yyscanner} +%parse-param {HEX_LEX_ENVIRONMENT *lex_env} + +%lex-param {yyscan_t yyscanner} +%lex-param {HEX_LEX_ENVIRONMENT *lex_env} + +%union { + int64_t integer; + RE_NODE *re_node; +} + +%token _BYTE_ +%token _MASKED_BYTE_ +%token _NUMBER_ + +%type tokens +%type token_sequence +%type token_or_range +%type token byte +%type alternatives +%type range + +%destructor { yr_re_node_destroy($$); $$ = NULL; } tokens +%destructor { yr_re_node_destroy($$); $$ = NULL; } token_sequence +%destructor { yr_re_node_destroy($$); $$ = NULL; } token_or_range +%destructor { yr_re_node_destroy($$); $$ = NULL; } token +%destructor { yr_re_node_destroy($$); $$ = NULL; } byte +%destructor { yr_re_node_destroy($$); $$ = NULL; } alternatives +%destructor { yr_re_node_destroy($$); $$ = NULL; } range + +%% + +hex_string + : '{' tokens '}' + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->root_node = $2; + } + ; + + +tokens + : token + { + $$ = $1; + } + | token token + { + fail_if_too_many_ast_levels({ + yr_re_node_destroy($1); + yr_re_node_destroy($2); + }); + + $$ = yr_re_node_create(RE_NODE_CONCAT, $1, $2); + + destroy_node_if($$ == NULL, $1); + destroy_node_if($$ == NULL, $2); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | token token_sequence token + { + RE_NODE* new_concat; + RE_NODE* leftmost_concat = NULL; + RE_NODE* leftmost_node = $2; + + fail_if_too_many_ast_levels({ + yr_re_node_destroy($1); + yr_re_node_destroy($2); + yr_re_node_destroy($3); + }); + + $$ = NULL; + + /* + Some portions of the code (i.e: yr_re_split_at_chaining_point) + expect a left-unbalanced tree where the right child of a concat node + can't be another concat node. A concat node must be always the left + child of its parent if the parent is also a concat. For this reason + the can't simply create two new concat nodes arranged like this: + + concat + / \ + / \ + token's \ + subtree concat + / \ + / \ + / \ + token_sequence's token's + subtree subtree + + Instead we must insert the subtree for the first token as the + leftmost node of the token_sequence subtree. + */ + + while (leftmost_node->type == RE_NODE_CONCAT) + { + leftmost_concat = leftmost_node; + leftmost_node = leftmost_node->left; + } + + new_concat = yr_re_node_create( + RE_NODE_CONCAT, $1, leftmost_node); + + if (new_concat != NULL) + { + if (leftmost_concat != NULL) + { + leftmost_concat->left = new_concat; + $$ = yr_re_node_create(RE_NODE_CONCAT, $2, $3); + } + else + { + $$ = yr_re_node_create(RE_NODE_CONCAT, new_concat, $3); + } + } + + destroy_node_if($$ == NULL, $1); + destroy_node_if($$ == NULL, $2); + destroy_node_if($$ == NULL, $3); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + ; + + +token_sequence + : token_or_range + { + $$ = $1; + } + | token_sequence token_or_range + { + fail_if_too_many_ast_levels({ + yr_re_node_destroy($1); + yr_re_node_destroy($2); + }); + + $$ = yr_re_node_create(RE_NODE_CONCAT, $1, $2); + + destroy_node_if($$ == NULL, $1); + destroy_node_if($$ == NULL, $2); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + ; + + +token_or_range + : token + { + $$ = $1; + } + | range + { + $$ = $1; + $$->greedy = FALSE; + } + ; + + +token + : byte + { + $$ = $1; + } + | '(' + { + lex_env->inside_or++; + } + alternatives ')' + { + $$ = $3; + lex_env->inside_or--; + } + ; + + +range + : '[' _NUMBER_ ']' + { + if ($2 <= 0) + { + yyerror(yyscanner, lex_env, "invalid jump length"); + YYABORT; + } + + if (lex_env->inside_or && $2 > STRING_CHAINING_THRESHOLD) + { + yyerror(yyscanner, lex_env, "jumps over " + STR(STRING_CHAINING_THRESHOLD) + " now allowed inside alternation (|)"); + YYABORT; + } + + $$ = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->start = (int) $2; + $$->end = (int) $2; + } + | '[' _NUMBER_ '-' _NUMBER_ ']' + { + if (lex_env->inside_or && + ($2 > STRING_CHAINING_THRESHOLD || + $4 > STRING_CHAINING_THRESHOLD) ) + { + yyerror(yyscanner, lex_env, "jumps over " + STR(STRING_CHAINING_THRESHOLD) + " now allowed inside alternation (|)"); + + YYABORT; + } + + if ($2 < 0 || $4 < 0) + { + yyerror(yyscanner, lex_env, "invalid negative jump length"); + YYABORT; + } + + if ($2 > $4) + { + yyerror(yyscanner, lex_env, "invalid jump range"); + YYABORT; + } + + $$ = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->start = (int) $2; + $$->end = (int) $4; + } + | '[' _NUMBER_ '-' ']' + { + if (lex_env->inside_or) + { + yyerror(yyscanner, lex_env, + "unbounded jumps not allowed inside alternation (|)"); + YYABORT; + } + + if ($2 < 0) + { + yyerror(yyscanner, lex_env, "invalid negative jump length"); + YYABORT; + } + + $$ = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->start = (int) $2; + $$->end = INT_MAX; + } + | '[' '-' ']' + { + if (lex_env->inside_or) + { + yyerror(yyscanner, lex_env, + "unbounded jumps not allowed inside alternation (|)"); + YYABORT; + } + + $$ = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->start = 0; + $$->end = INT_MAX; + } + ; + + +alternatives + : tokens + { + $$ = $1; + } + | alternatives '|' tokens + { + mark_as_not_fast_regexp(); + + fail_if_too_many_ast_levels({ + yr_re_node_destroy($1); + yr_re_node_destroy($3); + }); + + $$ = yr_re_node_create(RE_NODE_ALT, $1, $3); + + destroy_node_if($$ == NULL, $1); + destroy_node_if($$ == NULL, $3); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + ; + +byte + : _BYTE_ + { + $$ = yr_re_node_create(RE_NODE_LITERAL, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->value = (int) $1; + } + | _MASKED_BYTE_ + { + uint8_t mask = (uint8_t) ($1 >> 8); + + if (mask == 0x00) + { + $$ = yr_re_node_create(RE_NODE_ANY, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + else + { + $$ = yr_re_node_create(RE_NODE_MASKED_LITERAL, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->value = $1 & 0xFF; + $$->mask = mask; + } + } + ; + +%% \ No newline at end of file diff --git a/yara-master/libyara/hex_lexer.c b/yara-master/libyara/hex_lexer.c new file mode 100644 index 0000000..3ae0610 --- /dev/null +++ b/yara-master/libyara/hex_lexer.c @@ -0,0 +1,2465 @@ +#line 1 "hex_lexer.c" + +#line 3 "hex_lexer.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define hex_yy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer hex_yy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define hex_yy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer hex_yy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define hex_yy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer hex_yy_scan_buffer +#endif + +#ifdef yy_scan_string +#define hex_yy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string hex_yy_scan_string +#endif + +#ifdef yy_scan_bytes +#define hex_yy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes hex_yy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define hex_yy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer hex_yy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define hex_yy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer hex_yy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define hex_yy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state hex_yy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define hex_yy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer hex_yy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define hex_yypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state hex_yypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define hex_yypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state hex_yypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define hex_yyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack hex_yyensure_buffer_stack +#endif + +#ifdef yylex +#define hex_yylex_ALREADY_DEFINED +#else +#define yylex hex_yylex +#endif + +#ifdef yyrestart +#define hex_yyrestart_ALREADY_DEFINED +#else +#define yyrestart hex_yyrestart +#endif + +#ifdef yylex_init +#define hex_yylex_init_ALREADY_DEFINED +#else +#define yylex_init hex_yylex_init +#endif + +#ifdef yylex_init_extra +#define hex_yylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra hex_yylex_init_extra +#endif + +#ifdef yylex_destroy +#define hex_yylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy hex_yylex_destroy +#endif + +#ifdef yyget_debug +#define hex_yyget_debug_ALREADY_DEFINED +#else +#define yyget_debug hex_yyget_debug +#endif + +#ifdef yyset_debug +#define hex_yyset_debug_ALREADY_DEFINED +#else +#define yyset_debug hex_yyset_debug +#endif + +#ifdef yyget_extra +#define hex_yyget_extra_ALREADY_DEFINED +#else +#define yyget_extra hex_yyget_extra +#endif + +#ifdef yyset_extra +#define hex_yyset_extra_ALREADY_DEFINED +#else +#define yyset_extra hex_yyset_extra +#endif + +#ifdef yyget_in +#define hex_yyget_in_ALREADY_DEFINED +#else +#define yyget_in hex_yyget_in +#endif + +#ifdef yyset_in +#define hex_yyset_in_ALREADY_DEFINED +#else +#define yyset_in hex_yyset_in +#endif + +#ifdef yyget_out +#define hex_yyget_out_ALREADY_DEFINED +#else +#define yyget_out hex_yyget_out +#endif + +#ifdef yyset_out +#define hex_yyset_out_ALREADY_DEFINED +#else +#define yyset_out hex_yyset_out +#endif + +#ifdef yyget_leng +#define hex_yyget_leng_ALREADY_DEFINED +#else +#define yyget_leng hex_yyget_leng +#endif + +#ifdef yyget_text +#define hex_yyget_text_ALREADY_DEFINED +#else +#define yyget_text hex_yyget_text +#endif + +#ifdef yyget_lineno +#define hex_yyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno hex_yyget_lineno +#endif + +#ifdef yyset_lineno +#define hex_yyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno hex_yyset_lineno +#endif + +#ifdef yyget_column +#define hex_yyget_column_ALREADY_DEFINED +#else +#define yyget_column hex_yyget_column +#endif + +#ifdef yyset_column +#define hex_yyset_column_ALREADY_DEFINED +#else +#define yyset_column hex_yyset_column +#endif + +#ifdef yywrap +#define hex_yywrap_ALREADY_DEFINED +#else +#define yywrap hex_yywrap +#endif + +#ifdef yyget_lval +#define hex_yyget_lval_ALREADY_DEFINED +#else +#define yyget_lval hex_yyget_lval +#endif + +#ifdef yyset_lval +#define hex_yyset_lval_ALREADY_DEFINED +#else +#define yyset_lval hex_yyset_lval +#endif + +#ifdef yyalloc +#define hex_yyalloc_ALREADY_DEFINED +#else +#define yyalloc hex_yyalloc +#endif + +#ifdef yyrealloc +#define hex_yyrealloc_ALREADY_DEFINED +#else +#define yyrealloc hex_yyrealloc +#endif + +#ifdef yyfree +#define hex_yyfree_ALREADY_DEFINED +#else +#define yyfree hex_yyfree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define hex_yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 16 +#define YY_END_OF_BUFFER 17 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[35] = + { 0, + 0, 0, 0, 0, 0, 0, 17, 15, 13, 13, + 14, 15, 15, 15, 5, 16, 12, 11, 11, 8, + 9, 10, 0, 7, 1, 2, 3, 4, 9, 0, + 0, 7, 6, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 4, + 4, 5, 1, 1, 6, 1, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, + 1, 1, 9, 1, 10, 10, 10, 10, 10, 10, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 11, 1, 12, 1, 1, 1, 10, 10, 10, 10, + + 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4, 4, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[13] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 3, 3, 3, + 1, 1 + } ; + +static const flex_int16_t yy_base[40] = + { 0, + 0, 0, 0, 0, 12, 0, 46, 47, 47, 47, + 47, 20, 36, 35, 47, 47, 47, 47, 47, 47, + 35, 47, 37, 0, 47, 47, 47, 47, 33, 35, + 23, 0, 33, 47, 30, 26, 23, 33, 36 + } ; + +static const flex_int16_t yy_def[40] = + { 0, + 34, 1, 35, 35, 34, 5, 34, 34, 34, 34, + 34, 34, 36, 37, 34, 34, 34, 34, 34, 34, + 34, 34, 38, 39, 34, 34, 34, 34, 34, 38, + 38, 39, 38, 0, 34, 34, 34, 34, 34 + } ; + +static const flex_int16_t yy_nxt[60] = + { 0, + 8, 9, 10, 11, 8, 8, 12, 13, 14, 13, + 15, 8, 17, 18, 19, 17, 17, 20, 17, 21, + 17, 17, 17, 22, 23, 27, 24, 31, 25, 33, + 16, 16, 16, 30, 30, 30, 32, 31, 32, 31, + 29, 31, 29, 28, 26, 34, 7, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34 + } ; + +static const flex_int16_t yy_chk[60] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 12, 37, 12, 31, 36, 31, + 35, 35, 35, 38, 38, 38, 39, 33, 39, 30, + 29, 23, 21, 14, 13, 7, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34 + } ; + +/* Table of booleans, true if rule could match eol. */ +static const flex_int32_t yy_rule_can_match_eol[17] = + { 0, +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "hex_lexer.l" +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ +/* Lexical analyzer for hex strings */ +#line 33 "hex_lexer.l" + +/* Disable warnings for unused functions in this file. + +As we redefine YY_FATAL_ERROR macro to use our own function hex_yyfatal, the +yy_fatal_error function generated by Flex is not actually used, causing a +compiler warning. Flex doesn't offer any options to remove the yy_fatal_error +function. When they include something like %option noyy_fatal_error as they do +with noyywrap then we can remove this pragma. +*/ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hex_grammar.h" + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +#define ERROR_IF(x, error) \ + if (x) \ + { \ + RE_AST* re_ast = yyget_extra(yyscanner); \ + re_ast->error_code = error; \ + YYABORT; \ + } \ + +#line 756 "hex_lexer.c" +#define YY_NO_UNISTD_H 1 +#define YY_NO_INPUT 1 + +#line 760 "hex_lexer.c" + +#define INITIAL 0 +#define comment 1 +#define range 2 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yylval = yylval_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +#line 95 "hex_lexer.l" + + + +#line 1038 "hex_lexer.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 35 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 34 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 98 "hex_lexer.l" +{ + + yylval->integer = xtoi(yytext); + return _BYTE_; +} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 104 "hex_lexer.l" +{ + + yytext[1] = '0'; // replace ? by 0 + yylval->integer = xtoi(yytext) | 0xF000 ; + return _MASKED_BYTE_; +} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 111 "hex_lexer.l" +{ + + yytext[0] = '0'; // replace ? by 0 + yylval->integer = xtoi(yytext) | 0x0F00 ; + return _MASKED_BYTE_; +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 118 "hex_lexer.l" +{ + + yylval->integer = 0x0000; + return _MASKED_BYTE_; +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 124 "hex_lexer.l" +{ + + BEGIN(range); + return yytext[0]; +} + YY_BREAK +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +#line 130 "hex_lexer.l" +// skip comments + YY_BREAK +case 7: +YY_RULE_SETUP +#line 132 "hex_lexer.l" +// skip single-line comments + YY_BREAK +case 8: +YY_RULE_SETUP +#line 134 "hex_lexer.l" +{ + return yytext[0]; +} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 138 "hex_lexer.l" +{ + + yylval->integer = atoi(yytext); + return _NUMBER_; +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 144 "hex_lexer.l" +{ + + BEGIN(INITIAL); + return yytext[0]; +} + YY_BREAK +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +#line 150 "hex_lexer.l" +// skip whitespaces + YY_BREAK +case 12: +YY_RULE_SETUP +#line 152 "hex_lexer.l" +{ + + yyerror(yyscanner, lex_env, "invalid character in hex string jump"); + yyterminate(); +} + YY_BREAK +case 13: +/* rule 13 can match eol */ +YY_RULE_SETUP +#line 158 "hex_lexer.l" +// skip whitespaces + YY_BREAK +case 14: +YY_RULE_SETUP +#line 160 "hex_lexer.l" +{ // pass valid characters to the parser + + return yytext[0]; +} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 165 "hex_lexer.l" +{ // reject all other characters + + yyerror(yyscanner, lex_env, "invalid character in hex string"); + yyterminate(); +} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 171 "hex_lexer.l" +ECHO; + YY_BREAK +#line 1229 "hex_lexer.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(comment): +case YY_STATE_EOF(range): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 35 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 35 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 34); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 171 "hex_lexer.l" + + +void yyfatal( + yyscan_t yyscanner, + const char *error_message) +{ + jmp_buf* recovery_state = (jmp_buf*) yr_thread_storage_get_value( + &yr_recovery_state_key); + + longjmp(*recovery_state, 1); +} + +void yyerror( + yyscan_t yyscanner, + HEX_LEX_ENVIRONMENT* lex_env, + const char *error_message) +{ + // if lex_env->last_error_code was set to some error code before + // don't overwrite it, we are interested in the first error, not in + // subsequent errors like "syntax error, unexpected $end" caused by + // early parser termination. + + if (lex_env->last_error_code == ERROR_SUCCESS) + { + lex_env->last_error_code = ERROR_INVALID_HEX_STRING; + + strlcpy( + lex_env->last_error_message, + error_message, + sizeof(lex_env->last_error_message)); + } +} + + +int yr_parse_hex_string( + const char* hex_string, + RE_AST** re_ast, + RE_ERROR* error) +{ + yyscan_t yyscanner; + jmp_buf recovery_state; + HEX_LEX_ENVIRONMENT lex_env; + + lex_env.last_error_code = ERROR_SUCCESS; + lex_env.inside_or = 0; + + yr_thread_storage_set_value(&yr_recovery_state_key, &recovery_state); + + if (setjmp(recovery_state) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + FAIL_ON_ERROR(yr_re_ast_create(re_ast)); + + // The RE_FLAGS_FAST_REGEXP flag indicates a regular expression can be + // matched by faster algorithm. These regular expressions come from hex + // strings that do not contain alternatives, like in: + // + // { ( 01 02 | 03 04) 05 06 }. + // + // This flag is unset later during parsing if alternatives are used. + + (*re_ast)->flags |= RE_FLAGS_FAST_REGEXP; + + // Set RE_FLAGS_DOT_ALL because in hex strings the "dot" (?? in this case) + // must match all characters including new-line. + + (*re_ast)->flags |= RE_FLAGS_DOT_ALL; + + yylex_init(&yyscanner); + yyset_extra(*re_ast, yyscanner); + yy_scan_string(hex_string, yyscanner); + yyparse(yyscanner, &lex_env); + yylex_destroy(yyscanner); + + if (lex_env.last_error_code != ERROR_SUCCESS) + { + strlcpy(error->message, lex_env.last_error_message, sizeof(error->message)); + return lex_env.last_error_code; + } + + return ERROR_SUCCESS; +} + diff --git a/yara-master/libyara/hex_lexer.l b/yara-master/libyara/hex_lexer.l new file mode 100644 index 0000000..2a4c360 --- /dev/null +++ b/yara-master/libyara/hex_lexer.l @@ -0,0 +1,252 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +/* Lexical analyzer for hex strings */ + +%{ + +/* Disable warnings for unused functions in this file. + +As we redefine YY_FATAL_ERROR macro to use our own function hex_yyfatal, the +yy_fatal_error function generated by Flex is not actually used, causing a +compiler warning. Flex doesn't offer any options to remove the yy_fatal_error +function. When they include something like %option noyy_fatal_error as they do +with noyywrap then we can remove this pragma. +*/ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hex_grammar.h" + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +#define ERROR_IF(x, error) \ + if (x) \ + { \ + RE_AST* re_ast = yyget_extra(yyscanner); \ + re_ast->error_code = error; \ + YYABORT; \ + } \ + +%} + +%option reentrant bison-bridge +%option noyywrap +%option nounistd +%option noinput +%option nounput +%option never-interactive +%option yylineno +%option prefix="hex_yy" + +%option outfile="lex.yy.c" + +%option verbose +%option warn + +digit [0-9] +letter [a-zA-Z] +hexdigit [a-fA-F0-9] + +%x comment +%x range + +%% + + +{hexdigit}{2} { + + yylval->integer = xtoi(yytext); + return _BYTE_; +} + +{hexdigit}\? { + + yytext[1] = '0'; // replace ? by 0 + yylval->integer = xtoi(yytext) | 0xF000 ; + return _MASKED_BYTE_; +} + +\?{hexdigit} { + + yytext[0] = '0'; // replace ? by 0 + yylval->integer = xtoi(yytext) | 0x0F00 ; + return _MASKED_BYTE_; +} + +\?\? { + + yylval->integer = 0x0000; + return _MASKED_BYTE_; +} + +\[ { + + BEGIN(range); + return yytext[0]; +} + +"/*"(.|\n)*"*/" // skip comments + +"//".* // skip single-line comments + +\- { + return yytext[0]; +} + +{digit}+ { + + yylval->integer = atoi(yytext); + return _NUMBER_; +} + +\] { + + BEGIN(INITIAL); + return yytext[0]; +} + +[ \t\r\n] // skip whitespaces + +. { + + yyerror(yyscanner, lex_env, "invalid character in hex string jump"); + yyterminate(); +} + +[ \t\r\n] // skip whitespaces + +[{}()|] { // pass valid characters to the parser + + return yytext[0]; +} + +. { // reject all other characters + + yyerror(yyscanner, lex_env, "invalid character in hex string"); + yyterminate(); +} + +%% + +void yyfatal( + yyscan_t yyscanner, + const char *error_message) +{ + jmp_buf* recovery_state = (jmp_buf*) yr_thread_storage_get_value( + &yr_recovery_state_key); + + longjmp(*recovery_state, 1); +} + +void yyerror( + yyscan_t yyscanner, + HEX_LEX_ENVIRONMENT* lex_env, + const char *error_message) +{ + // if lex_env->last_error_code was set to some error code before + // don't overwrite it, we are interested in the first error, not in + // subsequent errors like "syntax error, unexpected $end" caused by + // early parser termination. + + if (lex_env->last_error_code == ERROR_SUCCESS) + { + lex_env->last_error_code = ERROR_INVALID_HEX_STRING; + + strlcpy( + lex_env->last_error_message, + error_message, + sizeof(lex_env->last_error_message)); + } +} + + +int yr_parse_hex_string( + const char* hex_string, + RE_AST** re_ast, + RE_ERROR* error) +{ + yyscan_t yyscanner; + jmp_buf recovery_state; + HEX_LEX_ENVIRONMENT lex_env; + + lex_env.last_error_code = ERROR_SUCCESS; + lex_env.inside_or = 0; + + yr_thread_storage_set_value(&yr_recovery_state_key, &recovery_state); + + if (setjmp(recovery_state) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + FAIL_ON_ERROR(yr_re_ast_create(re_ast)); + + // The RE_FLAGS_FAST_REGEXP flag indicates a regular expression can be + // matched by faster algorithm. These regular expressions come from hex + // strings that do not contain alternatives, like in: + // + // { ( 01 02 | 03 04) 05 06 }. + // + // This flag is unset later during parsing if alternatives are used. + + (*re_ast)->flags |= RE_FLAGS_FAST_REGEXP; + + // Set RE_FLAGS_DOT_ALL because in hex strings the "dot" (?? in this case) + // must match all characters including new-line. + + (*re_ast)->flags |= RE_FLAGS_DOT_ALL; + + yylex_init(&yyscanner); + yyset_extra(*re_ast, yyscanner); + yy_scan_string(hex_string, yyscanner); + yyparse(yyscanner, &lex_env); + yylex_destroy(yyscanner); + + if (lex_env.last_error_code != ERROR_SUCCESS) + { + strlcpy(error->message, lex_env.last_error_message, sizeof(error->message)); + return lex_env.last_error_code; + } + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/include/yara.h b/yara-master/libyara/include/yara.h new file mode 100644 index 0000000..c52d25a --- /dev/null +++ b/yara-master/libyara/include/yara.h @@ -0,0 +1,45 @@ +/* +Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_YARA_H +#define YR_YARA_H + +#include "yara/utils.h" +#include "yara/filemap.h" +#include "yara/compiler.h" +#include "yara/modules.h" +#include "yara/object.h" +#include "yara/libyara.h" +#include "yara/error.h" +#include "yara/stream.h" +#include "yara/hash.h" +#include "yara/scanner.h" +#include "yara/mem.h" + +#endif diff --git a/yara-master/libyara/include/yara/ahocorasick.h b/yara-master/libyara/include/yara/ahocorasick.h new file mode 100644 index 0000000..7f3559e --- /dev/null +++ b/yara-master/libyara/include/yara/ahocorasick.h @@ -0,0 +1,76 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef _AHOCORASICK_H +#define _AHOCORASICK_H + +#include +#include +#include + + +#define YR_AC_ROOT_STATE 0 +#define YR_AC_NEXT_STATE(t) (t >> 32) +#define YR_AC_INVALID_TRANSITION(t, c) (((t) & 0xFFFF) != c) + +#define YR_AC_MAKE_TRANSITION(state, code, flags) \ + ((uint64_t)((((uint64_t) state) << 32) | ((flags) << 16) | (code))) + +#define YR_AC_USED_FLAG 0x1 + +#define YR_AC_USED_TRANSITION_SLOT(x) ((x) & (YR_AC_USED_FLAG << 16)) +#define YR_AC_UNUSED_TRANSITION_SLOT(x) (!YR_AC_USED_TRANSITION_SLOT(x)) + + +int yr_ac_automaton_create( + YR_AC_AUTOMATON** automaton); + + +int yr_ac_automaton_destroy( + YR_AC_AUTOMATON* automaton); + + +int yr_ac_add_string( + YR_AC_AUTOMATON* automaton, + YR_STRING* string, + YR_ATOM_LIST_ITEM* atom, + YR_ARENA* matches_arena); + + +int yr_ac_compile( + YR_AC_AUTOMATON* automaton, + YR_ARENA* arena, + YR_AC_TABLES* tables); + + +void yr_ac_print_automaton( + YR_AC_AUTOMATON* automaton); + + +#endif diff --git a/yara-master/libyara/include/yara/arena.h b/yara-master/libyara/include/yara/arena.h new file mode 100644 index 0000000..36f47a0 --- /dev/null +++ b/yara-master/libyara/include/yara/arena.h @@ -0,0 +1,174 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_ARENA_H +#define YR_ARENA_H + +#include + +#include +#include + +// Indicated that the arena is self-contained and stored in a single page. A +// self-contained arenas is one that doesn't contains any pointers to outside +// data. All pointers in a self-contained arena points at some address within +// the arena. +#define ARENA_FLAGS_COALESCED 1 + +// Each pages of an arena marked with this flag maintain a list of YR_RELOC +// structures for keeping track of pointers stored within the arena. When the +// arena is relocated this allows to fix those pointers that pointed to some +// address within the relocated arena. +#define ARENA_FLAGS_RELOCATABLE 2 + +#define ARENA_FILE_VERSION ((17 << 16) | MAX_THREADS) + +#define EOL ((size_t) -1) + + +typedef struct _YR_RELOC +{ + uint32_t offset; + struct _YR_RELOC* next; + +} YR_RELOC; + + +typedef struct _YR_ARENA_PAGE +{ + uint8_t* new_address; + uint8_t* address; + + size_t size; + size_t used; + + YR_RELOC* reloc_list_head; + YR_RELOC* reloc_list_tail; + + struct _YR_ARENA_PAGE* next; + struct _YR_ARENA_PAGE* prev; + +} YR_ARENA_PAGE; + + +typedef struct _YR_ARENA +{ + int flags; + + YR_ARENA_PAGE* page_list_head; + YR_ARENA_PAGE* current_page; + +} YR_ARENA; + + +int yr_arena_create( + size_t initial_size, + int flags, + YR_ARENA** arena); + + +void yr_arena_destroy( + YR_ARENA* arena); + + +void* yr_arena_base_address( + YR_ARENA* arena); + + +void* yr_arena_next_address( + YR_ARENA* arena, + void* address, + size_t offset); + + +int yr_arena_coalesce( + YR_ARENA* arena); + + +int yr_arena_reserve_memory( + YR_ARENA* arena, + size_t size); + + +int yr_arena_allocate_memory( + YR_ARENA* arena, + size_t size, + void** allocated_memory); + + +int yr_arena_allocate_struct( + YR_ARENA* arena, + size_t size, + void** allocated_memory, + ...); + + +int yr_arena_make_ptr_relocatable( + YR_ARENA* arena, + void* base, + ...); + + +int yr_arena_write_data( + YR_ARENA* arena, + const void* data, + size_t size, + void** written_data); + + +int yr_arena_write_string( + YR_ARENA* arena, + const char* string, + char** written_string); + + +int yr_arena_append( + YR_ARENA* target_arena, + YR_ARENA* source_arena); + + +int yr_arena_load_stream( + YR_STREAM* stream, + YR_ARENA** arena); + + +int yr_arena_save_stream( + YR_ARENA* arena, + YR_STREAM* stream); + + +int yr_arena_duplicate( + YR_ARENA* arena, + YR_ARENA** duplicated); + + +void yr_arena_print( + YR_ARENA* arena); + +#endif diff --git a/yara-master/libyara/include/yara/atoms.h b/yara-master/libyara/include/yara/atoms.h new file mode 100644 index 0000000..8c0533f --- /dev/null +++ b/yara-master/libyara/include/yara/atoms.h @@ -0,0 +1,102 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_ATOMS_H +#define YR_ATOMS_H + +#include +#include + +#define ATOM_TREE_LEAF 1 +#define ATOM_TREE_AND 2 +#define ATOM_TREE_OR 3 + + +typedef struct _ATOM_TREE_NODE +{ + uint8_t type; + uint8_t atom_length; + uint8_t atom[MAX_ATOM_LENGTH]; + + uint8_t* forward_code; + uint8_t* backward_code; + + RE_NODE* recent_nodes[MAX_ATOM_LENGTH]; + + struct _ATOM_TREE_NODE* children_head; + struct _ATOM_TREE_NODE* children_tail; + struct _ATOM_TREE_NODE* next_sibling; + +} ATOM_TREE_NODE; + + +typedef struct _ATOM_TREE +{ + ATOM_TREE_NODE* current_leaf; + ATOM_TREE_NODE* root_node; + +} ATOM_TREE; + + +typedef struct _YR_ATOM_LIST_ITEM +{ + uint8_t atom_length; + uint8_t atom[MAX_ATOM_LENGTH]; + + uint16_t backtrack; + + uint8_t* forward_code; + uint8_t* backward_code; + + struct _YR_ATOM_LIST_ITEM* next; + +} YR_ATOM_LIST_ITEM; + + +int yr_atoms_extract_from_re( + RE_AST* re_ast, + int flags, + YR_ATOM_LIST_ITEM** atoms); + + +int yr_atoms_extract_from_string( + uint8_t* string, + int string_length, + int flags, + YR_ATOM_LIST_ITEM** atoms); + + +int yr_atoms_min_quality( + YR_ATOM_LIST_ITEM* atom_list); + + +void yr_atoms_list_destroy( + YR_ATOM_LIST_ITEM* list_head); + +#endif diff --git a/yara-master/libyara/include/yara/compiler.h b/yara-master/libyara/include/yara/compiler.h new file mode 100644 index 0000000..953cb0d --- /dev/null +++ b/yara-master/libyara/include/yara/compiler.h @@ -0,0 +1,260 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_COMPILER_H +#define YR_COMPILER_H + +#include +#include + +#include +#include +#include +#include +#include + + +#define YARA_ERROR_LEVEL_ERROR 0 +#define YARA_ERROR_LEVEL_WARNING 1 + + +typedef void (*YR_COMPILER_CALLBACK_FUNC)( + int error_level, + const char* file_name, + int line_number, + const char* message, + void* user_data); + + +typedef const char* (*YR_COMPILER_INCLUDE_CALLBACK_FUNC)( + const char* include_name, + const char* calling_rule_filename, + const char* calling_rule_namespace, + void* user_data); + + +typedef void (*YR_COMPILER_INCLUDE_FREE_FUNC)( + const char* callback_result_ptr, + void* user_data); + + +typedef void (*YR_COMPILER_RE_AST_CALLBACK_FUNC)( + const YR_RULE* rule, + const char* string_identifier, + const RE_AST* re_ast, + void* user_data); + + +typedef struct _YR_FIXUP +{ + void* address; + struct _YR_FIXUP* next; + +} YR_FIXUP; + + +typedef struct _YR_COMPILER +{ + int errors; + int current_line; + int last_error; + int last_error_line; + int last_result; + + jmp_buf error_recovery; + + YR_ARENA* sz_arena; + YR_ARENA* rules_arena; + YR_ARENA* strings_arena; + YR_ARENA* code_arena; + YR_ARENA* re_code_arena; + YR_ARENA* compiled_rules_arena; + YR_ARENA* externals_arena; + YR_ARENA* namespaces_arena; + YR_ARENA* metas_arena; + YR_ARENA* matches_arena; + YR_ARENA* automaton_arena; + + YR_AC_AUTOMATON* automaton; + YR_HASH_TABLE* rules_table; + YR_HASH_TABLE* objects_table; + YR_HASH_TABLE* strings_table; + YR_NAMESPACE* current_namespace; + YR_RULE* current_rule; + + YR_FIXUP* fixup_stack_head; + + int namespaces_count; + + uint8_t* loop_address[MAX_LOOP_NESTING]; + char* loop_identifier[MAX_LOOP_NESTING]; + int loop_depth; + int loop_for_of_mem_offset; + + char* file_name_stack[MAX_INCLUDE_DEPTH]; + int file_name_stack_ptr; + + char last_error_extra_info[MAX_COMPILER_ERROR_EXTRA_INFO]; + + char lex_buf[LEX_BUF_SIZE]; + char* lex_buf_ptr; + unsigned short lex_buf_len; + + char include_base_dir[MAX_PATH]; + void* user_data; + void* incl_clbk_user_data; + void* re_ast_clbk_user_data; + + YR_COMPILER_CALLBACK_FUNC callback; + YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback; + YR_COMPILER_INCLUDE_FREE_FUNC include_free; + YR_COMPILER_RE_AST_CALLBACK_FUNC re_ast_callback; + + +} YR_COMPILER; + + +#define yr_compiler_set_error_extra_info(compiler, info) \ + strlcpy( \ + compiler->last_error_extra_info, \ + info, \ + sizeof(compiler->last_error_extra_info)); \ + + +#define yr_compiler_set_error_extra_info_fmt(compiler, fmt, ...) \ + snprintf( \ + compiler->last_error_extra_info, \ + sizeof(compiler->last_error_extra_info), \ + fmt, __VA_ARGS__); + + + +int _yr_compiler_push_file_name( + YR_COMPILER* compiler, + const char* file_name); + + +void _yr_compiler_pop_file_name( + YR_COMPILER* compiler); + + +const char* _yr_compiler_default_include_callback( + const char* include_name, + const char* calling_rule_filename, + const char* calling_rule_namespace, + void* user_data); + + +YR_API int yr_compiler_create( + YR_COMPILER** compiler); + + +YR_API void yr_compiler_destroy( + YR_COMPILER* compiler); + + +YR_API void yr_compiler_set_callback( + YR_COMPILER* compiler, + YR_COMPILER_CALLBACK_FUNC callback, + void* user_data); + + +YR_API void yr_compiler_set_include_callback( + YR_COMPILER* compiler, + YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback, + YR_COMPILER_INCLUDE_FREE_FUNC include_free, + void* user_data); + + +YR_API void yr_compiler_set_re_ast_callback( + YR_COMPILER* compiler, + YR_COMPILER_RE_AST_CALLBACK_FUNC re_ast_callback, + void* user_data); + + +YR_API int yr_compiler_add_file( + YR_COMPILER* compiler, + FILE* rules_file, + const char* namespace_, + const char* file_name); + + +YR_API int yr_compiler_add_fd( + YR_COMPILER* compiler, + YR_FILE_DESCRIPTOR rules_fd, + const char* namespace_, + const char* file_name); + + +YR_API int yr_compiler_add_string( + YR_COMPILER* compiler, + const char* rules_string, + const char* namespace_); + + +YR_API char* yr_compiler_get_error_message( + YR_COMPILER* compiler, + char* buffer, + int buffer_size); + + +YR_API char* yr_compiler_get_current_file_name( + YR_COMPILER* compiler); + + +YR_API int yr_compiler_define_integer_variable( + YR_COMPILER* compiler, + const char* identifier, + int64_t value); + + +YR_API int yr_compiler_define_boolean_variable( + YR_COMPILER* compiler, + const char* identifier, + int value); + + +YR_API int yr_compiler_define_float_variable( + YR_COMPILER* compiler, + const char* identifier, + double value); + + +YR_API int yr_compiler_define_string_variable( + YR_COMPILER* compiler, + const char* identifier, + const char* value); + + +YR_API int yr_compiler_get_rules( + YR_COMPILER* compiler, + YR_RULES** rules); + + +#endif diff --git a/yara-master/libyara/include/yara/dex.h b/yara-master/libyara/include/yara/dex.h new file mode 100644 index 0000000..918051c --- /dev/null +++ b/yara-master/libyara/include/yara/dex.h @@ -0,0 +1,138 @@ +#ifndef _DEX_H +#define _DEX_H + +#include + +#include +#include + +#define DEX_FILE_MAGIC_035 "dex\n035\x00" +#define DEX_FILE_MAGIC_036 "dex\n036\x00" +#define DEX_FILE_MAGIC_037 "dex\n037\x00" +#define DEX_FILE_MAGIC_038 "dex\n038\x00" + +#pragma pack(push,1) + +typedef struct +{ + uint8_t magic[8]; + uint32_t checksum; + uint8_t signature[20]; + uint32_t file_size; + uint32_t header_size; + uint32_t endian_tag; + uint32_t link_size; + uint32_t link_offset; + uint32_t map_offset; + uint32_t string_ids_size; + uint32_t string_ids_offset; + uint32_t type_ids_size; + uint32_t type_ids_offset; + uint32_t proto_ids_size; + uint32_t proto_ids_offset; + uint32_t field_ids_size; + uint32_t field_ids_offset; + uint32_t method_ids_size; + uint32_t method_ids_offset; + uint32_t class_defs_size; + uint32_t class_defs_offset; + uint32_t data_size; + uint32_t data_offset; +} dex_header_t; + +typedef struct { + uint32_t string_data_offset; +} string_id_item_t; + + +typedef struct { + uint32_t utf16_size; +} string_data_item_t; + +typedef struct { + uint32_t descriptor_idx; +} type_id_item_t; + +typedef struct { + uint32_t shorty_idx; + uint32_t return_type_idx; + uint32_t parameters_offset; +} proto_id_item_t; + +typedef struct { + uint16_t class_idx; + uint16_t type_idx; + uint32_t name_idx; +} field_id_item_t; + +typedef struct { + uint16_t class_idx; + uint16_t proto_idx; + uint32_t name_idx; +} method_id_item_t; + +typedef struct { + uint32_t class_idx; + uint32_t access_flags; + uint32_t super_class_idx; + uint32_t interfaces_off; + uint32_t source_file_idx; + uint32_t annotations_offset; + uint32_t class_data_offset; + uint32_t static_values_offset; +} class_id_item_t; + +typedef struct { + uint32_t static_fields_size; + uint32_t instance_fields_size; + uint32_t direct_methods_size; + uint32_t virtual_methods_size; +} class_data_item_t; + +typedef struct { + uint32_t field_idx_diff; + uint32_t access_flags; +} encoded_field_t; + +typedef struct { + uint32_t method_idx_diff; + uint32_t access_flags; + uint32_t code_off; +} encoded_method_t; + +typedef struct { + uint16_t registers_size; + uint16_t ins_size; + uint16_t outs_size; + uint16_t tries_size; + uint32_t debug_info_off; + uint32_t insns_size; +} code_item_t; + +typedef struct { + uint16_t type; + uint16_t unused; + uint32_t size; + uint32_t offset; +} map_item_t; + +typedef struct _DEX +{ + const uint8_t* data; + size_t data_size; + dex_header_t *header; + YR_OBJECT* object; +} DEX; + + +#define fits_in_dex(dex, pointer, size) \ + ((size_t) size <= dex->data_size && \ + (uint8_t*) (pointer) >= dex->data && \ + (uint8_t*) (pointer) <= dex->data + dex->data_size - size) + +#define struct_fits_in_dex(dex, pointer, struct_type) \ + fits_in_dex(dex, pointer, sizeof(struct_type)) + +#pragma pack(pop) + +#endif \ No newline at end of file diff --git a/yara-master/libyara/include/yara/dotnet.h b/yara-master/libyara/include/yara/dotnet.h new file mode 100644 index 0000000..00c6cdd --- /dev/null +++ b/yara-master/libyara/include/yara/dotnet.h @@ -0,0 +1,337 @@ +#ifndef YR_DOTNET_H +#define YR_DOTNET_H + +#pragma pack(push, 1) + +// +// CLI header. +// ECMA-335 Section II.25.3.3 +// +typedef struct _CLI_HEADER { + DWORD Size; // Called "Cb" in documentation. + WORD MajorRuntimeVersion; + WORD MinorRuntimeVersion; + IMAGE_DATA_DIRECTORY MetaData; + DWORD Flags; + DWORD EntryPointToken; + IMAGE_DATA_DIRECTORY Resources; + IMAGE_DATA_DIRECTORY StrongNameSignature; + ULONGLONG CodeManagerTable; + IMAGE_DATA_DIRECTORY VTableFixups; + ULONGLONG ExportAddressTableJumps; + ULONGLONG ManagedNativeHeader; +} CLI_HEADER, *PCLI_HEADER; + +#define NET_METADATA_MAGIC 0x424a5342 + +// +// CLI MetaData +// ECMA-335 Section II.24.2.1 +// +// Note: This is only part of the struct, as the rest of it is variable length. +// +typedef struct _NET_METADATA { + DWORD Magic; + WORD MajorVersion; + WORD MinorVersion; + DWORD Reserved; + DWORD Length; + char Version[0]; +} NET_METADATA, *PNET_METADATA; + +#define DOTNET_STREAM_NAME_SIZE 32 + +// +// CLI Stream Header +// ECMA-335 Section II.24.2.2 +// +typedef struct _STREAM_HEADER { + DWORD Offset; + DWORD Size; + char Name[0]; +} STREAM_HEADER, *PSTREAM_HEADER; + + +// +// CLI #~ Stream Header +// ECMA-335 Section II.24.2.6 +// +typedef struct _TILDE_HEADER { + DWORD Reserved1; + BYTE MajorVersion; + BYTE MinorVersion; + BYTE HeapSizes; + BYTE Reserved2; + ULONGLONG Valid; + ULONGLONG Sorted; +} TILDE_HEADER, *PTILDE_HEADER; + +// These are the bit positions in Valid which will be set if the table +// exists. +#define BIT_MODULE 0x00 +#define BIT_TYPEREF 0x01 +#define BIT_TYPEDEF 0x02 +#define BIT_FIELDPTR 0x03 // Not documented in ECMA-335 +#define BIT_FIELD 0x04 +#define BIT_METHODDEFPTR 0x05 // Not documented in ECMA-335 +#define BIT_METHODDEF 0x06 +#define BIT_PARAMPTR 0x07 // Not documented in ECMA-335 +#define BIT_PARAM 0x08 +#define BIT_INTERFACEIMPL 0x09 +#define BIT_MEMBERREF 0x0A +#define BIT_CONSTANT 0x0B +#define BIT_CUSTOMATTRIBUTE 0x0C +#define BIT_FIELDMARSHAL 0x0D +#define BIT_DECLSECURITY 0x0E +#define BIT_CLASSLAYOUT 0x0F +#define BIT_FIELDLAYOUT 0x10 +#define BIT_STANDALONESIG 0x11 +#define BIT_EVENTMAP 0x12 +#define BIT_EVENTPTR 0x13 // Not documented in ECMA-335 +#define BIT_EVENT 0x14 +#define BIT_PROPERTYMAP 0x15 +#define BIT_PROPERTYPTR 0x16 // Not documented in ECMA-335 +#define BIT_PROPERTY 0x17 +#define BIT_METHODSEMANTICS 0x18 +#define BIT_METHODIMPL 0x19 +#define BIT_MODULEREF 0x1A +#define BIT_TYPESPEC 0x1B +#define BIT_IMPLMAP 0x1C +#define BIT_FIELDRVA 0x1D +#define BIT_ENCLOG 0x1E // Not documented in ECMA-335 +#define BIT_ENCMAP 0x1F // Not documented in ECMA-335 +#define BIT_ASSEMBLY 0x20 +#define BIT_ASSEMBLYPROCESSOR 0x21 +#define BIT_ASSEMBLYOS 0x22 +#define BIT_ASSEMBLYREF 0x23 +#define BIT_ASSEMBLYREFPROCESSOR 0x24 +#define BIT_ASSEMBLYREFOS 0x25 +#define BIT_FILE 0x26 +#define BIT_EXPORTEDTYPE 0x27 +#define BIT_MANIFESTRESOURCE 0x28 +#define BIT_NESTEDCLASS 0x29 +#define BIT_GENERICPARAM 0x2A +#define BIT_METHODSPEC 0x2B +#define BIT_GENERICPARAMCONSTRAINT 0x2C +// These are not documented in ECMA-335 nor is it clear what the format is. +// They are for debugging information as far as I can tell. +//#define BIT_DOCUMENT 0x30 +//#define BIT_METHODDEBUGINFORMATION 0x31 +//#define BIT_LOCALSCOPE 0x32 +//#define BIT_LOCALVARIABLE 0x33 +//#define BIT_LOCALCONSTANT 0x34 +//#define BIT_IMPORTSCOPE 0x35 +//#define BIT_STATEMACHINEMETHOD 0x36 + + +// +// Element types. Note this is not a complete list as we aren't parsing all of +// them. This only includes the ones we care about. +// ECMA-335 Section II.23.1.16 +// +#define ELEMENT_TYPE_STRING 0x0E + + +// The string length of a typelib attribute is at most 0xFF. +#define MAX_TYPELIB_SIZE 0xFF + +// +// Module table +// ECMA-335 Section II.22.30 +// +typedef struct _MODULE_TABLE { + WORD Generation; + union { + WORD Name_Short; + DWORD Name_Long; + } Name; + union { + WORD Mvid_Short; + DWORD Mvid_Long; + } Mvid; + union { + WORD EncId_Short; + DWORD EncId_Long; + } EncId; + union { + WORD EncBaseId_Short; + DWORD EncBaseId_Long; + } EncBaseId; +} MODULE_TABLE, *PMODULE_TABLE; + +// +// Assembly Table +// ECMA-335 Section II.22.2 +// +typedef struct _ASSEMBLY_TABLE { + DWORD HashAlgId; + WORD MajorVersion; + WORD MinorVersion; + WORD BuildNumber; + WORD RevisionNumber; + DWORD Flags; + union { + WORD PublicKey_Short; + DWORD PublicKey_Long; + } PublicKey; + union { + WORD Name_Short; + DWORD Name_Long; + } Name; +} ASSEMBLY_TABLE, *PASSEMBLY_TABLE; + + +// +// Assembly Reference Table +// ECMA-335 Section II.22.5 +// +typedef struct _ASSEMBLYREF_TABLE { + WORD MajorVersion; + WORD MinorVersion; + WORD BuildNumber; + WORD RevisionNumber; + DWORD Flags; + union { + WORD PublicKeyOrToken_Short; + DWORD PublicKeyOrToken_Long; + } PublicKeyOrToken; + union { + WORD Name_Short; + DWORD Name_Long; + } Name; +} ASSEMBLYREF_TABLE, *PASSEMBLYREF_TABLE; + + +// +// Manifest Resource Table +// ECMA-335 Section II.22.24 +// +typedef struct _MANIFESTRESOURCE_TABLE { + DWORD Offset; + DWORD Flags; + union { + WORD Name_Short; + DWORD Name_Long; + } Name; + union { + WORD Implementation_Short; + DWORD Implementation_Long; + } Implementation; +} MANIFESTRESOURCE_TABLE, *PMANIFESTRESOURCE_TABLE; + +// +// ModuleRef Table +// ECMA-335 Section II.22.31 +// +// This is a short table, but necessary because the field size can change. +// +typedef struct _MODULEREF_TABLE { + union { + WORD Name_Short; + DWORD Name_Long; + } Name; +} MODULEREF_TABLE, *PMODULEREF_TABLE; + + +// +// CustomAttribute Table +// ECMA-335 Section II.22.10 +// +typedef struct _CUSTOMATTRIBUTE_TABLE { + union { + WORD Parent_Short; + DWORD Parent_Long; + } Parent; + union { + WORD Type_Short; + DWORD Type_Long; + } Type; + union { + WORD Value_Short; + DWORD Value_Long; + } Value; +} CUSTOMATTRIBUTE_TABLE, *PCUSTOMATTRIBUTE_TABLE; + + +// +// Constant TAble +// ECMA-335 Section II.22.9 +// +typedef struct _CONSTANT_TABLE { + WORD Type; + union { + WORD Parent_Short; + DWORD Parent_Long; + } Parent; + union { + WORD Value_Short; + DWORD Value_Long; + } Value; +} CONSTANT_TABLE, *PCONSTANT_TABLE; + + +// Used to return offsets to the various headers. +typedef struct _STREAMS { + PSTREAM_HEADER guid; + PSTREAM_HEADER tilde; + PSTREAM_HEADER string; + PSTREAM_HEADER blob; + PSTREAM_HEADER us; +} STREAMS, *PSTREAMS; + + +// Used to return the value of parsing a #US or #Blob entry. +// ECMA-335 Section II.24.2.4 +typedef struct _BLOB_PARSE_RESULT { + uint8_t size; // Number of bytes parsed. This is the new offset. + DWORD length; // Value of the bytes parsed. This is the blob length. +} BLOB_PARSE_RESULT, *PBLOB_PARSE_RESULT; + + +// Used to store the number of rows of each table. +typedef struct _ROWS { + uint32_t module; + uint32_t moduleref; + uint32_t assemblyref; + uint32_t typeref; + uint32_t methoddef; + uint32_t memberref; + uint32_t typedef_; + uint32_t typespec; + uint32_t field; + uint32_t param; + uint32_t property; + uint32_t interfaceimpl; + uint32_t event; + uint32_t standalonesig; + uint32_t assembly; + uint32_t file; + uint32_t exportedtype; + uint32_t manifestresource; + uint32_t genericparam; + uint32_t genericparamconstraint; + uint32_t methodspec; + uint32_t assemblyrefprocessor; +} ROWS, *PROWS; + + +// Used to store the index sizes for the various tables. +typedef struct _INDEX_SIZES { + uint8_t string; + uint8_t guid; + uint8_t blob; + uint8_t field; + uint8_t methoddef; + uint8_t memberref; + uint8_t param; + uint8_t event; + uint8_t typedef_; + uint8_t property; + uint8_t moduleref; + uint8_t assemblyrefprocessor; + uint8_t assemblyref; + uint8_t genericparam; +} INDEX_SIZES, *PINDEX_SIZES; + +#pragma pack(pop) +#endif diff --git a/yara-master/libyara/include/yara/elf.h b/yara-master/libyara/include/yara/elf.h new file mode 100644 index 0000000..4260c56 --- /dev/null +++ b/yara-master/libyara/include/yara/elf.h @@ -0,0 +1,323 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef _ELF_H +#define _ELF_H + +#include + + +// 32-bit ELF base types + +typedef uint32_t elf32_addr_t; +typedef uint16_t elf32_half_t; +typedef uint32_t elf32_off_t; +typedef uint32_t elf32_word_t; + +// 64-bit ELF base types + +typedef uint64_t elf64_addr_t; +typedef uint16_t elf64_half_t; +typedef uint64_t elf64_off_t; +typedef uint32_t elf64_word_t; +typedef uint64_t elf64_xword_t; + +#define ELF_MAGIC 0x464C457F + +#define ELF_ET_NONE 0x0000 // no type +#define ELF_ET_REL 0x0001 // relocatable +#define ELF_ET_EXEC 0x0002 // executable +#define ELF_ET_DYN 0x0003 // Shared-Object-File +#define ELF_ET_CORE 0x0004 // Corefile +#define ELF_ET_LOPROC 0xFF00 // Processor-specific +#define ELF_ET_HIPROC 0x00FF // Processor-specific + +#define ELF_EM_NONE 0x0000 // no type +#define ELF_EM_M32 0x0001 // AT&T WE 32100 +#define ELF_EM_SPARC 0x0002 // SPARC +#define ELF_EM_386 0x0003 // Intel 80386 +#define ELF_EM_68K 0x0004 // Motorola 68000 +#define ELF_EM_88K 0x0005 // Motorola 88000 +#define ELF_EM_860 0x0007 // Intel 80860 +#define ELF_EM_MIPS 0x0008 // MIPS I Architecture +#define ELF_EM_MIPS_RS3_LE 0x000A // MIPS RS3000 Little-endian +#define ELF_EM_PPC 0x0014 // PowerPC +#define ELF_EM_PPC64 0x0015 // 64-bit PowerPC +#define ELF_EM_ARM 0x0028 // ARM +#define ELF_EM_X86_64 0x003E // AMD/Intel x86_64 +#define ELF_EM_AARCH64 0x00B7 // 64-bit ARM + +#define ELF_CLASS_NONE 0x0000 +#define ELF_CLASS_32 0x0001 // 32bit file +#define ELF_CLASS_64 0x0002 // 64bit file + +#define ELF_DATA_NONE 0x0000 +#define ELF_DATA_2LSB 0x0001 +#define ELF_DATA_2MSB 0x002 + + +#define ELF_SHT_NULL 0 // Section header table entry unused +#define ELF_SHT_PROGBITS 1 // Program data +#define ELF_SHT_SYMTAB 2 // Symbol table +#define ELF_SHT_STRTAB 3 // String table +#define ELF_SHT_RELA 4 // Relocation entries with addends +#define ELF_SHT_HASH 5 // Symbol hash table +#define ELF_SHT_DYNAMIC 6 // Dynamic linking information +#define ELF_SHT_NOTE 7 // Notes +#define ELF_SHT_NOBITS 8 // Program space with no data (bss) +#define ELF_SHT_REL 9 // Relocation entries, no addends +#define ELF_SHT_SHLIB 10 // Reserved +#define ELF_SHT_DYNSYM 11 // Dynamic linker symbol table +#define ELF_SHT_NUM 12 // Number of defined types + +#define ELF_SHF_WRITE 0x1 // Section is writable +#define ELF_SHF_ALLOC 0x2 // Section is present during execution +#define ELF_SHF_EXECINSTR 0x4 // Section contains executable instructions + +#define ELF_SHN_LORESERVE 0xFF00 + +#define ELF_PT_NULL 0 // The array element is unused +#define ELF_PT_LOAD 1 // Loadable segment +#define ELF_PT_DYNAMIC 2 // Segment contains dynamic linking info +#define ELF_PT_INTERP 3 // Contains interpreter pathname +#define ELF_PT_NOTE 4 // Location & size of auxiliary info +#define ELF_PT_SHLIB 5 // Reserved, unspecified semantics +#define ELF_PT_PHDR 6 // Location and size of program header table +#define ELF_PT_TLS 7 // Thread-Local Storage +#define ELF_PT_GNU_EH_FRAME 0x6474e550 +#define ELF_PT_GNU_STACK 0x6474e551 + +#define ELF_DT_NULL 0 // End of the dynamic entries +#define ELF_DT_NEEDED 1 // Name of needed library +#define ELF_DT_PLTRELSZ 2 // Size in bytes of PLT relocs +#define ELF_DT_PLTGOT 3 // Processor defined value */ +#define ELF_DT_HASH 4 // Address of symbol hash table +#define ELF_DT_STRTAB 5 // Address of string table +#define ELF_DT_SYMTAB 6 // Address of symbol table +#define ELF_DT_RELA 7 // Address of Rela relocs +#define ELF_DT_RELASZ 8 // Total size of Rela relocs +#define ELF_DT_RELAENT 9 // Size of one Rela reloc +#define ELF_DT_STRSZ 10 // Size of string table +#define ELF_DT_SYMENT 11 // Size of one symbol table entry +#define ELF_DT_INIT 12 // Address of init function +#define ELF_DT_FINI 13 // Address of termination function +#define ELF_DT_SONAME 14 // Name of shared object +#define ELF_DT_RPATH 15 // Library search path (deprecated) +#define ELF_DT_SYMBOLIC 16 // Start symbol search here +#define ELF_DT_REL 17 // Address of Rel relocs +#define ELF_DT_RELSZ 18 // Total size of Rel relocs +#define ELF_DT_RELENT 19 // Size of one Rel reloc +#define ELF_DT_PLTREL 20 // Type of reloc in PLT +#define ELF_DT_DEBUG 21 // For debugging; unspecified +#define ELF_DT_TEXTREL 22 // Reloc might modify .text +#define ELF_DT_JMPREL 23 // Address of PLT relocs +#define ELF_DT_BIND_NOW 24 // Process relocations of object +#define ELF_DT_INIT_ARRAY 25 // Array with addresses of init fct +#define ELF_DT_FINI_ARRAY 26 // Array with addresses of fini fct +#define ELF_DT_INIT_ARRAYSZ 27 // Size in bytes of DT_INIT_ARRAY +#define ELF_DT_FINI_ARRAYSZ 28 // Size in bytes of DT_FINI_ARRAY +#define ELF_DT_RUNPATH 29 // Library search path +#define ELF_DT_FLAGS 30 // Flags for the object being loaded +#define ELF_DT_ENCODING 32 // Start of encoded range + +#define ELF_STT_NOTYPE 0 // Symbol type is unspecified +#define ELF_STT_OBJECT 1 // Symbol is a data object +#define ELF_STT_FUNC 2 // Symbol is a code object +#define ELF_STT_SECTION 3 // Symbol associated with a section +#define ELF_STT_FILE 4 // Symbol's name is file name +#define ELF_STT_COMMON 5 // Symbol is a common data object +#define ELF_STT_TLS 6 // Symbol is thread-local data object + +#define ELF_STB_LOCAL 0 // Local symbol +#define ELF_STB_GLOBAL 1 // Global symbol +#define ELF_STB_WEAK 2 // Weak symbol + +#define ELF_PF_X 0x1 // Segment is executable +#define ELF_PF_W 0x2 // Segment is writable +#define ELF_PF_R 0x4 // Segment is readable + +#define ELF_PN_XNUM 0xffff + +#pragma pack(push,1) + +typedef struct +{ + uint32_t magic; + uint8_t _class; + uint8_t data; + uint8_t version; + uint8_t pad[8]; + uint8_t nident; + +} elf_ident_t; + + +typedef struct +{ + elf_ident_t ident; + elf32_half_t type; + elf32_half_t machine; + elf32_word_t version; + elf32_addr_t entry; + elf32_off_t ph_offset; + elf32_off_t sh_offset; + elf32_word_t flags; + elf32_half_t header_size; + elf32_half_t ph_entry_size; + elf32_half_t ph_entry_count; + elf32_half_t sh_entry_size; + elf32_half_t sh_entry_count; + elf32_half_t sh_str_table_index; + +} elf32_header_t; + + +typedef struct +{ + elf_ident_t ident; + elf64_half_t type; + elf64_half_t machine; + elf64_word_t version; + elf64_addr_t entry; + elf64_off_t ph_offset; + elf64_off_t sh_offset; + elf64_word_t flags; + elf64_half_t header_size; + elf64_half_t ph_entry_size; + elf64_half_t ph_entry_count; + elf64_half_t sh_entry_size; + elf64_half_t sh_entry_count; + elf64_half_t sh_str_table_index; + +} elf64_header_t; + + +typedef struct +{ + elf32_word_t type; + elf32_off_t offset; + elf32_addr_t virt_addr; + elf32_addr_t phys_addr; + elf32_word_t file_size; + elf32_word_t mem_size; + elf32_word_t flags; + elf32_word_t alignment; + +} elf32_program_header_t; + + +typedef struct +{ + elf64_word_t type; + elf64_word_t flags; + elf64_off_t offset; + elf64_addr_t virt_addr; + elf64_addr_t phys_addr; + elf64_xword_t file_size; + elf64_xword_t mem_size; + elf64_xword_t alignment; + +} elf64_program_header_t; + + +typedef struct +{ + elf32_word_t name; + elf32_word_t type; + elf32_word_t flags; + elf32_addr_t addr; + elf32_off_t offset; + elf32_word_t size; + elf32_word_t link; + elf32_word_t info; + elf32_word_t align; + elf32_word_t entry_size; + +} elf32_section_header_t; + + +typedef struct +{ + elf64_word_t name; + elf64_word_t type; + elf64_xword_t flags; + elf64_addr_t addr; + elf64_off_t offset; + elf64_xword_t size; + elf64_word_t link; + elf64_word_t info; + elf64_xword_t align; + elf64_xword_t entry_size; + +} elf64_section_header_t; + + +typedef struct +{ + elf32_word_t tag; + elf32_word_t val; + +} elf32_dyn_t; + + +typedef struct +{ + elf64_xword_t tag; + elf64_xword_t val; + +} elf64_dyn_t; + + +typedef struct +{ + elf32_word_t name; + elf32_addr_t value; + elf32_word_t size; + unsigned char info; + unsigned char other; + elf32_half_t shndx; + +} elf32_sym_t; + + +typedef struct +{ + elf32_word_t name; + unsigned char info; + unsigned char other; + elf32_half_t shndx; + elf64_addr_t value; + elf64_xword_t size; + +} elf64_sym_t; + + +#pragma pack(pop) + +#endif diff --git a/yara-master/libyara/include/yara/endian.h b/yara-master/libyara/include/yara/endian.h new file mode 100644 index 0000000..42c76a1 --- /dev/null +++ b/yara-master/libyara/include/yara/endian.h @@ -0,0 +1,100 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_ENDIAN_H +#define YR_ENDIAN_H + +#include + + +#if defined(__has_builtin) +# if __has_builtin(__builtin_bswap16) +# define yr_bswap16(x) __builtin_bswap16(x) +# endif +#endif + +#if !defined(yr_bswap16) && defined(_MSC_VER) +# define yr_bswap16(x) _byteswap_ushort(x) +#endif + +#if !defined(yr_bswap16) +uint16_t _yr_bswap16(uint16_t x); +# define yr_bswap16(x) _yr_bswap16(x) +#endif + + +#if defined(__has_builtin) +# if __has_builtin(__builtin_bswap32) +# define yr_bswap32(x) __builtin_bswap32(x) +# endif +#endif + +#if !defined(yr_bswap32) && defined(_MSC_VER) +# define yr_bswap32(x) _byteswap_ulong(x) +#endif + +#if !defined(yr_bswap32) +uint32_t _yr_bswap32(uint32_t x); +#define yr_bswap32(x) _yr_bswap32(x) +#endif + + +#if defined(__has_builtin) +# if __has_builtin(__builtin_bswap64) +# define yr_bswap64(x) __builtin_bswap64(x) +# endif +#endif + +#if !defined(yr_bswap64) && defined(_MSC_VER) +# define yr_bswap64(x) _byteswap_uint64(x) +#endif + +#if !defined(yr_bswap64) +uint64_t _yr_bswap64(uint64_t x); +#define yr_bswap64(x) _yr_bswap64(x) +#endif + + +#if defined(WORDS_BIGENDIAN) +#define yr_le16toh(x) yr_bswap16(x) +#define yr_le32toh(x) yr_bswap32(x) +#define yr_le64toh(x) yr_bswap64(x) +#define yr_be16toh(x) (x) +#define yr_be32toh(x) (x) +#define yr_be64toh(x) (x) +#else +#define yr_le16toh(x) (x) +#define yr_le32toh(x) (x) +#define yr_le64toh(x) (x) +#define yr_be16toh(x) yr_bswap16(x) +#define yr_be32toh(x) yr_bswap32(x) +#define yr_be64toh(x) yr_bswap64(x) +#endif + +#endif diff --git a/yara-master/libyara/include/yara/error.h b/yara-master/libyara/include/yara/error.h new file mode 100644 index 0000000..310ea6c --- /dev/null +++ b/yara-master/libyara/include/yara/error.h @@ -0,0 +1,133 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_ERROR_H +#define YR_ERROR_H + +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#endif + +#ifndef ERROR_SUCCESS +#define ERROR_SUCCESS 0 +#endif + +// ERROR_INSUFICIENT_MEMORY is misspelled but it's kept for backward +// compatibility, as some other programs can be using it in this form. +#define ERROR_INSUFICIENT_MEMORY 1 + +#define ERROR_INSUFFICIENT_MEMORY 1 +#define ERROR_COULD_NOT_ATTACH_TO_PROCESS 2 +#define ERROR_COULD_NOT_OPEN_FILE 3 +#define ERROR_COULD_NOT_MAP_FILE 4 +#define ERROR_INVALID_FILE 6 +#define ERROR_CORRUPT_FILE 7 +#define ERROR_UNSUPPORTED_FILE_VERSION 8 +#define ERROR_INVALID_REGULAR_EXPRESSION 9 +#define ERROR_INVALID_HEX_STRING 10 +#define ERROR_SYNTAX_ERROR 11 +#define ERROR_LOOP_NESTING_LIMIT_EXCEEDED 12 +#define ERROR_DUPLICATED_LOOP_IDENTIFIER 13 +#define ERROR_DUPLICATED_IDENTIFIER 14 +#define ERROR_DUPLICATED_TAG_IDENTIFIER 15 +#define ERROR_DUPLICATED_META_IDENTIFIER 16 +#define ERROR_DUPLICATED_STRING_IDENTIFIER 17 +#define ERROR_UNREFERENCED_STRING 18 +#define ERROR_UNDEFINED_STRING 19 +#define ERROR_UNDEFINED_IDENTIFIER 20 +#define ERROR_MISPLACED_ANONYMOUS_STRING 21 +#define ERROR_INCLUDES_CIRCULAR_REFERENCE 22 +#define ERROR_INCLUDE_DEPTH_EXCEEDED 23 +#define ERROR_WRONG_TYPE 24 +#define ERROR_EXEC_STACK_OVERFLOW 25 +#define ERROR_SCAN_TIMEOUT 26 +#define ERROR_TOO_MANY_SCAN_THREADS 27 +#define ERROR_CALLBACK_ERROR 28 +#define ERROR_INVALID_ARGUMENT 29 +#define ERROR_TOO_MANY_MATCHES 30 +#define ERROR_INTERNAL_FATAL_ERROR 31 +#define ERROR_NESTED_FOR_OF_LOOP 32 +#define ERROR_INVALID_FIELD_NAME 33 +#define ERROR_UNKNOWN_MODULE 34 +#define ERROR_NOT_A_STRUCTURE 35 +#define ERROR_NOT_INDEXABLE 36 +#define ERROR_NOT_A_FUNCTION 37 +#define ERROR_INVALID_FORMAT 38 +#define ERROR_TOO_MANY_ARGUMENTS 39 +#define ERROR_WRONG_ARGUMENTS 40 +#define ERROR_WRONG_RETURN_TYPE 41 +#define ERROR_DUPLICATED_STRUCTURE_MEMBER 42 +#define ERROR_EMPTY_STRING 43 +#define ERROR_DIVISION_BY_ZERO 44 +#define ERROR_REGULAR_EXPRESSION_TOO_LARGE 45 +#define ERROR_TOO_MANY_RE_FIBERS 46 +#define ERROR_COULD_NOT_READ_PROCESS_MEMORY 47 +#define ERROR_INVALID_EXTERNAL_VARIABLE_TYPE 48 +#define ERROR_REGULAR_EXPRESSION_TOO_COMPLEX 49 +#define ERROR_INVALID_MODULE_NAME 50 +#define ERROR_TOO_MANY_STRINGS 51 +#define ERROR_INTEGER_OVERFLOW 52 +#define ERROR_CALLBACK_REQUIRED 53 +#define ERROR_INVALID_OPERAND 54 + + +#define FAIL_ON_ERROR(x) { \ + int result = (x); \ + if (result != ERROR_SUCCESS) \ + return result; \ +} + +#define FAIL_ON_ERROR_WITH_CLEANUP(x, cleanup) { \ + int result = (x); \ + if (result != ERROR_SUCCESS) { \ + cleanup; \ + return result; \ + } \ +} + +#define FAIL_ON_COMPILER_ERROR(x) { \ + compiler->last_result = (x); \ + if (compiler->last_result != ERROR_SUCCESS) \ + return compiler->last_result; \ +} + + +#ifdef NDEBUG +#define assertf(expr, msg, ...) ((void)0) +#else +#define assertf(expr, msg, ...) \ + if(!(expr)) { \ + fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ + abort(); \ + } +#endif + +#endif diff --git a/yara-master/libyara/include/yara/exec.h b/yara-master/libyara/include/yara/exec.h new file mode 100644 index 0000000..c0a3e13 --- /dev/null +++ b/yara-master/libyara/include/yara/exec.h @@ -0,0 +1,175 @@ +/* +Copyright (c) 2013-2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_EXEC_H +#define YR_EXEC_H + +#include +#include +#include +#include + + +#define LOOP_LOCAL_VARS 4 + +#define UNDEFINED 0xFFFABADAFABADAFFLL +#define IS_UNDEFINED(x) ((size_t)(x) == (size_t) UNDEFINED) + +#define OP_ERROR 0 +#define OP_HALT 255 +#define OP_NOP 254 + +#define OP_AND 1 +#define OP_OR 2 +#define OP_NOT 3 +#define OP_BITWISE_NOT 4 +#define OP_BITWISE_AND 5 +#define OP_BITWISE_OR 6 +#define OP_BITWISE_XOR 7 +#define OP_SHL 8 +#define OP_SHR 9 +#define OP_MOD 10 +#define OP_INT_TO_DBL 11 +#define OP_STR_TO_BOOL 12 +#define OP_PUSH 13 +#define OP_POP 14 +#define OP_CALL 15 +#define OP_OBJ_LOAD 16 +#define OP_OBJ_VALUE 17 +#define OP_OBJ_FIELD 18 +#define OP_INDEX_ARRAY 19 +#define OP_COUNT 20 +#define OP_LENGTH 21 +#define OP_FOUND 22 +#define OP_FOUND_AT 23 +#define OP_FOUND_IN 24 +#define OP_OFFSET 25 +#define OP_OF 26 +#define OP_PUSH_RULE 27 +#define OP_INIT_RULE 28 +#define OP_MATCH_RULE 29 +#define OP_INCR_M 30 +#define OP_CLEAR_M 31 +#define OP_ADD_M 32 +#define OP_POP_M 33 +#define OP_PUSH_M 34 +#define OP_SWAPUNDEF 35 +#define OP_JNUNDEF 36 +#define OP_JLE 37 +#define OP_FILESIZE 38 +#define OP_ENTRYPOINT 39 +#define OP_CONTAINS 40 +#define OP_MATCHES 41 +#define OP_IMPORT 42 +#define OP_LOOKUP_DICT 43 +#define OP_JFALSE 44 +#define OP_JTRUE 45 + + +#define _OP_EQ 0 +#define _OP_NEQ 1 +#define _OP_LT 2 +#define _OP_GT 3 +#define _OP_LE 4 +#define _OP_GE 5 +#define _OP_ADD 6 +#define _OP_SUB 7 +#define _OP_MUL 8 +#define _OP_DIV 9 +#define _OP_MINUS 10 + + +#define OP_INT_BEGIN 100 +#define OP_INT_EQ (OP_INT_BEGIN + _OP_EQ) +#define OP_INT_NEQ (OP_INT_BEGIN + _OP_NEQ) +#define OP_INT_LT (OP_INT_BEGIN + _OP_LT) +#define OP_INT_GT (OP_INT_BEGIN + _OP_GT) +#define OP_INT_LE (OP_INT_BEGIN + _OP_LE) +#define OP_INT_GE (OP_INT_BEGIN + _OP_GE) +#define OP_INT_ADD (OP_INT_BEGIN + _OP_ADD) +#define OP_INT_SUB (OP_INT_BEGIN + _OP_SUB) +#define OP_INT_MUL (OP_INT_BEGIN + _OP_MUL) +#define OP_INT_DIV (OP_INT_BEGIN + _OP_DIV) +#define OP_INT_MINUS (OP_INT_BEGIN + _OP_MINUS) +#define OP_INT_END OP_INT_MINUS + +#define OP_DBL_BEGIN 120 +#define OP_DBL_EQ (OP_DBL_BEGIN + _OP_EQ) +#define OP_DBL_NEQ (OP_DBL_BEGIN + _OP_NEQ) +#define OP_DBL_LT (OP_DBL_BEGIN + _OP_LT) +#define OP_DBL_GT (OP_DBL_BEGIN + _OP_GT) +#define OP_DBL_LE (OP_DBL_BEGIN + _OP_LE) +#define OP_DBL_GE (OP_DBL_BEGIN + _OP_GE) +#define OP_DBL_ADD (OP_DBL_BEGIN + _OP_ADD) +#define OP_DBL_SUB (OP_DBL_BEGIN + _OP_SUB) +#define OP_DBL_MUL (OP_DBL_BEGIN + _OP_MUL) +#define OP_DBL_DIV (OP_DBL_BEGIN + _OP_DIV) +#define OP_DBL_MINUS (OP_DBL_BEGIN + _OP_MINUS) +#define OP_DBL_END OP_DBL_MINUS + +#define OP_STR_BEGIN 140 +#define OP_STR_EQ (OP_STR_BEGIN + _OP_EQ) +#define OP_STR_NEQ (OP_STR_BEGIN + _OP_NEQ) +#define OP_STR_LT (OP_STR_BEGIN + _OP_LT) +#define OP_STR_GT (OP_STR_BEGIN + _OP_GT) +#define OP_STR_LE (OP_STR_BEGIN + _OP_LE) +#define OP_STR_GE (OP_STR_BEGIN + _OP_GE) +#define OP_STR_END OP_STR_GE + +#define IS_INT_OP(x) ((x) >= OP_INT_BEGIN && (x) <= OP_INT_END) +#define IS_DBL_OP(x) ((x) >= OP_DBL_BEGIN && (x) <= OP_DBL_END) +#define IS_STR_OP(x) ((x) >= OP_STR_BEGIN && (x) <= OP_STR_END) + +#define OP_READ_INT 240 +#define OP_INT8 (OP_READ_INT + 0) +#define OP_INT16 (OP_READ_INT + 1) +#define OP_INT32 (OP_READ_INT + 2) +#define OP_UINT8 (OP_READ_INT + 3) +#define OP_UINT16 (OP_READ_INT + 4) +#define OP_UINT32 (OP_READ_INT + 5) +#define OP_INT8BE (OP_READ_INT + 6) +#define OP_INT16BE (OP_READ_INT + 7) +#define OP_INT32BE (OP_READ_INT + 8) +#define OP_UINT8BE (OP_READ_INT + 9) +#define OP_UINT16BE (OP_READ_INT + 10) +#define OP_UINT32BE (OP_READ_INT + 11) + + +#define OPERATION(operator, op1, op2) \ + (IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (UNDEFINED) : (op1 operator op2) + + +#define COMPARISON(operator, op1, op2) \ + (IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (0) : (op1 operator op2) + + +int yr_execute_code( + YR_SCAN_CONTEXT* context); + +#endif diff --git a/yara-master/libyara/include/yara/exefiles.h b/yara-master/libyara/include/yara/exefiles.h new file mode 100644 index 0000000..c8a6664 --- /dev/null +++ b/yara-master/libyara/include/yara/exefiles.h @@ -0,0 +1,43 @@ +/* +Copyright (c) 2007. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_EXEFILES_H +#define YR_EXEFILES_H + +uint64_t yr_get_entry_point_offset( + const uint8_t* buffer, + size_t buffer_length); + + +uint64_t yr_get_entry_point_address( + const uint8_t* buffer, + size_t buffer_length, + uint64_t base_address); + +#endif diff --git a/yara-master/libyara/include/yara/filemap.h b/yara-master/libyara/include/yara/filemap.h new file mode 100644 index 0000000..a932c7b --- /dev/null +++ b/yara-master/libyara/include/yara/filemap.h @@ -0,0 +1,90 @@ +/* +Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_FILEMAP_H +#define YR_FILEMAP_H + +#ifdef _MSC_VER +#define off_t int64_t +#else +#include +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#define YR_FILE_DESCRIPTOR HANDLE +#else +#define YR_FILE_DESCRIPTOR int +#endif + +#include + +#include +#include + + +typedef struct _YR_MAPPED_FILE +{ + YR_FILE_DESCRIPTOR file; + size_t size; + const uint8_t* data; + #if defined(_WIN32) || defined(__CYGWIN__) + HANDLE mapping; + #endif + +} YR_MAPPED_FILE; + + +YR_API int yr_filemap_map( + const char* file_path, + YR_MAPPED_FILE* pmapped_file); + + +YR_API int yr_filemap_map_fd( + YR_FILE_DESCRIPTOR file, + off_t offset, + size_t size, + YR_MAPPED_FILE* pmapped_file); + + +YR_API int yr_filemap_map_ex( + const char* file_path, + off_t offset, + size_t size, + YR_MAPPED_FILE* pmapped_file); + + +YR_API void yr_filemap_unmap( + YR_MAPPED_FILE* pmapped_file); + + +YR_API void yr_filemap_unmap_fd( + YR_MAPPED_FILE* pmapped_file); + +#endif diff --git a/yara-master/libyara/include/yara/globals.h b/yara-master/libyara/include/yara/globals.h new file mode 100644 index 0000000..efe0671 --- /dev/null +++ b/yara-master/libyara/include/yara/globals.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_GLOBALS_H +#define YR_GLOBALS_H + +#include + +extern char yr_lowercase[256]; +extern char yr_altercase[256]; + +extern YR_THREAD_STORAGE_KEY yr_tidx_key; +extern YR_THREAD_STORAGE_KEY yr_recovery_state_key; + +#endif diff --git a/yara-master/libyara/include/yara/hash.h b/yara-master/libyara/include/yara/hash.h new file mode 100644 index 0000000..8108333 --- /dev/null +++ b/yara-master/libyara/include/yara/hash.h @@ -0,0 +1,123 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_HASH_H +#define YR_HASH_H + +#include + +#include +#include + +typedef struct _YR_HASH_TABLE_ENTRY +{ + void* key; + size_t key_length; + char* ns; + void* value; + + struct _YR_HASH_TABLE_ENTRY* next; + +} YR_HASH_TABLE_ENTRY; + + +typedef struct _YR_HASH_TABLE +{ + int size; + + YR_HASH_TABLE_ENTRY* buckets[1]; + +} YR_HASH_TABLE; + + +typedef int (*YR_HASH_TABLE_FREE_VALUE_FUNC)(void* value); + + +uint32_t yr_hash( + uint32_t seed, + const void* buffer, + size_t len); + + +YR_API int yr_hash_table_create( + int size, + YR_HASH_TABLE** table); + + +YR_API void yr_hash_table_clean( + YR_HASH_TABLE* table, + YR_HASH_TABLE_FREE_VALUE_FUNC free_value); + + +YR_API void yr_hash_table_destroy( + YR_HASH_TABLE* table, + YR_HASH_TABLE_FREE_VALUE_FUNC free_value); + + +YR_API void* yr_hash_table_lookup( + YR_HASH_TABLE* table, + const char* key, + const char* ns); + + +YR_API void* yr_hash_table_remove( + YR_HASH_TABLE* table, + const char* key, + const char* ns); + + +YR_API int yr_hash_table_add( + YR_HASH_TABLE* table, + const char* key, + const char* ns, + void* value); + + +YR_API void* yr_hash_table_lookup_raw_key( + YR_HASH_TABLE* table, + const void* key, + size_t key_length, + const char* ns); + + +YR_API void* yr_hash_table_remove_raw_key( + YR_HASH_TABLE* table, + const void* key, + size_t key_length, + const char* ns); + + +YR_API int yr_hash_table_add_raw_key( + YR_HASH_TABLE* table, + const void* key, + size_t key_length, + const char* ns, + void* value); + +#endif diff --git a/yara-master/libyara/include/yara/hex_lexer.h b/yara-master/libyara/include/yara/hex_lexer.h new file mode 100644 index 0000000..77527ca --- /dev/null +++ b/yara-master/libyara/include/yara/hex_lexer.h @@ -0,0 +1,109 @@ +/* +Copyright (c) 2007. Victor M. Alvarez [plusvic@gmail.com]. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#undef yyparse +#undef yylex +#undef yyerror +#undef yyfatal +#undef yychar +#undef yydebug +#undef yynerrs +#undef yyget_extra +#undef yyget_lineno + +#undef YY_FATAL_ERROR +#undef YY_DECL +#undef LEX_ENV + +#define yyparse hex_yyparse +#define yylex hex_yylex +#define yyerror hex_yyerror +#define yyfatal hex_yyfatal +#define yychar hex_yychar +#define yydebug hex_yydebug +#define yynerrs hex_yynerrs +#define yyget_extra hex_yyget_extra +#define yyget_lineno hex_yyget_lineno + + +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +#define YY_EXTRA_TYPE RE_AST* +#define YY_USE_CONST + + +typedef struct _HEX_LEX_ENVIRONMENT +{ + int inside_or; + int last_error_code; + char last_error_message[256]; + +} HEX_LEX_ENVIRONMENT; + + +#define YY_FATAL_ERROR(msg) hex_yyfatal(yyscanner, msg) + +#define LEX_ENV ((HEX_LEX_ENVIRONMENT*) lex_env) + +#include + +#define YY_DECL int hex_yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner, HEX_LEX_ENVIRONMENT* lex_env) + + +YY_EXTRA_TYPE yyget_extra( + yyscan_t yyscanner); + +int yylex( + YYSTYPE* yylval_param, + yyscan_t yyscanner, + HEX_LEX_ENVIRONMENT* lex_env); + +int yyparse( + void *yyscanner, + HEX_LEX_ENVIRONMENT *lex_env); + +void yyerror( + yyscan_t yyscanner, + HEX_LEX_ENVIRONMENT* lex_env, + const char *error_message); + +void yyfatal( + yyscan_t yyscanner, + const char *error_message); + +int yr_parse_hex_string( + const char* hex_string, + RE_AST** re_ast, + RE_ERROR* error); diff --git a/yara-master/libyara/include/yara/integers.h b/yara-master/libyara/include/yara/integers.h new file mode 100644 index 0000000..082c33d --- /dev/null +++ b/yara-master/libyara/include/yara/integers.h @@ -0,0 +1,115 @@ +/* +Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_INTEGERS_H +#define YR_INTEGERS_H + + +#if ( defined( _MSC_VER ) && ( _MSC_VER < 1600 ) ) || ( defined( __BORLANDC__ ) && ( __BORLANDC__ <= 0x0560 ) ) + +#ifdef __cplusplus +extern "C" { +#endif + +// Microsoft Visual Studio C++ before Visual Studio 2010 or earlier versions of +// the Borland C++ Builder do not support the (u)int#_t type definitions but +// have __int# definitions instead + +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#ifdef __cplusplus +} +#endif + + +#ifndef INT8_MIN +#define INT8_MIN (-127i8 - 1) +#endif + +#ifndef INT8_MIN +#define INT16_MIN (-32767i16 - 1) +#endif + +#ifndef INT32_MIN +#define INT32_MIN (-2147483647i32 - 1) +#endif + +#ifndef INT64_MIN +#define INT64_MIN (-9223372036854775807i64 - 1) +#endif + +#ifndef INT8_MAX +#define INT8_MAX 127i8 +#endif + +#ifndef INT16_MAX +#define INT16_MAX 32767i16 +#endif + +#ifndef INT32_MAX +#define INT32_MAX 2147483647i32 +#endif + +#ifndef INT64_MAX +#define INT64_MAX 9223372036854775807i64 +#endif + +#ifndef UINT8_MAX +#define UINT8_MAX 0xffui8 +#endif + +#ifndef UINT16_MAX +#define UINT16_MAX 0xffffui16 +#endif + +#ifndef UINT32_MAX +#define UINT32_MAX 0xffffffffui32 +#endif + +#ifndef UINT64_MAX +#define UINT64_MAX 0xffffffffffffffffui64 +#endif + +#else + +// Other "compilers" and later versions of Microsoft Visual Studio C++ and +// Borland C/C++ define the types in + +#include + +#endif + +#endif diff --git a/yara-master/libyara/include/yara/lexer.h b/yara-master/libyara/include/yara/lexer.h new file mode 100644 index 0000000..2c6af19 --- /dev/null +++ b/yara-master/libyara/include/yara/lexer.h @@ -0,0 +1,149 @@ +/* +Copyright (c) 2007. Victor M. Alvarez [plusvic@gmail.com]. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + + +#undef yyparse +#undef yylex +#undef yyerror +#undef yyfatal +#undef yychar +#undef yydebug +#undef yynerrs +#undef yyget_extra +#undef yyget_lineno + +#undef YY_DECL +#undef YY_FATAL_ERROR +#undef YY_EXTRA_TYPE + +#define yyparse yara_yyparse +#define yylex yara_yylex +#define yyerror yara_yyerror +#define yyfatal yara_yyfatal +#define yywarning yara_yywarning +#define yychar yara_yychar +#define yydebug yara_yydebug +#define yynerrs yara_yynerrs +#define yyget_extra yara_yyget_extra +#define yyget_lineno yara_yyget_lineno + + +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +#ifndef YY_TYPEDEF_EXPRESSION_T +#define YY_TYPEDEF_EXPRESSION_T + + +// Expression type constants are powers of two because they are used as flags. +// For example: +// CHECK_TYPE(whatever, EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT) +// The expression above is used to ensure that the type of "whatever" is either +// integer or float. + +#define EXPRESSION_TYPE_BOOLEAN 1 +#define EXPRESSION_TYPE_INTEGER 2 +#define EXPRESSION_TYPE_STRING 4 +#define EXPRESSION_TYPE_REGEXP 8 +#define EXPRESSION_TYPE_OBJECT 16 +#define EXPRESSION_TYPE_FLOAT 32 + +typedef struct _EXPRESSION +{ + int type; + + union { + int64_t integer; + YR_OBJECT* object; + SIZED_STRING* sized_string; + } value; + + const char* identifier; + +} EXPRESSION; + +union YYSTYPE; + +#endif + + +#define YY_DECL int yylex( \ + union YYSTYPE* yylval_param, yyscan_t yyscanner, YR_COMPILER* compiler) + + +#define YY_FATAL_ERROR(msg) yara_yyfatal(yyscanner, msg) + + +#define YY_EXTRA_TYPE YR_COMPILER* +#define YY_USE_CONST + + +int yyget_lineno(yyscan_t yyscanner); + +int yylex( + union YYSTYPE* yylval_param, + yyscan_t yyscanner, + YR_COMPILER* compiler); + +int yyparse( + void *yyscanner, + YR_COMPILER* compiler); + +void yyerror( + yyscan_t yyscanner, + YR_COMPILER* compiler, + const char *error_message); + +void yywarning( + yyscan_t yyscanner, + const char *message_fmt, + ...); + +void yyfatal( + yyscan_t yyscanner, + const char *error_message); + +YY_EXTRA_TYPE yyget_extra( + yyscan_t yyscanner); + +int yr_lex_parse_rules_string( + const char* rules_string, + YR_COMPILER* compiler); + +int yr_lex_parse_rules_file( + FILE* rules_file, + YR_COMPILER* compiler); + +int yr_lex_parse_rules_fd( + YR_FILE_DESCRIPTOR rules_fd, + YR_COMPILER* compiler); diff --git a/yara-master/libyara/include/yara/libyara.h b/yara-master/libyara/include/yara/libyara.h new file mode 100644 index 0000000..2cccb3f --- /dev/null +++ b/yara-master/libyara/include/yara/libyara.h @@ -0,0 +1,91 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_LIBYARA_H +#define YR_LIBYARA_H + +#include + +#define YR_MAJOR_VERSION 3 +#define YR_MINOR_VERSION 7 +#define YR_MICRO_VERSION 0 + +#define version_str(s) _version_str(s) +#define _version_str(s) #s + +// Version as a string +#define YR_VERSION version_str(YR_MAJOR_VERSION) \ + "." version_str(YR_MINOR_VERSION) \ + "." version_str(YR_MICRO_VERSION) + +// Version as a single 4-byte hex number, e.g. 0x030401 == 3.4.1. +#define YR_VERSION_HEX ((YR_MAJOR_VERSION << 16) | \ + (YR_MINOR_VERSION << 8) | \ + (YR_MICRO_VERSION << 0)) + + +// Enumerated type listing configuration options +typedef enum _YR_CONFIG_NAME +{ + YR_CONFIG_STACK_SIZE, + YR_CONFIG_MAX_STRINGS_PER_RULE, + YR_CONFIG_MAX_MATCH_DATA, + + YR_CONFIG_LAST // End-of-enum marker, not a configuration + +} YR_CONFIG_NAME; + + +#define DEFAULT_STACK_SIZE 16384 +#define DEFAULT_MAX_STRINGS_PER_RULE 10000 +#define DEFAULT_MAX_MATCH_DATA 512 + + +YR_API int yr_initialize(void); + + +YR_API int yr_finalize(void); + + +YR_DEPRECATED_API void yr_finalize_thread(void); + + +YR_API int yr_get_tidx(void); + + +YR_API void yr_set_tidx(int); + + +YR_API int yr_set_configuration(YR_CONFIG_NAME, void*); + + +YR_API int yr_get_configuration(YR_CONFIG_NAME, void*); + + +#endif diff --git a/yara-master/libyara/include/yara/limits.h b/yara-master/libyara/include/yara/limits.h new file mode 100644 index 0000000..e8b2f42 --- /dev/null +++ b/yara-master/libyara/include/yara/limits.h @@ -0,0 +1,146 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_LIMITS_H +#define YR_LIMITS_H + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#endif + +#include "utils.h" + +#ifndef MAX_PATH +#define MAX_PATH 1024 +#endif + +// Maximum number of threads that can use a YR_RULES structure simultaneously. +// Increasing this number also increase memory usage as each YR_STRING structure +// has an array with MAX_THREADS entries for storing pointers to YR_MATCH +// structures. +#ifndef MAX_THREADS +#define MAX_THREADS 32 +#endif + +// Capacity of the buffer used for storing compiler error messages. Messages +// will be truncated at this size. +#ifndef MAX_COMPILER_ERROR_EXTRA_INFO +#define MAX_COMPILER_ERROR_EXTRA_INFO 256 +#endif + +// Maximum size for the substring (atoms) extracted from strings and regular +// expressions and put into the Aho-Corasick automaton. The maximum allows size +// for this constant is 255. +#ifndef MAX_ATOM_LENGTH +#define MAX_ATOM_LENGTH 4 +#endif + +// Maximum number of nested "for" loops in rule. Rules ith nested loops +// exceeding this number will be rejected by the compiler. +#ifndef MAX_LOOP_NESTING +#define MAX_LOOP_NESTING 4 +#endif + +#ifndef MAX_ARENA_PAGES +#define MAX_ARENA_PAGES 32 +#endif + +// Maximum number of nested included files. +#ifndef MAX_INCLUDE_DEPTH +#define MAX_INCLUDE_DEPTH 16 +#endif + +// Maximum number of matches allowed for a string. If more matches are found +// the scan will fail with ERROR_TOO_MANY_MATCHES. +#ifndef MAX_STRING_MATCHES +#define MAX_STRING_MATCHES 1000000 +#endif + +// Maximum number of argument that a function in a YARA module can have. +#ifndef MAX_FUNCTION_ARGS +#define MAX_FUNCTION_ARGS 128 +#endif + +// How many overloaded functions can share the same name in a YARA module. +#ifndef MAX_OVERLOADED_FUNCTIONS +#define MAX_OVERLOADED_FUNCTIONS 10 +#endif + +// Size of the stack used by yr_re_fast_exec. +#ifndef MAX_FAST_RE_STACK +#define MAX_FAST_RE_STACK 300 +#endif + + +// Regular expressions like /foo.{x,y}bar/ are split in two separate ones /foo/ +// and /bar/ if x is larger than STRING_CHAINING_THRESHOLD. This also applies to +// hex strings like { 01 02 03 [x-y] 004 05 06 }. +#ifndef STRING_CHAINING_THRESHOLD +#define STRING_CHAINING_THRESHOLD 200 +#endif + +// Size of the buffer used by the lexer for storing strings like include file +// paths and regular expressions. +#ifndef LEX_BUF_SIZE +#define LEX_BUF_SIZE 8192 +#endif + +// Maximum allowed split ID, also limiting the number of split instructions +// allowed in a regular expression. This number can't be increased +// over 255 without changing RE_SPLIT_ID_TYPE. +#ifndef RE_MAX_SPLIT_ID +#define RE_MAX_SPLIT_ID 128 +#endif + +// Maximum stack size for regexp evaluation +#ifndef RE_MAX_STACK +#define RE_MAX_STACK 1024 +#endif + +// Maximum code size for a compiled regexp +#ifndef RE_MAX_CODE_SIZE +#define RE_MAX_CODE_SIZE 32768 +#endif + +// Maximum input size scanned by yr_re_exec +#ifndef RE_SCAN_LIMIT +#define RE_SCAN_LIMIT 4096 +#endif + +// Maximum number of fibers +#ifndef RE_MAX_FIBERS +#define RE_MAX_FIBERS 1024 +#endif + +// Maximum number of levels in regexp's AST +#ifndef RE_MAX_AST_LEVELS +#define RE_MAX_AST_LEVELS 5000 +#endif + +#endif diff --git a/yara-master/libyara/include/yara/macho.h b/yara-master/libyara/include/yara/macho.h new file mode 100644 index 0000000..b00c359 --- /dev/null +++ b/yara-master/libyara/include/yara/macho.h @@ -0,0 +1,584 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef _MACHO_H +#define _MACHO_H + +#include + +// Mach-O file format magic constants + +#define MH_MAGIC 0xfeedface +#define MH_CIGAM 0xcefaedfe +#define MH_MAGIC_64 0xfeedfacf +#define MH_CIGAM_64 0xcffaedfe + +// Mach-O universal binary magic constants + +#define FAT_MAGIC 0xcafebabe +#define FAT_CIGAM 0xbebafeca +#define FAT_MAGIC_64 0xcafebabf +#define FAT_CIGAM_64 0xbfbafeca + +// Mach-O 64-bit masks + +#define CPU_ARCH_ABI64 0x01000000 // 64-bit ABI mask (for cputype) +#define CPU_SUBTYPE_LIB64 0x80000000 // 64-bit library mask (for cpusubtype) + +// Mach-O CPU types + +#define CPU_TYPE_MC680X0 0x00000006 // Motorola 68000 +#define CPU_TYPE_I386 0x00000007 // AMD/Intel x86 +#define CPU_TYPE_X86 0x00000007 // AMD/Intel x86 +#define CPU_TYPE_X86_64 0x01000007 // AMD/Intel x86-64 +#define CPU_TYPE_MIPS 0x00000008 // MIPS +#define CPU_TYPE_MC98000 0x0000000a // Motorola PowerPC +#define CPU_TYPE_HPPA 0x0000000b // HP PA-RISC +#define CPU_TYPE_ARM 0x0000000c // ARM +#define CPU_TYPE_ARM64 0x0100000c // ARM 64-bit +#define CPU_TYPE_MC88000 0x0000000d // Motorola 88000 +#define CPU_TYPE_SPARC 0x0000000e // SPARC +#define CPU_TYPE_I860 0x0000000f // Intel i860 +#define CPU_TYPE_ALPHA 0x00000010 // DEC Alpha +#define CPU_TYPE_POWERPC 0x00000012 // PowerPC +#define CPU_TYPE_POWERPC64 0x01000012 // PowerPC 64-bit + +// Mach-O Intel CPU sub-types + +#define CPU_SUBTYPE_INTEL_MODEL_ALL 0x00 +#define CPU_SUBTYPE_386 0x03 +#define CPU_SUBTYPE_486 0x04 +#define CPU_SUBTYPE_486SX 0x84 +#define CPU_SUBTYPE_586 0x05 +#define CPU_SUBTYPE_PENT 0x05 +#define CPU_SUBTYPE_PENTPRO 0x16 +#define CPU_SUBTYPE_PENTII_M3 0x36 +#define CPU_SUBTYPE_PENTII_M5 0x56 +#define CPU_SUBTYPE_CELERON 0x67 +#define CPU_SUBTYPE_CELERON_MOBILE 0x77 +#define CPU_SUBTYPE_PENTIUM_3 0x08 +#define CPU_SUBTYPE_PENTIUM_3_M 0x18 +#define CPU_SUBTYPE_PENTIUM_3_XEON 0x28 +#define CPU_SUBTYPE_PENTIUM_M 0x09 +#define CPU_SUBTYPE_PENTIUM_4 0x0a +#define CPU_SUBTYPE_PENTIUM_4_M 0x1a +#define CPU_SUBTYPE_ITANIUM 0x0b +#define CPU_SUBTYPE_ITANIUM_2 0x1b +#define CPU_SUBTYPE_XEON 0x0c +#define CPU_SUBTYPE_XEON_MP 0x1c + +// Mach-O ARM CPU sub-types + +#define CPU_SUBTYPE_ARM_ALL 0x00 +#define CPU_SUBTYPE_ARM_V4T 0x05 +#define CPU_SUBTYPE_ARM_V6 0x06 +#define CPU_SUBTYPE_ARM_V5 0x07 +#define CPU_SUBTYPE_ARM_V5TEJ 0x07 +#define CPU_SUBTYPE_ARM_XSCALE 0x08 +#define CPU_SUBTYPE_ARM_V7 0x09 +#define CPU_SUBTYPE_ARM_V7F 0x0a +#define CPU_SUBTYPE_ARM_V7S 0x0b +#define CPU_SUBTYPE_ARM_V7K 0x0c +#define CPU_SUBTYPE_ARM_V6M 0x0e +#define CPU_SUBTYPE_ARM_V7M 0x0f +#define CPU_SUBTYPE_ARM_V7EM 0x10 + +// Mach-O ARM 64-bit CPU sub-types + +#define CPU_SUBTYPE_ARM64_ALL 0x00 + +// Mach-O SPARC CPU sub-types + +#define CPU_SUBTYPE_SPARC_ALL 0x00 + +// Mach-O PowerPC CPU sub-types + +#define CPU_SUBTYPE_POWERPC_ALL 0x00 +#define CPU_SUBTYPE_MC980000_ALL 0x00 +#define CPU_SUBTYPE_POWERPC_601 0x01 +#define CPU_SUBTYPE_MC98601 0x01 +#define CPU_SUBTYPE_POWERPC_602 0x02 +#define CPU_SUBTYPE_POWERPC_603 0x03 +#define CPU_SUBTYPE_POWERPC_603e 0x04 +#define CPU_SUBTYPE_POWERPC_603ev 0x05 +#define CPU_SUBTYPE_POWERPC_604 0x06 +#define CPU_SUBTYPE_POWERPC_604e 0x07 +#define CPU_SUBTYPE_POWERPC_620 0x08 +#define CPU_SUBTYPE_POWERPC_750 0x09 +#define CPU_SUBTYPE_POWERPC_7400 0x0a +#define CPU_SUBTYPE_POWERPC_7450 0x0b +#define CPU_SUBTYPE_POWERPC_970 0x64 + +// Mach-O file types + +#define MH_OBJECT 0x01 // Object file +#define MH_EXECUTE 0x02 // Executable file +#define MH_FVMLIB 0x03 // Fixed VM shared library +#define MH_CORE 0x04 // Core dump file +#define MH_PRELOAD 0x05 // Preloaded executable file +#define MH_DYLIB 0x06 // Dynamic shared library +#define MH_DYLINKER 0x07 // Dynamic linker shared library +#define MH_BUNDLE 0x08 // Bundle file +#define MH_DYLIB_STUB 0x09 // Dynamic shared library stub +#define MH_DSYM 0x0a // Companion debug sections file +#define MH_KEXT_BUNDLE 0x0b // Kernel extension + +// Mach-O file flags + +#define MH_NOUNDEFS 0x00000001 +#define MH_INCRLINK 0x00000002 +#define MH_DYLDLINK 0x00000004 +#define MH_BINDATLOAD 0x00000008 +#define MH_PREBOUND 0x00000010 +#define MH_SPLIT_SEGS 0x00000020 +#define MH_LAZY_INIT 0x00000040 +#define MH_TWOLEVEL 0x00000080 +#define MH_FORCE_FLAT 0x00000100 +#define MH_NOMULTIDEFS 0x00000200 +#define MH_NOFIXPREBINDING 0x00000400 +#define MH_PREBINDABLE 0x00000800 +#define MH_ALLMODSBOUND 0x00001000 +#define MH_SUBSECTIONS_VIA_SYMBOLS 0x00002000 +#define MH_CANONICAL 0x00004000 +#define MH_WEAK_DEFINES 0x00008000 +#define MH_BINDS_TO_WEAK 0x00010000 +#define MH_ALLOW_STACK_EXECUTION 0x00020000 +#define MH_ROOT_SAFE 0x00040000 +#define MH_SETUID_SAFE 0x00080000 +#define MH_NO_REEXPORTED_DYLIBS 0x00100000 +#define MH_PIE 0x00200000 +#define MH_DEAD_STRIPPABLE_DYLIB 0x00400000 +#define MH_HAS_TLV_DESCRIPTORS 0x00800000 +#define MH_NO_HEAP_EXECUTION 0x01000000 +#define MH_APP_EXTENSION_SAFE 0x02000000 + +// Mach-O load commands + +#define LC_SEGMENT 0x00000001 +#define LC_SYMTAB 0x00000002 +#define LC_SYMSEG 0x00000003 +#define LC_THREAD 0x00000004 +#define LC_UNIXTHREAD 0x00000005 +#define LC_LOADFVMLIB 0x00000006 +#define LC_IDFVMLIB 0x00000007 +#define LC_IDENT 0x00000008 +#define LC_FVMFILE 0x00000009 +#define LC_PREPAGE 0x0000000a +#define LC_DYSYMTAB 0x0000000b +#define LC_LOAD_DYLIB 0x0000000c +#define LC_ID_DYLIB 0x0000000d +#define LC_LOAD_DYLINKER 0x0000000e +#define LC_ID_DYLINKER 0x0000000f +#define LC_PREBOUND_DYLIB 0x00000010 +#define LC_ROUTINES 0x00000011 +#define LC_SUB_FRAMEWORK 0x00000012 +#define LC_SUB_UMBRELLA 0x00000013 +#define LC_SUB_CLIENT 0x00000014 +#define LC_SUB_LIBRARY 0x00000015 +#define LC_TWOLEVEL_HINTS 0x00000016 +#define LC_PREBIND_CKSUM 0x00000017 +#define LC_LOAD_WEAK_DYLIB 0x80000018 +#define LC_SEGMENT_64 0x00000019 +#define LC_ROUTINES_64 0x0000001A +#define LC_UUID 0x0000001B +#define LC_RPATH 0x8000001C +#define LC_CODE_SIGNATURE 0x0000001D +#define LC_SEGMENT_SPLIT_INFO 0x0000001E +#define LC_REEXPORT_DYLIB 0x8000001F +#define LC_LAZY_LOAD_DYLIB 0x00000020 +#define LC_ENCRYPTION_INFO 0x00000021 +#define LC_DYLD_INFO 0x00000022 +#define LC_DYLD_INFO_ONLY 0x80000022 +#define LC_LOAD_UPWARD_DYLIB 0x80000023 +#define LC_VERSION_MIN_MACOSX 0x00000024 +#define LC_VERSION_MIN_IPHONEOS 0x00000025 +#define LC_FUNCTION_STARTS 0x00000026 +#define LC_DYLD_ENVIRONMENT 0x00000027 +#define LC_MAIN 0x80000028 +#define LC_DATA_IN_CODE 0x00000029 +#define LC_SOURCE_VERSION 0x0000002A +#define LC_DYLIB_CODE_SIGN_DRS 0x0000002B +#define LC_ENCRYPTION_INFO_64 0x0000002C +#define LC_LINKER_OPTION 0x0000002D +#define LC_LINKER_OPTIMIZATION_HINT 0x0000002E +#define LC_VERSION_MIN_TVOS 0x0000002F +#define LC_VERSION_MIN_WATCHOS 0x00000030 + +// Segment flags + +#define SG_HIGHVM 0x00000001 // Use high part of VM (stack) +#define SG_FVMLIB 0x00000002 // Allocated by a fixed VM library +#define SG_NORELOC 0x00000004 // No associated relocations +#define SG_PROTECTED_VERSION_1 0x00000008 // Segment is encryption protected + +// Section flag masks + +#define SECTION_TYPE 0x000000ff // Section type mask +#define SECTION_ATTRIBUTES 0xffffff00 // Section attributes mask + +// Section type (use SECTION_TYPE mask) + +#define S_REGULAR 0x00 +#define S_ZEROFILL 0x01 +#define S_CSTRING_LITERALS 0x02 +#define S_4BYTE_LITERALS 0x03 +#define S_8BYTE_LITERALS 0x04 +#define S_LITERAL_POINTERS 0x05 +#define S_NON_LAZY_SYMBOL_POINTERS 0x06 +#define S_LAZY_SYMBOL_POINTERS 0x07 +#define S_SYMBOL_STUBS 0x08 +#define S_MOD_INIT_FUNC_POINTERS 0x09 +#define S_MOD_TERM_FUNC_POINTERS 0x0a +#define S_COALESCED 0x0b +#define S_GB_ZEROFILL 0x0c +#define S_INTERPOSING 0x0d +#define S_16BYTE_LITERALS 0x0e +#define S_DTRACE_DOF 0x0f +#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 +#define S_THREAD_LOCAL_REGULAR 0x11 +#define S_THREAD_LOCAL_ZEROFILL 0x12 +#define S_THREAD_LOCAL_VARIABLES 0x13 +#define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14 +#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 + +// Section attributes (use SECTION_ATTRIBUTES mask) + +#define S_ATTR_PURE_INSTRUCTIONS 0x80000000 // Only pure instructions +#define S_ATTR_NO_TOC 0x40000000 // Contains coalesced symbols +#define S_ATTR_STRIP_STATIC_SYMS 0x20000000 // Can strip static symbols +#define S_ATTR_NO_DEAD_STRIP 0x10000000 // No dead stripping +#define S_ATTR_LIVE_SUPPORT 0x08000000 // Live blocks support +#define S_ATTR_SELF_MODIFYING_CODE 0x04000000 // Self modifying code +#define S_ATTR_DEBUG 0x02000000 // Debug section +#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 // Some machine instructions +#define S_ATTR_EXT_RELOC 0x00000200 // Has external relocations +#define S_ATTR_LOC_RELOC 0x00000100 // Has local relocations + +#pragma pack(push,1) + +typedef struct { + uint32_t magic; + uint32_t cputype; + uint32_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; +} mach_header_32_t; + + +typedef struct { + uint32_t magic; + uint32_t cputype; + uint32_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; + uint32_t reserved; +} mach_header_64_t; + + +typedef struct { + uint32_t cmd; + uint32_t cmdsize; +} load_command_t; + + +typedef struct { + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint32_t vmaddr; + uint32_t vmsize; + uint32_t fileoff; + uint32_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +} segment_command_32_t; + + +typedef struct { + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +} segment_command_64_t; + + +typedef struct { + char sectname[16]; + char segname[16]; + uint32_t addr; + uint32_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + uint32_t reserved1; + uint32_t reserved2; +} section_32_t; + + +typedef struct { + char sectname[16]; + char segname[16]; + uint64_t addr; + uint64_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; +} section_64_t; + + +typedef struct { + uint32_t cmd; + uint32_t cmdsize; + uint8_t uuid[16]; +} uuid_command_t; + + +typedef struct { + uint32_t cmd; + uint32_t cmdsize; + uint64_t entryoff; + uint64_t stacksize; +} entry_point_command_t; + + +typedef struct { + uint32_t cmd; + uint32_t cmdsize; + uint32_t flavor; + uint32_t count; + // cpu_thread_state +} thread_command_t; + + +typedef struct { + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ss; + uint32_t eflags; + uint32_t eip; + uint32_t cs; + uint32_t ds; + uint32_t es; + uint32_t fs; + uint32_t gs; +} x86_thread_state_t; + + +typedef struct { + uint32_t r[13]; + uint32_t sp; + uint32_t lr; + uint32_t pc; + uint32_t cpsr; +} arm_thread_state_t; + + +typedef struct { + uint32_t srr0; + uint32_t srr1; + uint32_t r[32]; + uint32_t cr; + uint32_t xer; + uint32_t lr; + uint32_t ctr; + uint32_t mq; + uint32_t vrsavead; +} ppc_thread_state_t; + + +typedef struct { + uint32_t psr; + uint32_t pc; + uint32_t npc; + uint32_t y; + uint32_t g1; + uint32_t g2; + uint32_t g3; + uint32_t g4; + uint32_t g5; + uint32_t g6; + uint32_t g7; + uint32_t o0; + uint32_t o1; + uint32_t o2; + uint32_t o3; + uint32_t o4; + uint32_t o5; + uint32_t o6; + uint32_t o7; +} sparc_thread_state_t; + + +typedef struct { + uint32_t dreg[8]; + uint32_t areg[8]; + uint16_t pad; + uint16_t sr; + uint32_t pc; +} m68k_thread_state_t; + + +typedef struct { + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t r12; + uint32_t r13; + uint32_t r14; + uint32_t r15; + uint32_t r16; + uint32_t r17; + uint32_t r18; + uint32_t r19; + uint32_t r20; + uint32_t r21; + uint32_t r22; + uint32_t r23; + uint32_t r24; + uint32_t r25; + uint32_t r26; + uint32_t r27; + uint32_t r28; + uint32_t r29; + uint32_t r30; + uint32_t r31; + uint32_t xip; + uint32_t xip_in_bd; + uint32_t nip; +} m88k_thread_state_t; + + +typedef struct { + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rsp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; + uint64_t rflags; + uint64_t cs; + uint64_t fs; + uint64_t gs; +} x86_thread_state64_t; + + +typedef struct { + uint64_t r[29]; + uint64_t fp; + uint64_t lr; + uint64_t sp; + uint64_t pc; + uint64_t cpsr; +} arm_thread_state64_t; + + +typedef struct { + uint64_t srr0; + uint64_t srr1; + uint64_t r[32]; + uint32_t cr; + uint64_t xer; + uint64_t lr; + uint64_t ctr; + uint32_t vrsave; +} ppc_thread_state64_t; + + +typedef struct { + uint32_t magic; + uint32_t nfat_arch; +} fat_header_t; + + +typedef struct { + uint32_t cputype; + uint32_t cpusubtype; + uint32_t offset; + uint32_t size; + uint32_t align; +} fat_arch_32_t; + + +typedef struct { + uint32_t cputype; + uint32_t cpusubtype; + uint64_t offset; + uint64_t size; + uint32_t align; + uint32_t reserved; +} fat_arch_64_t; + +#pragma pack(pop) + +#endif diff --git a/yara-master/libyara/include/yara/mem.h b/yara-master/libyara/include/yara/mem.h new file mode 100644 index 0000000..ff7dc3e --- /dev/null +++ b/yara-master/libyara/include/yara/mem.h @@ -0,0 +1,74 @@ +/* +Copyright (c) 2007. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_MEM_H +#define YR_MEM_H + +#include + +#ifdef DMALLOC + +#define yr_malloc malloc +#define yr_calloc calloc +#define yr_realloc realloc +#define yr_free free +#define yr_strdup strdup +#define yr_strndup strndup + +#include + +#else + +void* yr_calloc( + size_t count, + size_t size); + +void* yr_malloc( + size_t size); + +void* yr_realloc( + void* ptr, + size_t size); + +void yr_free( + void *ptr); + +char* yr_strdup( + const char *str); + +char* yr_strndup( + const char *str, size_t n); + +#endif + +int yr_heap_alloc(void); + +int yr_heap_free(void); + +#endif diff --git a/yara-master/libyara/include/yara/modules.h b/yara-master/libyara/include/yara/modules.h new file mode 100644 index 0000000..1724f00 --- /dev/null +++ b/yara-master/libyara/include/yara/modules.h @@ -0,0 +1,440 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_MODULES_H +#define YR_MODULES_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Concatenation that macro-expands its arguments. + +#define YR_CONCAT(arg1, arg2) _YR_CONCAT(arg1, arg2) // expands the arguments. +#define _YR_CONCAT(arg1, arg2) arg1 ## arg2 // do the actual concatenation. + + +#define module_declarations YR_CONCAT(MODULE_NAME, __declarations) +#define module_load YR_CONCAT(MODULE_NAME, __load) +#define module_unload YR_CONCAT(MODULE_NAME, __unload) +#define module_initialize YR_CONCAT(MODULE_NAME, __initialize) +#define module_finalize YR_CONCAT(MODULE_NAME, __finalize) + +#define begin_declarations \ + int module_declarations(YR_OBJECT* module) { \ + YR_OBJECT* stack[64]; \ + int stack_top = 0; \ + stack[stack_top] = module; + + +#define end_declarations \ + return ERROR_SUCCESS; } + + +#define begin_struct(name) { \ + YR_OBJECT* structure; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_STRUCTURE, \ + name, \ + stack[stack_top], \ + &structure)); \ + assertf( \ + stack_top < sizeof(stack)/sizeof(stack[0]) - 1, \ + "too many nested structures"); \ + stack[++stack_top] = structure; \ + } + + +#define begin_struct_array(name) { \ + YR_OBJECT* structure; \ + YR_OBJECT* array; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_ARRAY, \ + name, \ + stack[stack_top], \ + &array)); \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_STRUCTURE, \ + name, \ + array, \ + &structure)); \ + assertf( \ + stack_top < sizeof(stack)/sizeof(stack[0]) - 1, \ + "too many nested structures"); \ + stack[++stack_top] = structure; \ + } + + +#define begin_struct_dictionary(name) { \ + YR_OBJECT* structure; \ + YR_OBJECT* array; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_DICTIONARY, \ + name, \ + stack[stack_top], \ + &array)); \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_STRUCTURE, \ + name, \ + array, \ + &structure)); \ + assertf( \ + stack_top < sizeof(stack)/sizeof(stack[0]) - 1, \ + "too many nested structures"); \ + stack[++stack_top] = structure; \ + } + + +#define end_struct(name) { \ + assert(stack[stack_top]->type == OBJECT_TYPE_STRUCTURE); \ + assertf( \ + strcmp(stack[stack_top]->identifier, name) == 0, \ + "unbalanced begin_struct/end_struct"); \ + stack_top--; \ + } + + +#define end_struct_array(name) end_struct(name) + + +#define end_struct_dictionary(name) end_struct(name) + + +#define declare_integer(name) { \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_INTEGER, \ + name, \ + stack[stack_top], \ + NULL)); \ + } + + +#define declare_integer_array(name) { \ + YR_OBJECT* array; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_ARRAY, \ + name, \ + stack[stack_top], \ + &array)); \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_INTEGER, \ + name, \ + array, \ + NULL)); \ + } + + +#define declare_integer_dictionary(name) { \ + YR_OBJECT* dict; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_DICTIONARY, \ + name, \ + stack[stack_top], \ + &dict)); \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_INTEGER, \ + name, \ + dict, \ + NULL)); \ + } + + +#define declare_float(name) { \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_FLOAT, \ + name, \ + stack[stack_top], \ + NULL)); \ + } + + +#define declare_float_array(name) { \ + YR_OBJECT* array; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_ARRAY, \ + name, \ + stack[stack_top], \ + &array)); \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_FLOAT, \ + name, \ + array, \ + NULL)); \ + } + + +#define declare_float_dictionary(name) { \ + YR_OBJECT* dict; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_DICTIONARY, \ + name, \ + stack[stack_top], \ + &dict)); \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_FLOAT, \ + name, \ + dict, \ + NULL)); \ + } + + +#define declare_string(name) { \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_STRING, \ + name, \ + stack[stack_top], \ + NULL)); \ + } + + +#define declare_string_array(name) { \ + YR_OBJECT* array; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_ARRAY, \ + name, \ + stack[stack_top], \ + &array)); \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_STRING, \ + name, \ + array, \ + NULL)); \ + } + + +#define declare_string_dictionary(name) { \ + YR_OBJECT* dict; \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_DICTIONARY, \ + name, \ + stack[stack_top], \ + &dict)); \ + FAIL_ON_ERROR(yr_object_create( \ + OBJECT_TYPE_STRING, \ + name, \ + dict, \ + NULL)); \ + } + + +#define declare_function(name, args_fmt, ret_fmt, func) { \ + YR_OBJECT* function; \ + FAIL_ON_ERROR(yr_object_function_create( \ + name, \ + args_fmt, \ + ret_fmt, \ + func, \ + stack[stack_top], \ + &function)); \ + } + + +#define define_function(func) \ + int func ( \ + YR_VALUE* __args, \ + YR_SCAN_CONTEXT* __context, \ + YR_OBJECT_FUNCTION* __function_obj) + + +#define sized_string_argument(n) \ + (__args[n-1].ss) + +#define string_argument(n) \ + (sized_string_argument(n)->c_string) + +#define integer_argument(n) \ + (__args[n-1].i) + +#define float_argument(n) \ + (__args[n-1].d) + +#define regexp_argument(n) \ + ((RE*)(__args[n-1].re)) + + +#define module() yr_object_get_root((YR_OBJECT*) __function_obj) +#define parent() (__function_obj->parent) +#define scan_context() (__context) + + +#define foreach_memory_block(iterator, block) \ + for (block = iterator->first(iterator); \ + block != NULL; \ + block = iterator->next(iterator)) \ + + +#define first_memory_block(context) \ + (context)->iterator->first((context)->iterator) + + +#define is_undefined(object, ...) \ + yr_object_has_undefined_value(object, __VA_ARGS__) + + +#define get_object(object, ...) \ + yr_object_lookup(object, 0, __VA_ARGS__) + + +#define get_integer(object, ...) \ + yr_object_get_integer(object, __VA_ARGS__) + + +#define get_float(object, ...) \ + yr_object_get_float(object, __VA_ARGS__) + + +#define get_string(object, ...) \ + yr_object_get_string(object, __VA_ARGS__) + + +#define set_integer(value, object, ...) \ + yr_object_set_integer(value, object, __VA_ARGS__) + + +#define set_float(value, object, ...) \ + yr_object_set_float(value, object, __VA_ARGS__) + + +#define set_sized_string(value, len, object, ...) \ + yr_object_set_string(value, len, object, __VA_ARGS__) + + +#define set_string(value, object, ...) \ + set_sized_string(value, strlen(value), object, __VA_ARGS__) + + +#define return_integer(integer) { \ + assertf( \ + __function_obj->return_obj->type == OBJECT_TYPE_INTEGER, \ + "return type differs from function declaration"); \ + return yr_object_set_integer( \ + (integer), \ + __function_obj->return_obj, \ + NULL); \ + } + + +#define return_float(double_) { \ + double d = (double) (double_); \ + assertf( \ + __function_obj->return_obj->type == OBJECT_TYPE_FLOAT, \ + "return type differs from function declaration"); \ + return yr_object_set_float( \ + (d != (double) UNDEFINED) ? d : NAN, \ + __function_obj->return_obj, \ + NULL); \ + } + + +#define return_string(string) { \ + char* s = (char*) (string); \ + assertf( \ + __function_obj->return_obj->type == OBJECT_TYPE_STRING, \ + "return type differs from function declaration"); \ + return yr_object_set_string( \ + (s != (char*) UNDEFINED) ? s : NULL, \ + (s != (char*) UNDEFINED) ? strlen(s) : 0, \ + __function_obj->return_obj, \ + NULL); \ + } + + +typedef int (*YR_EXT_INITIALIZE_FUNC)( + YR_MODULE* module); + + +typedef int (*YR_EXT_FINALIZE_FUNC)( + YR_MODULE* module); + + +typedef int (*YR_EXT_DECLARATIONS_FUNC)( + YR_OBJECT* module_object); + + +typedef int (*YR_EXT_LOAD_FUNC)( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size); + + +typedef int (*YR_EXT_UNLOAD_FUNC)( + YR_OBJECT* module_object); + + +struct YR_MODULE +{ + char* name; + + YR_EXT_DECLARATIONS_FUNC declarations; + YR_EXT_LOAD_FUNC load; + YR_EXT_UNLOAD_FUNC unload; + YR_EXT_INITIALIZE_FUNC initialize; + YR_EXT_FINALIZE_FUNC finalize; +}; + + +struct YR_MODULE_IMPORT +{ + const char* module_name; + void* module_data; + size_t module_data_size; +}; + + +int yr_modules_initialize(void); + + +int yr_modules_finalize(void); + + +int yr_modules_do_declarations( + const char* module_name, + YR_OBJECT* main_structure); + + +int yr_modules_load( + const char* module_name, + YR_SCAN_CONTEXT* context); + + +int yr_modules_unload_all( + YR_SCAN_CONTEXT* context); + +#endif diff --git a/yara-master/libyara/include/yara/object.h b/yara-master/libyara/include/yara/object.h new file mode 100644 index 0000000..1b9236d --- /dev/null +++ b/yara-master/libyara/include/yara/object.h @@ -0,0 +1,185 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_OBJECT_H +#define YR_OBJECT_H + +#ifdef _MSC_VER + +#include +#ifndef isnan +#define isnan _isnan +#endif + +#ifndef INFINITY +#define INFINITY (DBL_MAX + DBL_MAX) +#endif + +#ifndef NAN +#define NAN (INFINITY-INFINITY) +#endif + +#endif + + +#include +#include + +#define OBJECT_CREATE 1 + +#define OBJECT_TYPE_INTEGER 1 +#define OBJECT_TYPE_STRING 2 +#define OBJECT_TYPE_STRUCTURE 3 +#define OBJECT_TYPE_ARRAY 4 +#define OBJECT_TYPE_FUNCTION 5 +#define OBJECT_TYPE_DICTIONARY 6 +#define OBJECT_TYPE_FLOAT 7 + + +int yr_object_create( + int8_t type, + const char* identifier, + YR_OBJECT* parent, + YR_OBJECT** object); + + +int yr_object_function_create( + const char* identifier, + const char* arguments_fmt, + const char* return_fmt, + YR_MODULE_FUNC func, + YR_OBJECT* parent, + YR_OBJECT** function); + + +int yr_object_from_external_variable( + YR_EXTERNAL_VARIABLE* external, + YR_OBJECT** object); + + +void yr_object_destroy( + YR_OBJECT* object); + + +int yr_object_copy( + YR_OBJECT* object, + YR_OBJECT** object_copy); + + +YR_OBJECT* yr_object_lookup_field( + YR_OBJECT* object, + const char* field_name); + + +YR_OBJECT* yr_object_lookup( + YR_OBJECT* root, + int flags, + const char* pattern, + ...); + + +int yr_object_has_undefined_value( + YR_OBJECT* object, + const char* field, + ...); + +int64_t yr_object_get_integer( + YR_OBJECT* object, + const char* field, + ...); + + +SIZED_STRING* yr_object_get_string( + YR_OBJECT* object, + const char* field, + ...); + + +int yr_object_set_integer( + int64_t value, + YR_OBJECT* object, + const char* field, + ...); + + +int yr_object_set_float( + double value, + YR_OBJECT* object, + const char* field, + ...); + + +int yr_object_set_string( + const char* value, + size_t len, + YR_OBJECT* object, + const char* field, + ...); + + +YR_OBJECT* yr_object_array_get_item( + YR_OBJECT* object, + int flags, + int index); + + +int yr_object_array_set_item( + YR_OBJECT* object, + YR_OBJECT* item, + int index); + + +YR_OBJECT* yr_object_dict_get_item( + YR_OBJECT* object, + int flags, + const char* key); + + +int yr_object_dict_set_item( + YR_OBJECT* object, + YR_OBJECT* item, + const char* key); + + +int yr_object_structure_set_member( + YR_OBJECT* object, + YR_OBJECT* member); + + +YR_OBJECT* yr_object_get_root( + YR_OBJECT* object); + + +YR_API void yr_object_print_data( + YR_OBJECT* object, + int indent, + int print_identifier); + + +#endif diff --git a/yara-master/libyara/include/yara/parser.h b/yara-master/libyara/include/yara/parser.h new file mode 100644 index 0000000..837f560 --- /dev/null +++ b/yara-master/libyara/include/yara/parser.h @@ -0,0 +1,138 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_PARSER_H +#define YR_PARSER_H + + +#include "lexer.h" + + +int yr_parser_emit( + yyscan_t yyscanner, + uint8_t instruction, + uint8_t** instruction_address); + + +int yr_parser_emit_with_arg( + yyscan_t yyscanner, + uint8_t instruction, + int64_t argument, + uint8_t** instruction_address, + int64_t** argument_address); + + +int yr_parser_emit_with_arg_double( + yyscan_t yyscanner, + uint8_t instruction, + double argument, + uint8_t** instruction_address, + double** argument_address); + + +int yr_parser_emit_with_arg_reloc( + yyscan_t yyscanner, + uint8_t instruction, + void* argument, + uint8_t** instruction_address, + void** argument_address); + + +int yr_parser_check_types( + YR_COMPILER* compiler, + YR_OBJECT_FUNCTION* function, + const char* actual_args_fmt); + + +YR_STRING* yr_parser_lookup_string( + yyscan_t yyscanner, + const char* identifier); + + +int yr_parser_lookup_loop_variable( + yyscan_t yyscanner, + const char* identifier); + + +YR_RULE* yr_parser_reduce_rule_declaration_phase_1( + yyscan_t yyscanner, + int32_t flags, + const char* identifier); + + +int yr_parser_reduce_rule_declaration_phase_2( + yyscan_t yyscanner, + YR_RULE* rule); + + +YR_STRING* yr_parser_reduce_string_declaration( + yyscan_t yyscanner, + int32_t flags, + const char* identifier, + SIZED_STRING* str); + + +YR_META* yr_parser_reduce_meta_declaration( + yyscan_t yyscanner, + int32_t type, + const char* identifier, + const char* string, + int64_t integer); + + +int yr_parser_reduce_string_identifier( + yyscan_t yyscanner, + const char* identifier, + uint8_t instruction, + uint64_t at_offset); + + +int yr_parser_emit_pushes_for_strings( + yyscan_t yyscanner, + const char* identifier); + + +int yr_parser_reduce_external( + yyscan_t yyscanner, + const char* identifier, + uint8_t instruction); + + +int yr_parser_reduce_import( + yyscan_t yyscanner, + SIZED_STRING* module_name); + + +int yr_parser_reduce_operation( + yyscan_t yyscanner, + const char* operation, + EXPRESSION left_operand, + EXPRESSION right_operand); + +#endif diff --git a/yara-master/libyara/include/yara/pe.h b/yara-master/libyara/include/yara/pe.h new file mode 100644 index 0000000..7847ba2 --- /dev/null +++ b/yara-master/libyara/include/yara/pe.h @@ -0,0 +1,511 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_PE_H +#define YR_PE_H + +#include +#include + +#pragma pack(push, 1) + +#if defined(_WIN32) || defined(__CYGWIN__) +#include + +// These definitions are not present in older Windows headers. + +#ifndef IMAGE_FILE_MACHINE_ARMNT +#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 +#endif + +#ifndef IMAGE_FILE_MACHINE_ARM64 +#define IMAGE_FILE_MACHINE_ARM64 0xaa64 +#endif + +#else + +#include + +#include + +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef int32_t LONG; +typedef uint32_t ULONG; +typedef uint64_t ULONGLONG; + + +#define FIELD_OFFSET(type, field) ((size_t)&(((type *)0)->field)) + +#ifndef _MAC + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_OS2_SIGNATURE 0x454E // NE +#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE +#define IMAGE_VXD_SIGNATURE 0x454C // LE +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 + +#else + +#define IMAGE_DOS_SIGNATURE 0x4D5A // MZ +#define IMAGE_OS2_SIGNATURE 0x4E45 // NE +#define IMAGE_OS2_SIGNATURE_LE 0x4C45 // LE +#define IMAGE_NT_SIGNATURE 0x50450000 // PE00 + +#endif + +#pragma pack(push, 2) + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + WORD e_magic; // Magic number + WORD e_cblp; // Bytes on last page of file + WORD e_cp; // Pages in file + WORD e_crlc; // Relocations + WORD e_cparhdr; // Size of header in paragraphs + WORD e_minalloc; // Minimum extra paragraphs needed + WORD e_maxalloc; // Maximum extra paragraphs needed + WORD e_ss; // Initial (relative) SS value + WORD e_sp; // Initial SP value + WORD e_csum; // Checksum + WORD e_ip; // Initial IP value + WORD e_cs; // Initial (relative) CS value + WORD e_lfarlc; // File address of relocation table + WORD e_ovno; // Overlay number + WORD e_res[4]; // Reserved words + WORD e_oemid; // OEM identifier (for e_oeminfo) + WORD e_oeminfo; // OEM information; e_oemid specific + WORD e_res2[10]; // Reserved words + LONG e_lfanew; // File address of new exe header + } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +#pragma pack(pop) + +// +// File header format. +// + +#pragma pack(push,4) + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + + + +#define IMAGE_SIZEOF_FILE_HEADER 20 + + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references). +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line numbers stripped from file. +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file. +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file. +#define IMAGE_FILE_SYSTEM 0x1000 // System File. +#define IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. + + +#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 +#define IMAGE_FILE_MACHINE_AM33 0x01d3 +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 +#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 +#define IMAGE_FILE_MACHINE_ARM64 0xaa64 +#define IMAGE_FILE_MACHINE_EBC 0x0ebc +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_M32R 0x9041 +#define IMAGE_FILE_MACHINE_MIPS16 0x0266 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 +#define IMAGE_FILE_MACHINE_POWERPC 0x01f0 +#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 +#define IMAGE_FILE_MACHINE_R4000 0x0166 +#define IMAGE_FILE_MACHINE_SH3 0x01a2 +#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 +#define IMAGE_FILE_MACHINE_SH4 0x01a6 +#define IMAGE_FILE_MACHINE_SH5 0x01a8 +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 + +// Section characteristics +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#define IMAGE_SCN_GPREL 0x00008000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +// +// Directory format. +// + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers +#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor + + +// +// Optional header format. +// + +typedef struct _IMAGE_OPTIONAL_HEADER32 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + + +typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + + +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + + +typedef struct _IMAGE_NT_HEADERS32 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; + +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + + +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; + +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; + +// IMAGE_FIRST_SECTION doesn't need 32/64 versions since the file header is +// the same either way. + +#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ + ((BYTE*)ntheader + \ + FIELD_OFFSET( IMAGE_NT_HEADERS32, OptionalHeader ) + \ + yr_le16toh(((PIMAGE_NT_HEADERS32)(ntheader))->FileHeader.SizeOfOptionalHeader) \ + )) + +// Subsystem Values + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 +#define IMAGE_SUBSYSTEM_NATIVE 1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define IMAGE_SUBSYSTEM_OS2_CUI 5 +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 +#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 +#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13 +#define IMAGE_SUBSYSTEM_XBOX 14 +#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 + +// DllCharacteristics values + +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 +#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +// +// Section header format. +// + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; + +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + + +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; + DWORD OriginalFirstThunk; + } ; + DWORD TimeDateStamp; + DWORD ForwarderChain; + DWORD Name; + DWORD FirstThunk; + +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + + +typedef struct _IMAGE_IMPORT_BY_NAME { + WORD Hint; + BYTE Name[1]; + +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +typedef struct _IMAGE_THUNK_DATA32 { + union { + DWORD ForwarderString; + DWORD Function; + DWORD Ordinal; + DWORD AddressOfData; + } u1; + +} IMAGE_THUNK_DATA32, *PIMAGE_THUNK_DATA32; + + +#define IMAGE_ORDINAL_FLAG32 0x80000000 +#define IMAGE_ORDINAL_FLAG64 0x8000000000000000L + +typedef struct _IMAGE_THUNK_DATA64 { + union { + ULONGLONG ForwarderString; + ULONGLONG Function; + ULONGLONG Ordinal; + ULONGLONG AddressOfData; + } u1; + +} IMAGE_THUNK_DATA64, *PIMAGE_THUNK_DATA64; + + +typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { + DWORD Name; + DWORD OffsetToData; +} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY; + + + typedef struct _IMAGE_RESOURCE_DATA_ENTRY { + DWORD OffsetToData; + DWORD Size; + DWORD CodePage; + DWORD Reserved; + } IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY; + + +typedef struct _IMAGE_RESOURCE_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + WORD NumberOfNamedEntries; + WORD NumberOfIdEntries; +} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; + +#pragma pack(pop) + +#endif // _WIN32 + +typedef struct _VERSION_INFO { + WORD Length; + WORD ValueLength; + WORD Type; + char Key[0]; +} VERSION_INFO, *PVERSION_INFO; + + +#define WIN_CERT_REVISION_1_0 0x0100 +#define WIN_CERT_REVISION_2_0 0x0200 + +#define WIN_CERT_TYPE_X509 0x0001 +#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 +#define WIN_CERT_TYPE_RESERVED_1 0x0003 +#define WIN_CERT_TYPE_TS_STACK_SIGNED 0x0004 + +#define WIN_CERTIFICATE_HEADER_SIZE 8 + +typedef struct _WIN_CERTIFICATE { + DWORD Length; + WORD Revision; + WORD CertificateType; + BYTE Certificate[0]; +} WIN_CERTIFICATE, *PWIN_CERTIFICATE; + + +// +// Rich signature. +// http://www.ntcore.com/files/richsign.htm +// + +#define RICH_VERSION_ID(id_version) (id_version >> 16) +#define RICH_VERSION_VERSION(id_version) (id_version & 0xFFFF) + +typedef struct _RICH_VERSION_INFO { + DWORD id_version; //tool id and version (use RICH_VERSION_ID and RICH_VERSION_VERSION macros) + DWORD times; //number of times this tool was used +} RICH_VERSION_INFO, *PRICH_VERSION_INFO; + +typedef struct _RICH_SIGNATURE { + DWORD dans; + DWORD key1; + DWORD key2; + DWORD key3; + RICH_VERSION_INFO versions[0]; +} RICH_SIGNATURE, *PRICH_SIGNATURE; + +#define RICH_DANS 0x536e6144 // "DanS" +#define RICH_RICH 0x68636952 // "Rich" + + +#pragma pack(pop) +#endif diff --git a/yara-master/libyara/include/yara/pe_utils.h b/yara-master/libyara/include/yara/pe_utils.h new file mode 100644 index 0000000..794395b --- /dev/null +++ b/yara-master/libyara/include/yara/pe_utils.h @@ -0,0 +1,108 @@ +#ifndef YR_PE_UTILS_H +#define YR_PE_UTILS_H + +#include + +#define MAX_PE_SECTIONS 96 + + +#define IS_64BITS_PE(pe) \ + (yr_le16toh(pe->header64->OptionalHeader.Magic) == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + + +#define OptionalHeader(pe,field) \ + (IS_64BITS_PE(pe) ? \ + pe->header64->OptionalHeader.field : \ + pe->header->OptionalHeader.field) + + +// +// Imports are stored in a linked list. Each node (IMPORTED_DLL) contains the +// name of the DLL and a pointer to another linked list of +// IMPORT_EXPORT_FUNCTION structures containing the details of imported +// functions. +// + +typedef struct _IMPORTED_DLL +{ + char *name; + + struct _IMPORT_EXPORT_FUNCTION *functions; + struct _IMPORTED_DLL *next; + +} IMPORTED_DLL, *PIMPORTED_DLL; + + +// +// This is used to track imported and exported functions. The "has_ordinal" +// field is only used in the case of imports as those are optional. Every export +// has an ordinal so we don't need the field there, but in the interest of +// keeping duplicate code to a minimum we use this function for both imports and +// exports. +// + +typedef struct _IMPORT_EXPORT_FUNCTION +{ + char *name; + uint8_t has_ordinal; + uint16_t ordinal; + + struct _IMPORT_EXPORT_FUNCTION *next; + +} IMPORT_EXPORT_FUNCTION, *PIMPORT_EXPORT_FUNCTION; + + +typedef struct _PE +{ + const uint8_t* data; + size_t data_size; + + union { + PIMAGE_NT_HEADERS32 header; + PIMAGE_NT_HEADERS64 header64; + }; + + YR_OBJECT* object; + IMPORTED_DLL* imported_dlls; + IMPORT_EXPORT_FUNCTION* exported_functions; + + uint32_t resources; + +} PE; + + +#define fits_in_pe(pe, pointer, size) \ + ((size_t) size <= pe->data_size && \ + (uint8_t*) (pointer) >= pe->data && \ + (uint8_t*) (pointer) <= pe->data + pe->data_size - size) + +#define struct_fits_in_pe(pe, pointer, struct_type) \ + fits_in_pe(pe, pointer, sizeof(struct_type)) + + +PIMAGE_NT_HEADERS32 pe_get_header( + const uint8_t* data, + size_t data_size); + + +PIMAGE_DATA_DIRECTORY pe_get_directory_entry( + PE* pe, + int entry); + + +int64_t pe_rva_to_offset( + PE* pe, + uint64_t rva); + + +char *ord_lookup( + char *dll, + uint16_t ord); + + +#if HAVE_LIBCRYPTO +#include +time_t ASN1_get_time_t(ASN1_TIME* time); +#endif + +#endif diff --git a/yara-master/libyara/include/yara/proc.h b/yara-master/libyara/include/yara/proc.h new file mode 100644 index 0000000..d408e70 --- /dev/null +++ b/yara-master/libyara/include/yara/proc.h @@ -0,0 +1,58 @@ +/* +Copyright (c) 2007. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_PROC_H +#define YR_PROC_H + +#include + +typedef struct _YR_PROC_ITERATOR_CTX { + const uint8_t* buffer; + size_t buffer_size; + YR_MEMORY_BLOCK current_block; + void* proc_info; +} YR_PROC_ITERATOR_CTX; + +YR_API int yr_process_open_iterator( + int pid, + YR_MEMORY_BLOCK_ITERATOR* iterator); + +YR_API int yr_process_close_iterator( + YR_MEMORY_BLOCK_ITERATOR* iterator); + +YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator); + +YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator); + +YR_API const uint8_t* yr_process_fetch_memory_block_data( + YR_MEMORY_BLOCK* block); + +#endif diff --git a/yara-master/libyara/include/yara/re.h b/yara-master/libyara/include/yara/re.h new file mode 100644 index 0000000..212f984 --- /dev/null +++ b/yara-master/libyara/include/yara/re.h @@ -0,0 +1,200 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_RE_H +#define YR_RE_H + +#include + +#include +#include +#include + +#define RE_NODE_LITERAL 1 +#define RE_NODE_MASKED_LITERAL 2 +#define RE_NODE_ANY 3 +#define RE_NODE_CONCAT 4 +#define RE_NODE_ALT 5 +#define RE_NODE_RANGE 6 +#define RE_NODE_STAR 7 +#define RE_NODE_PLUS 8 +#define RE_NODE_CLASS 9 +#define RE_NODE_WORD_CHAR 10 +#define RE_NODE_NON_WORD_CHAR 11 +#define RE_NODE_SPACE 12 +#define RE_NODE_NON_SPACE 13 +#define RE_NODE_DIGIT 14 +#define RE_NODE_NON_DIGIT 15 +#define RE_NODE_EMPTY 16 +#define RE_NODE_ANCHOR_START 17 +#define RE_NODE_ANCHOR_END 18 +#define RE_NODE_WORD_BOUNDARY 19 +#define RE_NODE_NON_WORD_BOUNDARY 20 +#define RE_NODE_RANGE_ANY 21 + + +#define RE_OPCODE_ANY 0xA0 +#define RE_OPCODE_ANY_EXCEPT_NEW_LINE 0xA1 +#define RE_OPCODE_LITERAL 0xA2 +#define RE_OPCODE_MASKED_LITERAL 0xA4 +#define RE_OPCODE_CLASS 0xA5 +#define RE_OPCODE_WORD_CHAR 0xA7 +#define RE_OPCODE_NON_WORD_CHAR 0xA8 +#define RE_OPCODE_SPACE 0xA9 +#define RE_OPCODE_NON_SPACE 0xAA +#define RE_OPCODE_DIGIT 0xAB +#define RE_OPCODE_NON_DIGIT 0xAC +#define RE_OPCODE_MATCH 0xAD + +#define RE_OPCODE_MATCH_AT_END 0xB0 +#define RE_OPCODE_MATCH_AT_START 0xB1 +#define RE_OPCODE_WORD_BOUNDARY 0xB2 +#define RE_OPCODE_NON_WORD_BOUNDARY 0xB3 +#define RE_OPCODE_REPEAT_ANY_GREEDY 0xB4 +#define RE_OPCODE_REPEAT_ANY_UNGREEDY 0xB5 + +#define RE_OPCODE_SPLIT_A 0xC0 +#define RE_OPCODE_SPLIT_B 0xC1 +#define RE_OPCODE_JUMP 0xC2 +#define RE_OPCODE_REPEAT_START_GREEDY 0xC3 +#define RE_OPCODE_REPEAT_END_GREEDY 0xC4 +#define RE_OPCODE_REPEAT_START_UNGREEDY 0xC5 +#define RE_OPCODE_REPEAT_END_UNGREEDY 0xC6 + + +#define RE_FLAGS_FAST_REGEXP 0x02 +#define RE_FLAGS_BACKWARDS 0x04 +#define RE_FLAGS_EXHAUSTIVE 0x08 +#define RE_FLAGS_WIDE 0x10 +#define RE_FLAGS_NO_CASE 0x20 +#define RE_FLAGS_SCAN 0x40 +#define RE_FLAGS_DOT_ALL 0x80 +#define RE_FLAGS_GREEDY 0x400 +#define RE_FLAGS_UNGREEDY 0x800 + + +typedef int RE_MATCH_CALLBACK_FUNC( + const uint8_t* match, + int match_length, + int flags, + void* args); + + +int yr_re_ast_create( + RE_AST** re_ast); + +void yr_re_ast_destroy( + RE_AST* re_ast); + +void yr_re_ast_print( + RE_AST* re_ast); + +SIZED_STRING* yr_re_ast_extract_literal( + RE_AST* re_ast); + + +int yr_re_ast_contains_dot_star( + RE_AST* re_ast); + + +int yr_re_ast_split_at_chaining_point( + RE_AST* re_ast, + RE_AST** result_re_ast, + RE_AST** remainder_re_ast, + int32_t* min_gap, + int32_t* max_gap); + + +int yr_re_ast_emit_code( + RE_AST* re_ast, + YR_ARENA* arena, + int backwards_code); + + +RE_NODE* yr_re_node_create( + int type, + RE_NODE* left, + RE_NODE* right); + + +void yr_re_node_destroy( + RE_NODE* node); + + +int yr_re_exec( + YR_SCAN_CONTEXT* context, + const uint8_t* code, + const uint8_t* input_data, + size_t input_forwards_size, + size_t input_backwards_size, + int flags, + RE_MATCH_CALLBACK_FUNC callback, + void* callback_args, + int* matches); + + +int yr_re_fast_exec( + YR_SCAN_CONTEXT* context, + const uint8_t* code, + const uint8_t* input_data, + size_t input_forwards_size, + size_t input_backwards_size, + int flags, + RE_MATCH_CALLBACK_FUNC callback, + void* callback_args, + int* matches); + + +int yr_re_parse( + const char* re_string, + RE_AST** re_ast, + RE_ERROR* error); + + +int yr_re_parse_hex( + const char* hex_string, + RE_AST** re_ast, + RE_ERROR* error); + + +int yr_re_compile( + const char* re_string, + int flags, + YR_ARENA* code_arena, + RE** re, + RE_ERROR* error); + + +int yr_re_match( + YR_SCAN_CONTEXT* context, + RE* re, + const char* target); + + +#endif diff --git a/yara-master/libyara/include/yara/re_lexer.h b/yara-master/libyara/include/yara/re_lexer.h new file mode 100644 index 0000000..26d8f71 --- /dev/null +++ b/yara-master/libyara/include/yara/re_lexer.h @@ -0,0 +1,108 @@ + /* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#undef yyparse +#undef yylex +#undef yyerror +#undef yyfatal +#undef yychar +#undef yydebug +#undef yynerrs +#undef yyget_extra +#undef yyget_lineno + +#undef YY_FATAL_ERROR +#undef YY_DECL +#undef LEX_ENV + + +#define yyparse re_yyparse +#define yylex re_yylex +#define yyerror re_yyerror +#define yyfatal re_yyfatal +#define yychar re_yychar +#define yydebug re_yydebug +#define yynerrs re_yynerrs +#define yyget_extra re_yyget_extra +#define yyget_lineno re_yyget_lineno + + +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +#define YY_EXTRA_TYPE RE_AST* +#define YY_USE_CONST + + +typedef struct _RE_LEX_ENVIRONMENT +{ + RE_CLASS re_class; + int last_error_code; + char last_error_message[256]; + +} RE_LEX_ENVIRONMENT; + + +#define LEX_ENV ((RE_LEX_ENVIRONMENT*) lex_env) + +#define YY_FATAL_ERROR(msg) re_yyfatal(yyscanner, msg) + +#include + +#define YY_DECL int re_yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env) + + +YY_EXTRA_TYPE yyget_extra( + yyscan_t yyscanner); + +int yylex( + YYSTYPE* yylval_param, + yyscan_t yyscanner, + RE_LEX_ENVIRONMENT* lex_env); + +int yyparse( + void *yyscanner, + RE_LEX_ENVIRONMENT *lex_env); + +void yyerror( + yyscan_t yyscanner, + RE_LEX_ENVIRONMENT* lex_env, + const char *error_message); + +void yyfatal( + yyscan_t yyscanner, + const char *error_message); + +int yr_parse_re_string( + const char* re_string, + RE_AST** re_ast, + RE_ERROR* error); diff --git a/yara-master/libyara/include/yara/rules.h b/yara-master/libyara/include/yara/rules.h new file mode 100644 index 0000000..25e60cf --- /dev/null +++ b/yara-master/libyara/include/yara/rules.h @@ -0,0 +1,168 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_RULES_H +#define YR_RULES_H + +#include +#include +#include + + +#define CALLBACK_MSG_RULE_MATCHING 1 +#define CALLBACK_MSG_RULE_NOT_MATCHING 2 +#define CALLBACK_MSG_SCAN_FINISHED 3 +#define CALLBACK_MSG_IMPORT_MODULE 4 +#define CALLBACK_MSG_MODULE_IMPORTED 5 + +#define CALLBACK_CONTINUE 0 +#define CALLBACK_ABORT 1 +#define CALLBACK_ERROR 2 + + +#define yr_rule_tags_foreach(rule, tag_name) \ + for (tag_name = rule->tags; \ + tag_name != NULL && *tag_name != '\0'; \ + tag_name += strlen(tag_name) + 1) + + +#define yr_rule_metas_foreach(rule, meta) \ + for (meta = rule->metas; !META_IS_NULL(meta); meta++) + + +#define yr_rule_strings_foreach(rule, string) \ + for (string = rule->strings; !STRING_IS_NULL(string); string++) + + +#define yr_string_matches_foreach(string, match) \ + for (match = STRING_MATCHES(string).head; match != NULL; match = match->next) + + +#define yr_rules_foreach(rules, rule) \ + for (rule = rules->rules_list_head; !RULE_IS_NULL(rule); rule++) + + + +YR_API int yr_rules_scan_mem( + YR_RULES* rules, + const uint8_t* buffer, + size_t buffer_size, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout); + + +YR_API int yr_rules_scan_file( + YR_RULES* rules, + const char* filename, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout); + + +YR_API int yr_rules_scan_fd( + YR_RULES* rules, + YR_FILE_DESCRIPTOR fd, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout); + + +YR_API int yr_rules_scan_proc( + YR_RULES* rules, + int pid, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout); + + +YR_API int yr_rules_save( + YR_RULES* rules, + const char* filename); + + +YR_API int yr_rules_save_stream( + YR_RULES* rules, + YR_STREAM* stream); + + +YR_API int yr_rules_load( + const char* filename, + YR_RULES** rules); + + +YR_API int yr_rules_load_stream( + YR_STREAM* stream, + YR_RULES** rules); + + +YR_API int yr_rules_destroy( + YR_RULES* rules); + + +YR_API int yr_rules_define_integer_variable( + YR_RULES* rules, + const char* identifier, + int64_t value); + + +YR_API int yr_rules_define_boolean_variable( + YR_RULES* rules, + const char* identifier, + int value); + + +YR_API int yr_rules_define_float_variable( + YR_RULES* rules, + const char* identifier, + double value); + + +YR_API int yr_rules_define_string_variable( + YR_RULES* rules, + const char* identifier, + const char* value); + + +YR_API void yr_rules_print_profiling_info( + YR_RULES* rules); + + +YR_API void yr_rule_disable( + YR_RULE* rule); + + +YR_API void yr_rule_enable( + YR_RULE* rule); + +#endif diff --git a/yara-master/libyara/include/yara/scan.h b/yara-master/libyara/include/yara/scan.h new file mode 100644 index 0000000..8768260 --- /dev/null +++ b/yara-master/libyara/include/yara/scan.h @@ -0,0 +1,49 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_SCAN_H +#define YR_SCAN_H + +#include + +// Bitmasks for flags. +#define SCAN_FLAGS_FAST_MODE 1 +#define SCAN_FLAGS_PROCESS_MEMORY 2 +#define SCAN_FLAGS_NO_TRYCATCH 4 + + +int yr_scan_verify_match( + YR_SCAN_CONTEXT* context, + YR_AC_MATCH* ac_match, + const uint8_t* data, + size_t data_size, + uint64_t data_base, + size_t offset); + +#endif diff --git a/yara-master/libyara/include/yara/scanner.h b/yara-master/libyara/include/yara/scanner.h new file mode 100644 index 0000000..49a5ed6 --- /dev/null +++ b/yara-master/libyara/include/yara/scanner.h @@ -0,0 +1,122 @@ +/* +Copyright (c) 2018. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_SCANNER_H +#define YR_SCANNER_H + +#include +#include + + +typedef YR_SCAN_CONTEXT YR_SCANNER; + + +YR_API int yr_scanner_create( + YR_RULES* rules, + YR_SCANNER** scanner); + + +YR_API void yr_scanner_destroy( + YR_SCANNER* scanner); + + +YR_API void yr_scanner_set_callback( + YR_SCANNER* scanner, + YR_CALLBACK_FUNC callback, + void* user_data); + + +YR_API void yr_scanner_set_timeout( + YR_SCANNER* scanner, + int timeout); + + +YR_API void yr_scanner_set_flags( + YR_SCANNER* scanner, + int flags); + + +YR_API int yr_scanner_define_integer_variable( + YR_SCANNER* scanner, + const char* identifier, + int64_t value); + + +YR_API int yr_scanner_define_boolean_variable( + YR_SCANNER* scanner, + const char* identifier, + int value); + + +YR_API int yr_scanner_define_float_variable( + YR_SCANNER* scanner, + const char* identifier, + double value); + + +YR_API int yr_scanner_define_string_variable( + YR_SCANNER* scanner, + const char* identifier, + const char* value); + + +YR_API int yr_scanner_scan_mem_blocks( + YR_SCANNER* scanner, + YR_MEMORY_BLOCK_ITERATOR* iterator); + + +YR_API int yr_scanner_scan_mem( + YR_SCANNER* scanner, + const uint8_t* buffer, + size_t buffer_size); + + +YR_API int yr_scanner_scan_file( + YR_SCANNER* scanner, + const char* filename); + + +YR_API int yr_scanner_scan_fd( + YR_SCANNER* scanner, + YR_FILE_DESCRIPTOR fd); + + +YR_API int yr_scanner_scan_proc( + YR_SCANNER* scanner, + int pid); + + +YR_API YR_RULE* yr_scanner_last_error_rule( + YR_SCANNER* scanner); + + +YR_API YR_STRING* yr_scanner_last_error_string( + YR_SCANNER* scanner); + +#endif diff --git a/yara-master/libyara/include/yara/sizedstr.h b/yara-master/libyara/include/yara/sizedstr.h new file mode 100644 index 0000000..da4b98d --- /dev/null +++ b/yara-master/libyara/include/yara/sizedstr.h @@ -0,0 +1,70 @@ +/* +Copyright (c) 2007-2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef _SIZEDSTR_H +#define _SIZEDSTR_H + +#include + +#include + +// +// This struct is used to support strings containing null chars. The length of +// the string is stored along the string data. However the string data is also +// terminated with a null char. +// + +#define SIZED_STRING_FLAGS_NO_CASE 1 +#define SIZED_STRING_FLAGS_DOT_ALL 2 + +#pragma pack(push) +#pragma pack(8) + + +typedef struct _SIZED_STRING +{ + uint32_t length; + uint32_t flags; + + char c_string[1]; + +} SIZED_STRING; + +#pragma pack(pop) + + +int sized_string_cmp( + SIZED_STRING* s1, + SIZED_STRING* s2); + + +SIZED_STRING* sized_string_dup( + SIZED_STRING* s); + +#endif diff --git a/yara-master/libyara/include/yara/stopwatch.h b/yara-master/libyara/include/yara/stopwatch.h new file mode 100644 index 0000000..59f7120 --- /dev/null +++ b/yara-master/libyara/include/yara/stopwatch.h @@ -0,0 +1,79 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_STOPWATCH_H +#define YR_STOPWATCH_H + +#include +#include + +#if defined(_WIN32) + +#include + +typedef struct _YR_STOPWATCH +{ + LARGE_INTEGER frequency; + LARGE_INTEGER start; + +} YR_STOPWATCH; + +#elif defined(__MACH__) + +#include + +typedef struct _YR_STOPWATCH +{ + mach_timebase_info_data_t timebase; + uint64_t start; + +} YR_STOPWATCH; + +#else + +typedef struct _YR_STOPWATCH +{ + struct timespec ts_start; + +} YR_STOPWATCH; + +#endif + + +// yr_stopwatch_start starts measuring time. +void yr_stopwatch_start( + YR_STOPWATCH* stopwatch); + +// yr_stopwatch_elapsed_us returns the number of microseconds elapsed +// since the last call to yr_stopwatch_start or since the last time that +// yr_stopwatch_elapsed_us was called with restart set to TRUE. +uint64_t yr_stopwatch_elapsed_us( + YR_STOPWATCH* stopwatch); + +#endif diff --git a/yara-master/libyara/include/yara/stream.h b/yara-master/libyara/include/yara/stream.h new file mode 100644 index 0000000..a84d893 --- /dev/null +++ b/yara-master/libyara/include/yara/stream.h @@ -0,0 +1,72 @@ +/* +Copyright (c) 2015. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_STREAM_H +#define YR_STREAM_H + +#include + +typedef size_t (*YR_STREAM_READ_FUNC)( + void* ptr, + size_t size, + size_t count, + void* user_data); + + +typedef size_t (*YR_STREAM_WRITE_FUNC)( + const void* ptr, + size_t size, + size_t count, + void* user_data); + + +typedef struct _YR_STREAM +{ + void* user_data; + + YR_STREAM_READ_FUNC read; + YR_STREAM_WRITE_FUNC write; + +} YR_STREAM; + + +size_t yr_stream_read( + void* ptr, + size_t size, + size_t count, + YR_STREAM* stream); + + +size_t yr_stream_write( + const void* ptr, + size_t size, + size_t count, + YR_STREAM* stream); + +#endif diff --git a/yara-master/libyara/include/yara/strutils.h b/yara-master/libyara/include/yara/strutils.h new file mode 100644 index 0000000..47bb270 --- /dev/null +++ b/yara-master/libyara/include/yara/strutils.h @@ -0,0 +1,111 @@ +/* +Copyright (c) 2007-2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_STRUTILS_H +#define YR_STRUTILS_H + +#include +#include + +#include + + +#if defined(_WIN32) || defined(__CYGWIN__) + +#if !defined(PRIu64) +#define PRIu64 "I64u" +#endif + +#if !defined(PRIx64) +#define PRIx64 "I64x" +#endif + +#if !defined(PRId64) +#define PRId64 "I64d" +#endif + +#else +#include +#endif + + +// Cygwin already has these functions. +#if defined(_WIN32) && !defined(__CYGWIN__) +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#endif + + +uint64_t xtoi( + const char* hexstr); + + +#if !HAVE_STRLCPY && !defined(strlcpy) +size_t strlcpy( + char *dst, + const char *src, + size_t size); +#endif + + +#if !HAVE_STRLCAT && !defined(strlcat) +size_t strlcat( + char *dst, + const char *src, + size_t size); +#endif + + +#if !HAVE_MEMMEM && !defined(memmem) +void* memmem( + const void *haystack, + size_t haystack_size, + const void *needle, + size_t needle_size); +#endif + + +int strnlen_w( + const char* w_str); + + +int strcmp_w( + const char* w_str, + const char* str); + + +size_t strlcpy_w( + char* dst, + const char* w_src, + size_t n); + +#endif diff --git a/yara-master/libyara/include/yara/threading.h b/yara-master/libyara/include/yara/threading.h new file mode 100644 index 0000000..d9c2fed --- /dev/null +++ b/yara-master/libyara/include/yara/threading.h @@ -0,0 +1,65 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_MUTEX_H +#define YR_MUTEX_H + + + +#if defined(_WIN32) || defined(__CYGWIN__) + +#include + +typedef DWORD YR_THREAD_ID; +typedef DWORD YR_THREAD_STORAGE_KEY; +typedef HANDLE YR_MUTEX; + +#else + +#include + +typedef pthread_t YR_THREAD_ID; +typedef pthread_key_t YR_THREAD_STORAGE_KEY; +typedef pthread_mutex_t YR_MUTEX; + +#endif + +YR_THREAD_ID yr_current_thread_id(void); + +int yr_mutex_create(YR_MUTEX*); +int yr_mutex_destroy(YR_MUTEX*); +int yr_mutex_lock(YR_MUTEX*); +int yr_mutex_unlock(YR_MUTEX*); + +int yr_thread_storage_create(YR_THREAD_STORAGE_KEY*); +int yr_thread_storage_destroy(YR_THREAD_STORAGE_KEY*); +int yr_thread_storage_set_value(YR_THREAD_STORAGE_KEY*, void*); +void* yr_thread_storage_get_value(YR_THREAD_STORAGE_KEY*); + +#endif diff --git a/yara-master/libyara/include/yara/types.h b/yara-master/libyara/include/yara/types.h new file mode 100644 index 0000000..2fd102b --- /dev/null +++ b/yara-master/libyara/include/yara/types.h @@ -0,0 +1,718 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef YR_TYPES_H +#define YR_TYPES_H + + +#include +#include +#include +#include +#include +#include +#include + + +#define DECLARE_REFERENCE(type, name) \ + union { type name; int64_t name##_; } YR_ALIGN(8) + + + +#define NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL 0x01 + + +#define STRING_GFLAGS_REFERENCED 0x01 +#define STRING_GFLAGS_HEXADECIMAL 0x02 +#define STRING_GFLAGS_NO_CASE 0x04 +#define STRING_GFLAGS_ASCII 0x08 +#define STRING_GFLAGS_WIDE 0x10 +#define STRING_GFLAGS_REGEXP 0x20 +#define STRING_GFLAGS_FAST_REGEXP 0x40 +#define STRING_GFLAGS_FULL_WORD 0x80 +#define STRING_GFLAGS_ANONYMOUS 0x100 +#define STRING_GFLAGS_SINGLE_MATCH 0x200 +#define STRING_GFLAGS_LITERAL 0x400 +#define STRING_GFLAGS_FITS_IN_ATOM 0x800 +#define STRING_GFLAGS_NULL 0x1000 +#define STRING_GFLAGS_CHAIN_PART 0x2000 +#define STRING_GFLAGS_CHAIN_TAIL 0x4000 +#define STRING_GFLAGS_FIXED_OFFSET 0x8000 +#define STRING_GFLAGS_GREEDY_REGEXP 0x10000 +#define STRING_GFLAGS_DOT_ALL 0x20000 +#define STRING_GFLAGS_DISABLED 0x40000 +#define STRING_GFLAGS_XOR 0x80000 + +#define STRING_IS_HEX(x) \ + (((x)->g_flags) & STRING_GFLAGS_HEXADECIMAL) + +#define STRING_IS_NO_CASE(x) \ + (((x)->g_flags) & STRING_GFLAGS_NO_CASE) + +#define STRING_IS_DOT_ALL(x) \ + (((x)->g_flags) & STRING_GFLAGS_DOT_ALL) + +#define STRING_IS_ASCII(x) \ + (((x)->g_flags) & STRING_GFLAGS_ASCII) + +#define STRING_IS_WIDE(x) \ + (((x)->g_flags) & STRING_GFLAGS_WIDE) + +#define STRING_IS_REGEXP(x) \ + (((x)->g_flags) & STRING_GFLAGS_REGEXP) + +#define STRING_IS_GREEDY_REGEXP(x) \ + (((x)->g_flags) & STRING_GFLAGS_GREEDY_REGEXP) + +#define STRING_IS_FULL_WORD(x) \ + (((x)->g_flags) & STRING_GFLAGS_FULL_WORD) + +#define STRING_IS_ANONYMOUS(x) \ + (((x)->g_flags) & STRING_GFLAGS_ANONYMOUS) + +#define STRING_IS_REFERENCED(x) \ + (((x)->g_flags) & STRING_GFLAGS_REFERENCED) + +#define STRING_IS_SINGLE_MATCH(x) \ + (((x)->g_flags) & STRING_GFLAGS_SINGLE_MATCH) + +#define STRING_IS_FIXED_OFFSET(x) \ + (((x)->g_flags) & STRING_GFLAGS_FIXED_OFFSET) + +#define STRING_IS_LITERAL(x) \ + (((x)->g_flags) & STRING_GFLAGS_LITERAL) + +#define STRING_IS_FAST_REGEXP(x) \ + (((x)->g_flags) & STRING_GFLAGS_FAST_REGEXP) + +#define STRING_IS_CHAIN_PART(x) \ + (((x)->g_flags) & STRING_GFLAGS_CHAIN_PART) + +#define STRING_IS_CHAIN_TAIL(x) \ + (((x)->g_flags) & STRING_GFLAGS_CHAIN_TAIL) + +#define STRING_IS_NULL(x) \ + ((x) == NULL || ((x)->g_flags) & STRING_GFLAGS_NULL) + +#define STRING_FITS_IN_ATOM(x) \ + (((x)->g_flags) & STRING_GFLAGS_FITS_IN_ATOM) + +#define STRING_IS_DISABLED(x) \ + (((x)->g_flags) & STRING_GFLAGS_DISABLED) + +#define STRING_IS_XOR(x) \ + (((x)->g_flags) & STRING_GFLAGS_XOR) + +#define STRING_FOUND(x) \ + ((x)->matches[yr_get_tidx()].tail != NULL) + +#define STRING_MATCHES(x) \ + ((x)->matches[yr_get_tidx()]) + + +#define RULE_TFLAGS_MATCH 0x01 + +#define RULE_GFLAGS_PRIVATE 0x01 +#define RULE_GFLAGS_GLOBAL 0x02 +#define RULE_GFLAGS_REQUIRE_EXECUTABLE 0x04 +#define RULE_GFLAGS_REQUIRE_FILE 0x08 +#define RULE_GFLAGS_NULL 0x1000 +#define RULE_GFLAGS_DISABLED 0x2000 + +#define RULE_IS_PRIVATE(x) \ + (((x)->g_flags) & RULE_GFLAGS_PRIVATE) + +#define RULE_IS_GLOBAL(x) \ + (((x)->g_flags) & RULE_GFLAGS_GLOBAL) + +#define RULE_IS_NULL(x) \ + (((x)->g_flags) & RULE_GFLAGS_NULL) + +#define RULE_IS_DISABLED(x) \ + (((x)->g_flags) & RULE_GFLAGS_DISABLED) + +#define RULE_MATCHES(x) \ + ((x)->t_flags[yr_get_tidx()] & RULE_TFLAGS_MATCH) + + +#define META_TYPE_NULL 0 +#define META_TYPE_INTEGER 1 +#define META_TYPE_STRING 2 +#define META_TYPE_BOOLEAN 3 + +#define META_IS_NULL(x) \ + ((x) != NULL ? (x)->type == META_TYPE_NULL : TRUE) + + +#define EXTERNAL_VARIABLE_TYPE_NULL 0 +#define EXTERNAL_VARIABLE_TYPE_FLOAT 1 +#define EXTERNAL_VARIABLE_TYPE_INTEGER 2 +#define EXTERNAL_VARIABLE_TYPE_BOOLEAN 3 +#define EXTERNAL_VARIABLE_TYPE_STRING 4 +#define EXTERNAL_VARIABLE_TYPE_MALLOC_STRING 5 + +#define EXTERNAL_VARIABLE_IS_NULL(x) \ + ((x) != NULL ? (x)->type == EXTERNAL_VARIABLE_TYPE_NULL : TRUE) + + +typedef struct RE RE; +typedef struct RE_AST RE_AST; +typedef struct RE_NODE RE_NODE; +typedef struct RE_CLASS RE_CLASS; +typedef struct RE_ERROR RE_ERROR; +typedef struct RE_FIBER RE_FIBER; +typedef struct RE_FIBER_LIST RE_FIBER_LIST; +typedef struct RE_FIBER_POOL RE_FIBER_POOL; + +typedef struct YR_AC_MATCH YR_AC_MATCH; +typedef struct YR_AC_STATE YR_AC_STATE; +typedef struct YR_AC_AUTOMATON YR_AC_AUTOMATON; +typedef struct YR_AC_MATCH_TABLE_ENTRY YR_AC_MATCH_TABLE_ENTRY; +typedef struct YR_AC_TABLES YR_AC_TABLES; + +typedef struct YR_NAMESPACE YR_NAMESPACE; +typedef struct YR_META YR_META; +typedef struct YR_MATCHES YR_MATCHES; +typedef struct YR_STRING YR_STRING; +typedef struct YR_RULE YR_RULE; +typedef struct YR_RULES YR_RULES; +typedef struct YR_EXTERNAL_VARIABLE YR_EXTERNAL_VARIABLE; +typedef struct YR_MATCH YR_MATCH; +typedef struct YR_SCAN_CONTEXT YR_SCAN_CONTEXT; + +typedef union YR_VALUE YR_VALUE; + +typedef struct YR_OBJECT YR_OBJECT; +typedef struct YR_OBJECT_STRUCTURE YR_OBJECT_STRUCTURE; +typedef struct YR_OBJECT_ARRAY YR_OBJECT_ARRAY; +typedef struct YR_OBJECT_DICTIONARY YR_OBJECT_DICTIONARY; +typedef struct YR_OBJECT_FUNCTION YR_OBJECT_FUNCTION; + +typedef struct YR_STRUCTURE_MEMBER YR_STRUCTURE_MEMBER; +typedef struct YR_ARRAY_ITEMS YR_ARRAY_ITEMS; +typedef struct YR_DICTIONARY_ITEMS YR_DICTIONARY_ITEMS; + +typedef struct YR_MODULE YR_MODULE; +typedef struct YR_MODULE_IMPORT YR_MODULE_IMPORT; + +typedef struct YR_MEMORY_BLOCK YR_MEMORY_BLOCK; +typedef struct YR_MEMORY_BLOCK_ITERATOR YR_MEMORY_BLOCK_ITERATOR; + + +#pragma pack(push) +#pragma pack(8) + + +struct YR_NAMESPACE +{ + int32_t t_flags[MAX_THREADS]; // Thread-specific flags + DECLARE_REFERENCE(char*, name); +}; + + +struct YR_META +{ + int32_t type; + YR_ALIGN(8) int64_t integer; + + DECLARE_REFERENCE(const char*, identifier); + DECLARE_REFERENCE(char*, string); +}; + + +struct YR_MATCHES +{ + int32_t count; + + DECLARE_REFERENCE(YR_MATCH*, head); + DECLARE_REFERENCE(YR_MATCH*, tail); +}; + + +struct YR_STRING +{ + int32_t g_flags; + int32_t length; + + DECLARE_REFERENCE(char*, identifier); + DECLARE_REFERENCE(uint8_t*, string); + DECLARE_REFERENCE(YR_STRING*, chained_to); + DECLARE_REFERENCE(YR_RULE*, rule); + + int32_t chain_gap_min; + int32_t chain_gap_max; + + int64_t fixed_offset; + + YR_MATCHES matches[MAX_THREADS]; + YR_MATCHES unconfirmed_matches[MAX_THREADS]; + + // Used only when PROFILING_ENABLED is defined + uint64_t time_cost; +}; + + +struct YR_RULE +{ + int32_t g_flags; // Global flags + int32_t t_flags[MAX_THREADS]; // Thread-specific flags + + DECLARE_REFERENCE(const char*, identifier); + DECLARE_REFERENCE(const char*, tags); + DECLARE_REFERENCE(YR_META*, metas); + DECLARE_REFERENCE(YR_STRING*, strings); + DECLARE_REFERENCE(YR_NAMESPACE*, ns); + + // Used only when PROFILING_ENABLED is defined + uint64_t time_cost; +}; + + +struct YR_EXTERNAL_VARIABLE +{ + int32_t type; + + YR_ALIGN(8) union { + int64_t i; + double f; + char* s; + } value; + + DECLARE_REFERENCE(char*, identifier); +}; + + +struct YR_AC_MATCH +{ + uint16_t backtrack; + + DECLARE_REFERENCE(YR_STRING*, string); + DECLARE_REFERENCE(const uint8_t*, forward_code); + DECLARE_REFERENCE(const uint8_t*, backward_code); + DECLARE_REFERENCE(YR_AC_MATCH*, next); +}; + + +struct YR_AC_MATCH_TABLE_ENTRY +{ + DECLARE_REFERENCE(YR_AC_MATCH*, match); +}; + + +typedef uint64_t YR_AC_TRANSITION; +typedef YR_AC_TRANSITION* YR_AC_TRANSITION_TABLE; +typedef YR_AC_MATCH_TABLE_ENTRY* YR_AC_MATCH_TABLE; + + +struct YR_AC_TABLES +{ + YR_AC_TRANSITION* transitions; + YR_AC_MATCH_TABLE_ENTRY* matches; +}; + + +typedef struct YARA_RULES_FILE_HEADER +{ + DECLARE_REFERENCE(YR_RULE*, rules_list_head); + DECLARE_REFERENCE(YR_EXTERNAL_VARIABLE*, externals_list_head); + DECLARE_REFERENCE(const uint8_t*, code_start); + DECLARE_REFERENCE(YR_AC_MATCH_TABLE, match_table); + DECLARE_REFERENCE(YR_AC_TRANSITION_TABLE, transition_table); + +} YARA_RULES_FILE_HEADER; + + +typedef struct _YR_INIT_RULE_ARGS +{ + DECLARE_REFERENCE(YR_RULE*, rule); + DECLARE_REFERENCE(const uint8_t*, jmp_addr); + +} YR_INIT_RULE_ARGS; + + +#pragma pack(pop) + + +// +// Structs defined below are never stored in the compiled rules file +// + +struct RE_NODE +{ + int type; + + union { + int value; + int count; + int start; + }; + + union { + int mask; + int end; + }; + + int greedy; + + RE_CLASS* re_class; + + RE_NODE* left; + RE_NODE* right; + + uint8_t* forward_code; + uint8_t* backward_code; +}; + + +struct RE_CLASS +{ + uint8_t negated; + uint8_t bitmap[32]; +}; + + +struct RE_AST +{ + uint32_t flags; + uint16_t levels; + RE_NODE* root_node; +}; + + +// Disable warning due to zero length array in Microsoft's compiler + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4200) +#endif + +struct RE +{ + uint32_t flags; + uint8_t code[0]; +}; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +struct RE_ERROR +{ + char message[384]; +}; + + +struct RE_FIBER +{ + const uint8_t* ip; // instruction pointer + int32_t sp; // stack pointer + int32_t rc; // repeat counter + + uint16_t stack[RE_MAX_STACK]; + + RE_FIBER* prev; + RE_FIBER* next; +}; + + +struct RE_FIBER_LIST +{ + RE_FIBER* head; + RE_FIBER* tail; +}; + + +struct RE_FIBER_POOL +{ + int fiber_count; + RE_FIBER_LIST fibers; +}; + + +struct YR_MATCH +{ + int64_t base; // Base address for the match + int64_t offset; // Offset relative to base for the match + int32_t match_length; // Match length + int32_t data_length; + + // Pointer to a buffer containing a portion of the matched data. The size of + // the buffer is data_length. data_length is always <= length and is limited + // to MAX_MATCH_DATA bytes. + + const uint8_t* data; + + // If the match belongs to a chained string chain_length contains the + // length of the chain. This field is used only in unconfirmed matches. + + int32_t chain_length; + + YR_MATCH* prev; + YR_MATCH* next; +}; + + +struct YR_AC_STATE +{ + uint8_t depth; + uint8_t input; + + uint32_t t_table_slot; + + YR_AC_STATE* failure; + YR_AC_STATE* first_child; + YR_AC_STATE* siblings; + YR_AC_MATCH* matches; +}; + + +struct YR_AC_AUTOMATON +{ + // Both m_table and t_table have the same number of elements, which is + // stored in tables_size. + + uint32_t tables_size; + uint32_t t_table_unused_candidate; + + YR_AC_TRANSITION_TABLE t_table; + YR_AC_MATCH_TABLE m_table; + YR_AC_STATE* root; +}; + + +struct YR_RULES +{ + unsigned char tidx_mask[YR_BITARRAY_NCHARS(MAX_THREADS)]; + const uint8_t* code_start; + + YR_MUTEX mutex; + YR_ARENA* arena; + YR_RULE* rules_list_head; + YR_EXTERNAL_VARIABLE* externals_list_head; + YR_AC_TRANSITION_TABLE transition_table; + YR_AC_MATCH_TABLE match_table; + + // Used only when PROFILING_ENABLED is defined + uint64_t time_cost; +}; + + +typedef const uint8_t* (*YR_MEMORY_BLOCK_FETCH_DATA_FUNC)( + YR_MEMORY_BLOCK* self); + + +typedef YR_MEMORY_BLOCK* (*YR_MEMORY_BLOCK_ITERATOR_FUNC)( + YR_MEMORY_BLOCK_ITERATOR* self); + + +struct YR_MEMORY_BLOCK +{ + size_t size; + uint64_t base; + + void* context; + + YR_MEMORY_BLOCK_FETCH_DATA_FUNC fetch_data; +}; + + +struct YR_MEMORY_BLOCK_ITERATOR +{ + void* context; + + YR_MEMORY_BLOCK_ITERATOR_FUNC first; + YR_MEMORY_BLOCK_ITERATOR_FUNC next; +}; + + +typedef int (*YR_CALLBACK_FUNC)( + int message, + void* message_data, + void* user_data); + + +struct YR_SCAN_CONTEXT +{ + // File size of the file being scanned. + uint64_t file_size; + + // Entry point of the file being scanned, if the file is PE or ELF. + uint64_t entry_point; + + // Scanning flags. + int flags; + + // Thread index for the thread using this scan context. The number of threads + // that can use a YR_RULES object simultaneusly is limited by the MAX_THREADS + // constant. Each thread using a YR_RULES get assigned a unique thread index + // in the range [0, MAX_THREADS) + int tidx; + + // Scan timeout in nanoseconds. + uint64_t timeout; + + // Pointer to user-provided data passed to the callback function. + void* user_data; + + // Pointer to the user-provided callback function that is called when an + // event occurs during the scan (a rule matching, a module being loaded, etc) + YR_CALLBACK_FUNC callback; + + // Pointer to the YR_RULES object associated to this scan context. + YR_RULES* rules; + + // Pointer to the YR_STRING causing the most recent scan error. + YR_STRING* last_error_string; + + // Pointer to the iterator used for scanning + YR_MEMORY_BLOCK_ITERATOR* iterator; + + // Pointer to a table mapping identifiers to YR_OBJECT structures. This table + // contains entries for external variables and modules. + YR_HASH_TABLE* objects_table; + + // Arena used for storing YR_MATCH structures asociated to the matches found. + YR_ARENA* matches_arena; + + // Arena used for storing pointers to the YR_STRING struct for each matching + // string. The pointers are used by _yr_scanner_clean_matches. + YR_ARENA* matching_strings_arena; + + // Stopwatch used for measuring the time elapsed during the scan. + YR_STOPWATCH stopwatch; + + // Fiber pool used by yr_re_exec. + RE_FIBER_POOL re_fiber_pool; +}; + + +union YR_VALUE +{ + int64_t i; + double d; + void* p; + YR_OBJECT* o; + YR_STRING* s; + SIZED_STRING* ss; + RE* re; +}; + + +#define OBJECT_COMMON_FIELDS \ + int8_t type; \ + const char* identifier; \ + YR_OBJECT* parent; \ + void* data; + + +struct YR_OBJECT +{ + OBJECT_COMMON_FIELDS + YR_VALUE value; +}; + + +struct YR_OBJECT_STRUCTURE +{ + OBJECT_COMMON_FIELDS + YR_STRUCTURE_MEMBER* members; +}; + + +struct YR_OBJECT_ARRAY +{ + OBJECT_COMMON_FIELDS + YR_OBJECT* prototype_item; + YR_ARRAY_ITEMS* items; +}; + + +struct YR_OBJECT_DICTIONARY +{ + OBJECT_COMMON_FIELDS + YR_OBJECT* prototype_item; + YR_DICTIONARY_ITEMS* items; +}; + + +typedef int (*YR_MODULE_FUNC)( + YR_VALUE* args, + YR_SCAN_CONTEXT* context, + YR_OBJECT_FUNCTION* function_obj); + + +struct YR_OBJECT_FUNCTION +{ + OBJECT_COMMON_FIELDS + YR_OBJECT* return_obj; + + struct + { + const char* arguments_fmt; + YR_MODULE_FUNC code; + } prototypes[MAX_OVERLOADED_FUNCTIONS]; +}; + + +#define object_as_structure(obj) ((YR_OBJECT_STRUCTURE*) (obj)) +#define object_as_array(obj) ((YR_OBJECT_ARRAY*) (obj)) +#define object_as_dictionary(obj) ((YR_OBJECT_DICTIONARY*) (obj)) +#define object_as_function(obj) ((YR_OBJECT_FUNCTION*) (obj)) + + +struct YR_STRUCTURE_MEMBER +{ + YR_OBJECT* object; + YR_STRUCTURE_MEMBER* next; +}; + + +struct YR_ARRAY_ITEMS +{ + int count; + YR_OBJECT* objects[1]; +}; + + +struct YR_DICTIONARY_ITEMS +{ + int used; + int free; + + struct { + + char* key; + YR_OBJECT* obj; + + } objects[1]; +}; + + +#endif diff --git a/yara-master/libyara/include/yara/utils.h b/yara-master/libyara/include/yara/utils.h new file mode 100644 index 0000000..2869736 --- /dev/null +++ b/yara-master/libyara/include/yara/utils.h @@ -0,0 +1,123 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + + +#ifndef YR_UTILS_H +#define YR_UTILS_H + +#include + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#if _WIN32 || __CYGWIN__ +#define PRIu64 "I64d" +#else +#include +#endif + +#ifdef __cplusplus +#define EXTERNC extern "C" +#else +#define EXTERNC +#endif + +#if defined(__GNUC__) +#define YR_API EXTERNC __attribute__((visibility("default"))) +#elif defined(_MSC_VER) +#define YR_API EXTERNC __declspec(dllexport) +#else +#define YR_API EXTERNC +#endif + +#if defined(__GNUC__) +#define YR_DEPRECATED_API EXTERNC __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define YR_DEPRECATED_API EXTERNC __declspec(deprecated) +#else +#define YR_DEPRECATED_API EXTERNC +#endif + +#if defined(__GNUC__) +#define YR_ALIGN(n) __attribute__((aligned(n))) +#elif defined(_MSC_VER) +#define YR_ALIGN(n) __declspec(align(n)) +#else +#define YR_ALIGN(n) +#endif + +#define yr_min(x, y) ((x < y) ? (x) : (y)) +#define yr_max(x, y) ((x > y) ? (x) : (y)) + +#define yr_swap(x, y, T) do { T temp = x; x = y; y = temp; } while (0) + +#ifdef NDEBUG + +#define assertf(expr, msg, ...) ((void)0) + +#else + +#include + +#define assertf(expr, msg, ...) \ + if(!(expr)) { \ + fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ + abort(); \ + } + +#endif + +// Set, unset, and test bits in an array of unsigned characters by integer +// index. The underlying array must be of type char or unsigned char to +// ensure compatibility with the CHAR_BIT constant used in these definitions. + +#define YR_BITARRAY_SET(uchar_array_base, bitnum) \ + (((uchar_array_base)[(bitnum)/CHAR_BIT]) = \ + ((uchar_array_base)[(bitnum)/CHAR_BIT] | (1 << ((bitnum) % CHAR_BIT)))) + +#define YR_BITARRAY_UNSET(uchar_array_base, bitnum) \ + (((uchar_array_base)[(bitnum)/CHAR_BIT]) = \ + ((uchar_array_base)[(bitnum)/CHAR_BIT] & (~(1 << ((bitnum) % CHAR_BIT))))) + +#define YR_BITARRAY_TEST(uchar_array_base, bitnum) \ + (((uchar_array_base)[(bitnum)/CHAR_BIT] & (1 << ((bitnum) % CHAR_BIT))) != 0) + +#define YR_BITARRAY_NCHARS(bitnum) \ + (((bitnum)+(CHAR_BIT-1))/CHAR_BIT) + +#endif diff --git a/yara-master/libyara/lexer.c b/yara-master/libyara/lexer.c new file mode 100644 index 0000000..2c009c7 --- /dev/null +++ b/yara-master/libyara/lexer.c @@ -0,0 +1,3558 @@ +#line 1 "lexer.c" + +#line 3 "lexer.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define yara_yy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer yara_yy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define yara_yy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer yara_yy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define yara_yy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer yara_yy_scan_buffer +#endif + +#ifdef yy_scan_string +#define yara_yy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string yara_yy_scan_string +#endif + +#ifdef yy_scan_bytes +#define yara_yy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes yara_yy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define yara_yy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer yara_yy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define yara_yy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer yara_yy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define yara_yy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state yara_yy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define yara_yy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer yara_yy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define yara_yypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state yara_yypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define yara_yypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state yara_yypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define yara_yyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack yara_yyensure_buffer_stack +#endif + +#ifdef yylex +#define yara_yylex_ALREADY_DEFINED +#else +#define yylex yara_yylex +#endif + +#ifdef yyrestart +#define yara_yyrestart_ALREADY_DEFINED +#else +#define yyrestart yara_yyrestart +#endif + +#ifdef yylex_init +#define yara_yylex_init_ALREADY_DEFINED +#else +#define yylex_init yara_yylex_init +#endif + +#ifdef yylex_init_extra +#define yara_yylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra yara_yylex_init_extra +#endif + +#ifdef yylex_destroy +#define yara_yylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy yara_yylex_destroy +#endif + +#ifdef yyget_debug +#define yara_yyget_debug_ALREADY_DEFINED +#else +#define yyget_debug yara_yyget_debug +#endif + +#ifdef yyset_debug +#define yara_yyset_debug_ALREADY_DEFINED +#else +#define yyset_debug yara_yyset_debug +#endif + +#ifdef yyget_extra +#define yara_yyget_extra_ALREADY_DEFINED +#else +#define yyget_extra yara_yyget_extra +#endif + +#ifdef yyset_extra +#define yara_yyset_extra_ALREADY_DEFINED +#else +#define yyset_extra yara_yyset_extra +#endif + +#ifdef yyget_in +#define yara_yyget_in_ALREADY_DEFINED +#else +#define yyget_in yara_yyget_in +#endif + +#ifdef yyset_in +#define yara_yyset_in_ALREADY_DEFINED +#else +#define yyset_in yara_yyset_in +#endif + +#ifdef yyget_out +#define yara_yyget_out_ALREADY_DEFINED +#else +#define yyget_out yara_yyget_out +#endif + +#ifdef yyset_out +#define yara_yyset_out_ALREADY_DEFINED +#else +#define yyset_out yara_yyset_out +#endif + +#ifdef yyget_leng +#define yara_yyget_leng_ALREADY_DEFINED +#else +#define yyget_leng yara_yyget_leng +#endif + +#ifdef yyget_text +#define yara_yyget_text_ALREADY_DEFINED +#else +#define yyget_text yara_yyget_text +#endif + +#ifdef yyget_lineno +#define yara_yyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno yara_yyget_lineno +#endif + +#ifdef yyset_lineno +#define yara_yyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno yara_yyset_lineno +#endif + +#ifdef yyget_column +#define yara_yyget_column_ALREADY_DEFINED +#else +#define yyget_column yara_yyget_column +#endif + +#ifdef yyset_column +#define yara_yyset_column_ALREADY_DEFINED +#else +#define yyset_column yara_yyset_column +#endif + +#ifdef yywrap +#define yara_yywrap_ALREADY_DEFINED +#else +#define yywrap yara_yywrap +#endif + +#ifdef yyget_lval +#define yara_yyget_lval_ALREADY_DEFINED +#else +#define yyget_lval yara_yyget_lval +#endif + +#ifdef yyset_lval +#define yara_yyset_lval_ALREADY_DEFINED +#else +#define yyset_lval yara_yyset_lval +#endif + +#ifdef yyalloc +#define yara_yyalloc_ALREADY_DEFINED +#else +#define yyalloc yara_yyalloc +#endif + +#ifdef yyrealloc +#define yara_yyrealloc_ALREADY_DEFINED +#else +#define yyrealloc yara_yyrealloc +#endif + +#ifdef yyfree +#define yara_yyfree_ALREADY_DEFINED +#else +#define yyfree yara_yyfree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yara_yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 75 +#define YY_END_OF_BUFFER 76 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[248] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 76, 74, 73, 73, 49, 70, 47, 46, 74, 71, + 52, 52, 2, 74, 3, 48, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 74, 62, 63, 56, 75, 68, 69, + 65, 75, 43, 44, 40, 40, 49, 7, 47, 45, + 46, 1, 38, 41, 0, 52, 0, 0, 0, 0, + 8, 4, 6, 5, 9, 48, 51, 51, 51, 51, + 26, 51, 51, 51, 51, 51, 51, 51, 51, 27, + 51, 51, 51, 28, 25, 51, 51, 51, 51, 51, + + 51, 51, 51, 0, 0, 62, 64, 59, 60, 58, + 57, 64, 68, 65, 65, 67, 66, 43, 39, 41, + 53, 52, 55, 54, 31, 24, 32, 51, 51, 51, + 51, 51, 30, 51, 51, 51, 51, 51, 51, 51, + 51, 23, 51, 51, 51, 51, 51, 51, 51, 17, + 72, 0, 0, 0, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 50, 51, 13, 51, + 51, 12, 51, 29, 21, 16, 0, 0, 0, 0, + 0, 72, 61, 15, 51, 51, 51, 22, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 0, 0, + + 51, 51, 51, 51, 51, 11, 37, 51, 50, 51, + 19, 51, 51, 0, 0, 0, 0, 0, 72, 51, + 51, 51, 51, 51, 51, 35, 10, 14, 0, 72, + 0, 0, 0, 51, 36, 51, 34, 18, 0, 0, + 0, 0, 20, 51, 42, 33, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 6, 7, 8, 1, 1, 1, 9, + 9, 10, 1, 1, 9, 11, 12, 13, 14, 15, + 16, 17, 17, 18, 17, 19, 20, 1, 1, 21, + 22, 23, 9, 24, 25, 26, 25, 25, 25, 25, + 27, 27, 27, 27, 28, 27, 29, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 9, 30, 9, 1, 31, 1, 32, 33, 34, 35, + + 36, 37, 38, 39, 40, 27, 27, 41, 42, 43, + 44, 45, 27, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 9, 56, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[57] = + { 0, + 1, 2, 3, 2, 1, 4, 1, 1, 2, 5, + 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 1, 9, 1, 1, 10, 10, 11, 12, 12, 13, + 11, 10, 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 11, 12, 11, 11, 11, 11, 11, 11, + 11, 12, 11, 11, 1, 1 + } ; + +static const flex_int16_t yy_base[270] = + { 0, + 0, 0, 54, 55, 56, 59, 587, 586, 581, 579, + 560, 594, 594, 594, 535, 594, 0, 535, 522, 53, + 53, 59, 45, 497, 50, 0, 0, 51, 467, 464, + 51, 442, 32, 44, 438, 32, 432, 426, 426, 62, + 433, 427, 418, 447, 0, 594, 594, 84, 0, 594, + 62, 446, 0, 594, 594, 445, 433, 594, 0, 594, + 440, 594, 594, 0, 102, 0, 422, 421, 124, 0, + 594, 594, 594, 594, 594, 0, 0, 401, 71, 348, + 0, 338, 332, 338, 337, 331, 335, 331, 329, 45, + 325, 324, 62, 0, 0, 331, 329, 323, 332, 318, + + 323, 330, 312, 92, 113, 0, 594, 594, 594, 594, + 594, 0, 0, 310, 594, 594, 594, 0, 594, 0, + 136, 594, 144, 0, 0, 0, 0, 316, 78, 309, + 307, 315, 0, 309, 316, 304, 297, 114, 301, 302, + 301, 0, 282, 235, 230, 227, 232, 219, 230, 0, + 594, 255, 161, 0, 224, 223, 230, 208, 224, 212, + 207, 225, 210, 206, 236, 232, 213, 206, 0, 197, + 211, 0, 197, 0, 0, 0, 229, 226, 216, 0, + 119, 0, 594, 0, 189, 187, 181, 0, 184, 179, + 181, 173, 181, 179, 178, 177, 164, 173, 272, 133, + + 170, 166, 164, 153, 160, 0, 0, 169, 0, 157, + 0, 167, 155, 0, 0, 327, 188, 134, 0, 148, + 144, 143, 136, 136, 145, 0, 0, 0, 156, 125, + 157, 122, 172, 69, 0, 64, 0, 0, 183, 178, + 0, 189, 0, 29, 594, 0, 594, 383, 396, 409, + 422, 428, 433, 441, 448, 453, 458, 469, 479, 491, + 504, 516, 529, 542, 548, 551, 561, 574, 580 + } ; + +static const flex_int16_t yy_def[270] = + { 0, + 247, 1, 248, 248, 249, 249, 250, 250, 251, 251, + 247, 247, 247, 247, 252, 247, 253, 254, 247, 247, + 255, 255, 247, 247, 247, 256, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 258, 259, 247, 247, 260, 261, 247, + 247, 262, 263, 247, 247, 247, 252, 247, 253, 247, + 254, 247, 247, 264, 247, 22, 247, 247, 247, 265, + 247, 247, 247, 247, 247, 256, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + + 257, 257, 257, 258, 247, 259, 247, 247, 247, 247, + 247, 266, 261, 247, 247, 247, 247, 263, 247, 264, + 247, 247, 247, 265, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 247, 267, 268, 269, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 267, 247, 268, 179, + 179, 179, 247, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 247, 179, + + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 199, 199, 267, 179, 199, 199, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 267, 267, + 179, 199, 199, 257, 257, 257, 257, 257, 247, 267, + 199, 199, 257, 257, 247, 257, 0, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247 + } ; + +static const flex_int16_t yy_nxt[651] = + { 0, + 12, 13, 14, 13, 15, 16, 17, 18, 12, 12, + 19, 20, 21, 22, 22, 22, 22, 22, 22, 22, + 23, 24, 25, 26, 27, 27, 27, 27, 27, 12, + 27, 28, 27, 29, 27, 30, 31, 32, 27, 33, + 27, 34, 35, 36, 37, 38, 39, 40, 41, 27, + 42, 43, 27, 27, 44, 12, 46, 46, 50, 47, + 47, 50, 63, 65, 64, 71, 72, 51, 94, 65, + 51, 74, 75, 89, 90, 91, 246, 95, 137, 92, + 67, 68, 84, 48, 48, 52, 67, 68, 52, 108, + 85, 78, 138, 79, 86, 141, 69, 80, 81, 87, + + 99, 114, 247, 105, 70, 126, 244, 100, 115, 142, + 247, 243, 156, 109, 121, 121, 121, 121, 121, 121, + 121, 121, 152, 127, 153, 157, 110, 165, 199, 166, + 200, 111, 167, 242, 178, 112, 123, 123, 123, 123, + 123, 123, 199, 232, 200, 233, 239, 151, 121, 121, + 121, 121, 121, 121, 121, 121, 123, 123, 123, 123, + 123, 123, 180, 104, 180, 240, 199, 241, 200, 180, + 238, 237, 181, 180, 180, 180, 180, 180, 180, 180, + 180, 232, 236, 233, 239, 180, 180, 178, 245, 216, + 235, 234, 180, 180, 180, 180, 180, 180, 232, 231, + + 233, 228, 227, 226, 225, 224, 223, 222, 221, 220, + 213, 212, 211, 210, 209, 208, 182, 180, 104, 180, + 207, 206, 205, 204, 180, 203, 202, 181, 180, 180, + 180, 180, 180, 180, 180, 180, 201, 104, 178, 198, + 180, 180, 197, 196, 195, 194, 167, 180, 180, 180, + 180, 180, 180, 167, 193, 192, 191, 190, 189, 188, + 187, 186, 185, 184, 178, 176, 138, 175, 174, 173, + 172, 182, 214, 215, 216, 215, 214, 214, 214, 214, + 215, 217, 214, 218, 215, 215, 215, 215, 215, 215, + 215, 215, 214, 214, 214, 214, 215, 215, 214, 214, + + 214, 214, 214, 215, 215, 215, 215, 215, 215, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 219, 216, 216, + 216, 171, 170, 169, 168, 216, 178, 164, 229, 216, + 216, 216, 216, 216, 216, 216, 216, 163, 162, 161, + 160, 216, 216, 159, 158, 155, 115, 150, 216, 216, + 216, 216, 216, 216, 149, 148, 147, 146, 145, 144, + 143, 140, 139, 136, 135, 134, 133, 132, 131, 130, + 129, 128, 230, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 49, 49, 49, 49, + + 49, 49, 49, 49, 49, 49, 49, 49, 49, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 57, 57, 57, 57, 57, + 59, 125, 59, 59, 59, 61, 122, 122, 61, 60, + 61, 61, 61, 66, 247, 66, 119, 117, 105, 66, + 76, 103, 76, 76, 76, 77, 102, 77, 77, 77, + 104, 104, 101, 98, 97, 104, 104, 96, 104, 106, + 106, 93, 88, 106, 106, 106, 106, 106, 106, 106, + 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, + + 107, 107, 107, 107, 113, 113, 83, 113, 113, 113, + 82, 113, 113, 113, 113, 113, 116, 116, 73, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 118, + 118, 118, 62, 118, 118, 118, 118, 118, 118, 118, + 118, 118, 120, 120, 60, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 120, 124, 58, 124, 154, 247, + 154, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 179, 179, 179, 179, 179, 179, + 179, 179, 179, 179, 179, 179, 179, 183, 56, 183, + 56, 54, 54, 11, 247, 247, 247, 247, 247, 247, + + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247 + } ; + +static const flex_int16_t yy_chk[651] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 4, 5, 3, + 4, 6, 20, 21, 20, 23, 23, 5, 36, 22, + 6, 25, 25, 33, 33, 34, 244, 36, 90, 34, + 21, 21, 31, 3, 4, 5, 22, 22, 6, 48, + 31, 28, 90, 28, 31, 93, 21, 28, 28, 31, + + 40, 51, 22, 104, 21, 79, 236, 40, 51, 93, + 22, 234, 129, 48, 65, 65, 65, 65, 65, 65, + 65, 65, 105, 79, 105, 129, 48, 138, 181, 138, + 181, 48, 138, 232, 230, 48, 69, 69, 69, 69, + 69, 69, 200, 218, 200, 218, 225, 104, 121, 121, + 121, 121, 121, 121, 121, 121, 123, 123, 123, 123, + 123, 123, 153, 153, 153, 229, 231, 229, 231, 153, + 224, 223, 153, 153, 153, 153, 153, 153, 153, 153, + 153, 233, 222, 233, 239, 153, 153, 240, 239, 240, + 221, 220, 153, 153, 153, 153, 153, 153, 242, 217, + + 242, 213, 212, 210, 208, 205, 204, 203, 202, 201, + 198, 197, 196, 195, 194, 193, 153, 179, 179, 179, + 192, 191, 190, 189, 179, 187, 186, 179, 179, 179, + 179, 179, 179, 179, 179, 179, 185, 178, 177, 173, + 179, 179, 171, 170, 168, 167, 166, 179, 179, 179, + 179, 179, 179, 165, 164, 163, 162, 161, 160, 159, + 158, 157, 156, 155, 152, 149, 148, 147, 146, 145, + 144, 179, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 216, 216, + 216, 143, 141, 140, 139, 216, 216, 137, 216, 216, + 216, 216, 216, 216, 216, 216, 216, 136, 135, 134, + 132, 216, 216, 131, 130, 128, 114, 103, 216, 216, + 216, 216, 216, 216, 102, 101, 100, 99, 98, 97, + 96, 92, 91, 89, 88, 87, 86, 85, 84, 83, + 82, 80, 216, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, + + 249, 249, 249, 249, 249, 249, 249, 249, 249, 250, + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, + 250, 250, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 252, 252, 252, 252, 252, + 253, 78, 253, 253, 253, 254, 68, 67, 254, 61, + 254, 254, 254, 255, 57, 255, 56, 52, 44, 255, + 256, 43, 256, 256, 256, 257, 42, 257, 257, 257, + 258, 258, 41, 39, 38, 258, 258, 37, 258, 259, + 259, 35, 32, 259, 259, 259, 259, 259, 259, 259, + 259, 260, 260, 260, 260, 260, 260, 260, 260, 260, + + 260, 260, 260, 260, 261, 261, 30, 261, 261, 261, + 29, 261, 261, 261, 261, 261, 262, 262, 24, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 263, + 263, 263, 19, 263, 263, 263, 263, 263, 263, 263, + 263, 263, 264, 264, 18, 264, 264, 264, 264, 264, + 264, 264, 264, 264, 264, 265, 15, 265, 266, 11, + 266, 267, 267, 267, 267, 267, 267, 267, 267, 267, + 267, 267, 267, 267, 268, 268, 268, 268, 268, 268, + 268, 268, 268, 268, 268, 268, 268, 269, 10, 269, + 9, 8, 7, 247, 247, 247, 247, 247, 247, 247, + + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247 + } ; + +/* Table of booleans, true if rule could match eol. */ +static const flex_int32_t yy_rule_can_match_eol[76] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "lexer.l" +/* +Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ +/* Lexical analyzer for YARA */ +#line 33 "lexer.l" + +/* Disable warnings for unused functions in this file. + +As we redefine YY_FATAL_ERROR macro to use our own function yara_yyfatal, the +yy_fatal_error function generated by Flex is not actually used, causing a +compiler warning. Flex doesn't offer any options to remove the yy_fatal_error +function. When they include something like %option noyy_fatal_error as they do +with noyywrap then we can remove this pragma. +*/ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#define strtoll _strtoi64 +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "grammar.h" + +#define error(error_code) \ + { \ + compiler->last_result = error_code; \ + yyerror(yyscanner, compiler, NULL); \ + yyterminate(); \ + } + +#define syntax_error(error_msg) \ + { \ + yr_compiler_set_error_extra_info(compiler, error_msg); \ + error(ERROR_SYNTAX_ERROR); \ + } + +#define lex_check_space_ok(data, current_size, max_length) \ + if (strlen(data) + current_size >= max_length - 1) \ + { \ + yyerror(yyscanner, compiler, "out of space in lex_buf"); \ + yyterminate(); \ + } + +#define yytext_to_buffer \ + { \ + char *yptr = yytext; \ + lex_check_space_ok(yptr, yyextra->lex_buf_len, LEX_BUF_SIZE); \ + while(*yptr) \ + { \ + *yyextra->lex_buf_ptr++ = *yptr++; \ + yyextra->lex_buf_len++; \ + } \ + } + +#define alloc_sized_string(str, str_len) \ + SIZED_STRING* str = (SIZED_STRING*) yr_malloc( \ + str_len + sizeof(SIZED_STRING)); \ + if (str == NULL) \ + { \ + yyerror(yyscanner, compiler, "not enough memory"); \ + yyterminate(); \ + } \ + else \ + { \ + str->length = (uint32_t) (str_len); \ + str->flags = 0; \ + } \ + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +static int is_absolute_path( + char* path) +{ + if (path == NULL) + return FALSE; + + #if defined(_WIN32) || defined(__CYGWIN__) + return strlen(path) > 2 && + path[1] == ':' && (path[2] == '/' || path[2] == '\\'); + #else + return strlen(path) > 0 && path[0] == '/'; + #endif +} + +#line 1027 "lexer.c" +#define YY_NO_UNISTD_H 1 +#define YY_NO_INPUT 1 + +#line 1031 "lexer.c" + +#define INITIAL 0 +#define str 1 +#define regexp 2 +#define include 3 +#define comment 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yylval = yylval_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +#line 158 "lexer.l" + + +#line 1310 "lexer.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 248 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 247 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 160 "lexer.l" +{ return _DOT_DOT_; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 161 "lexer.l" +{ return _LT_; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 162 "lexer.l" +{ return _GT_; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 163 "lexer.l" +{ return _LE_; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 164 "lexer.l" +{ return _GE_; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 165 "lexer.l" +{ return _EQ_; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 166 "lexer.l" +{ return _NEQ_; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 167 "lexer.l" +{ return _SHIFT_LEFT_; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 168 "lexer.l" +{ return _SHIFT_RIGHT_; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 169 "lexer.l" +{ return _PRIVATE_; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 170 "lexer.l" +{ return _GLOBAL_; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 171 "lexer.l" +{ return _RULE_; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 172 "lexer.l" +{ return _META_; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 173 "lexer.l" +{ return _STRINGS_; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 174 "lexer.l" +{ return _ASCII_; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 175 "lexer.l" +{ return _WIDE_; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 176 "lexer.l" +{ return _XOR_; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 177 "lexer.l" +{ return _FULLWORD_; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 178 "lexer.l" +{ return _NOCASE_; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 179 "lexer.l" +{ return _CONDITION_; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 180 "lexer.l" +{ return _TRUE_; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 181 "lexer.l" +{ return _FALSE_; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 182 "lexer.l" +{ return _NOT_; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 183 "lexer.l" +{ return _AND_; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 184 "lexer.l" +{ return _OR_; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 185 "lexer.l" +{ return _AT_; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 186 "lexer.l" +{ return _IN_; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 187 "lexer.l" +{ return _OF_; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 188 "lexer.l" +{ return _THEM_; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 189 "lexer.l" +{ return _FOR_; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 190 "lexer.l" +{ return _ALL_; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 191 "lexer.l" +{ return _ANY_; } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 192 "lexer.l" +{ return _ENTRYPOINT_; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 193 "lexer.l" +{ return _FILESIZE_; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 194 "lexer.l" +{ return _MATCHES_; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 195 "lexer.l" +{ return _CONTAINS_; } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 196 "lexer.l" +{ return _IMPORT_; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 199 "lexer.l" +{ BEGIN(comment); } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 200 "lexer.l" +{ BEGIN(INITIAL); } + YY_BREAK +case 40: +/* rule 40 can match eol */ +YY_RULE_SETUP +#line 201 "lexer.l" +{ /* skip comments */ } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 204 "lexer.l" +{ /* skip single-line comments */ } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 207 "lexer.l" +{ + yyextra->lex_buf_ptr = yyextra->lex_buf; + yyextra->lex_buf_len = 0; + BEGIN(include); + } + YY_BREAK +case 43: +/* rule 43 can match eol */ +YY_RULE_SETUP +#line 214 "lexer.l" +{ yytext_to_buffer; } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 217 "lexer.l" +{ + + if (compiler->include_callback != NULL) + { + #ifdef _MSC_VER + char* b = NULL; + #endif + char* s = NULL; + char* f; + + char buffer[1024]; + const char* included_rules; + char* current_file_name; + char* include_path; + + *yyextra->lex_buf_ptr = '\0'; // null-terminate included file path + + current_file_name = yr_compiler_get_current_file_name(compiler); + + if (current_file_name == NULL || + compiler->include_callback != _yr_compiler_default_include_callback || + is_absolute_path(yyextra->lex_buf)) + { + include_path = yyextra->lex_buf; + } + else + { + strlcpy(buffer, current_file_name, sizeof(buffer)); + s = strrchr(buffer, '/'); + + #ifdef _MSC_VER + b = strrchr(buffer, '\\'); // in Windows both path delimiters are accepted + #endif + + #ifdef _MSC_VER + if (s != NULL || b != NULL) + #else + if (s != NULL) + #endif + { + #ifdef _MSC_VER + f = (b > s) ? (b + 1) : (s + 1); + #else + f = s + 1; + #endif + + strlcpy(f, yyextra->lex_buf, sizeof(buffer) - (f - buffer)); + include_path = buffer; + } + else + { + include_path = yyextra->lex_buf; + } + } + + included_rules = compiler->include_callback( + include_path, + current_file_name, + compiler->current_namespace->name, + compiler->incl_clbk_user_data); + + if (included_rules != NULL) + { + int error_code = _yr_compiler_push_file_name(compiler, include_path); + + if (error_code != ERROR_SUCCESS) + { + if (error_code == ERROR_INCLUDES_CIRCULAR_REFERENCE) + { + yyerror(yyscanner, compiler, "includes circular reference"); + } + else if (error_code == ERROR_INCLUDE_DEPTH_EXCEEDED) + { + yyerror(yyscanner, compiler, "includes depth exceeded"); + } + + if (compiler->include_free != NULL) + { + compiler->include_free(included_rules, compiler->incl_clbk_user_data); + } + + yyterminate(); + } + + // Workaround for flex issue: https://github.com/westes/flex/issues/58 + yypush_buffer_state(YY_CURRENT_BUFFER, yyscanner); + yy_scan_string(included_rules, yyscanner); + yyset_lineno(1, yyscanner); + + if (compiler->include_free != NULL) + { + compiler->include_free(included_rules, compiler->incl_clbk_user_data); + } + } + else + { + char* err_msg_fmt; + char err_msg[512]; + + if (compiler->include_callback == _yr_compiler_default_include_callback) + { + err_msg_fmt = "can't open include file: %s"; + } + else + { + err_msg_fmt = "callback failed to provide include resource: %s"; + } + + snprintf( + err_msg, + sizeof(err_msg), + err_msg_fmt, + yyextra->lex_buf); + + yyerror(yyscanner, compiler, err_msg); + } + + } + else // not allowing includes + { + yyerror(yyscanner, compiler, "includes are disabled"); + } + + BEGIN(INITIAL); +} + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(str): +case YY_STATE_EOF(regexp): +case YY_STATE_EOF(include): +case YY_STATE_EOF(comment): +#line 344 "lexer.l" +{ + + YR_COMPILER* compiler = yyget_extra(yyscanner); + + _yr_compiler_pop_file_name(compiler); + yypop_buffer_state(yyscanner); + + if (!YY_CURRENT_BUFFER) + { + yyterminate(); + } +} + YY_BREAK +case 45: +YY_RULE_SETUP +#line 358 "lexer.l" +{ + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + error(ERROR_INSUFFICIENT_MEMORY); + + return _STRING_IDENTIFIER_WITH_WILDCARD_; +} + YY_BREAK +case 46: +YY_RULE_SETUP +#line 369 "lexer.l" +{ + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + error(ERROR_INSUFFICIENT_MEMORY); + + return _STRING_IDENTIFIER_; +} + YY_BREAK +case 47: +YY_RULE_SETUP +#line 380 "lexer.l" +{ + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + { + error(ERROR_INSUFFICIENT_MEMORY); + } + else + { + yylval->c_string[0] = '$'; /* replace # by $*/ + } + + return _STRING_COUNT_; +} + YY_BREAK +case 48: +YY_RULE_SETUP +#line 397 "lexer.l" +{ + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + { + error(ERROR_INSUFFICIENT_MEMORY); + } + else + { + yylval->c_string[0] = '$'; /* replace @ by $*/ + } + + return _STRING_OFFSET_; +} + YY_BREAK +case 49: +YY_RULE_SETUP +#line 414 "lexer.l" +{ + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + { + error(ERROR_INSUFFICIENT_MEMORY); + } + else + { + yylval->c_string[0] = '$'; /* replace ! by $*/ + } + + return _STRING_LENGTH_; +} + YY_BREAK +case 50: +YY_RULE_SETUP +#line 431 "lexer.l" +{ + + char* text = yytext; + + if (*text == 'u') + { + yylval->integer = 3; + text++; + } + else + { + yylval->integer = 0; + } + + if (strstr(text, "int8") == text) + { + yylval->integer += 0; + text += 4; + } + else if (strstr(text, "int16") == text) + { + yylval->integer += 1; + text += 5; + } + else if (strstr(text, "int32") == text) + { + yylval->integer += 2; + text += 5; + } + + if (strcmp(text, "be") == 0) + { + yylval->integer += 6; + } + + return _INTEGER_FUNCTION_; +} + YY_BREAK +case 51: +YY_RULE_SETUP +#line 470 "lexer.l" +{ + + if (strlen(yytext) > 128) + syntax_error("identifier too long"); + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + error(ERROR_INSUFFICIENT_MEMORY); + + return _IDENTIFIER_; +} + YY_BREAK +case 52: +YY_RULE_SETUP +#line 484 "lexer.l" +{ + + char *endptr; + + errno = 0; + yylval->integer = strtoll(yytext, &endptr, 10); + + if (yylval->integer == LLONG_MAX && errno == ERANGE) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + else if (strstr(yytext, "KB") != NULL) + { + if (yylval->integer > LLONG_MAX / 1024) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + else + { + yylval->integer *= 1024; + } + } + else if (strstr(yytext, "MB") != NULL) + { + if (yylval->integer > LLONG_MAX / 1048576) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + else + { + yylval->integer *= 1048576; + } + } + + return _NUMBER_; +} + YY_BREAK +case 53: +YY_RULE_SETUP +#line 524 "lexer.l" +{ + yylval->double_ = atof(yytext); + return _DOUBLE_; +} + YY_BREAK +case 54: +YY_RULE_SETUP +#line 529 "lexer.l" +{ + + char *endptr; + + errno = 0; + yylval->integer = strtoll(yytext, &endptr, 16); + + if (yylval->integer == LLONG_MAX && errno == ERANGE) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + + return _NUMBER_; +} + YY_BREAK +case 55: +YY_RULE_SETUP +#line 545 "lexer.l" +{ + + char *endptr; + + errno = 0; + yylval->integer = strtoll(yytext + 2, &endptr, 8); + + if (yylval->integer == LLONG_MAX && errno == ERANGE) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + + return _NUMBER_; +} + YY_BREAK +case 56: +YY_RULE_SETUP +#line 562 "lexer.l" +{ /* saw closing quote - all done */ + + alloc_sized_string(s, yyextra->lex_buf_len); + + *yyextra->lex_buf_ptr = '\0'; + memcpy(s->c_string, yyextra->lex_buf, yyextra->lex_buf_len + 1); + yylval->sized_string = s; + + BEGIN(INITIAL); + + return _TEXT_STRING_; +} + YY_BREAK +case 57: +YY_RULE_SETUP +#line 576 "lexer.l" +{ + + lex_check_space_ok("\t", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '\t'; + yyextra->lex_buf_len++; +} + YY_BREAK +case 58: +YY_RULE_SETUP +#line 584 "lexer.l" +{ + + lex_check_space_ok("\n", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '\n'; + yyextra->lex_buf_len++; +} + YY_BREAK +case 59: +YY_RULE_SETUP +#line 592 "lexer.l" +{ + + lex_check_space_ok("\"", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '\"'; + yyextra->lex_buf_len++; +} + YY_BREAK +case 60: +YY_RULE_SETUP +#line 600 "lexer.l" +{ + + lex_check_space_ok("\\", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '\\'; + yyextra->lex_buf_len++; +} + YY_BREAK +case 61: +YY_RULE_SETUP +#line 608 "lexer.l" +{ + + int result; + + sscanf( yytext + 2, "%x", &result ); + lex_check_space_ok("X", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = result; + yyextra->lex_buf_len++; +} + YY_BREAK +case 62: +YY_RULE_SETUP +#line 619 "lexer.l" +{ yytext_to_buffer; } + YY_BREAK +case 63: +/* rule 63 can match eol */ +YY_RULE_SETUP +#line 622 "lexer.l" +{ + syntax_error("unterminated string"); +} + YY_BREAK +case 64: +/* rule 64 can match eol */ +YY_RULE_SETUP +#line 627 "lexer.l" +{ + syntax_error("illegal escape sequence"); +} + YY_BREAK +case 65: +YY_RULE_SETUP +#line 632 "lexer.l" +{ + + if (yyextra->lex_buf_len > 0) + { + alloc_sized_string(s, yyextra->lex_buf_len); + + if (yytext[1] == 'i') + s->flags |= SIZED_STRING_FLAGS_NO_CASE; + + if (yytext[1] == 's' || yytext[2] == 's') + s->flags |= SIZED_STRING_FLAGS_DOT_ALL; + + *yyextra->lex_buf_ptr = '\0'; + strlcpy(s->c_string, yyextra->lex_buf, s->length + 1); + yylval->sized_string = s; + } + else + { + syntax_error("empty regular expression"); + } + + BEGIN(INITIAL); + return _REGEXP_; +} + YY_BREAK +case 66: +YY_RULE_SETUP +#line 658 "lexer.l" +{ + + lex_check_space_ok("/", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '/'; + yyextra->lex_buf_len++ ; +} + YY_BREAK +case 67: +YY_RULE_SETUP +#line 666 "lexer.l" +{ + + lex_check_space_ok("\\.", yyextra->lex_buf_len, LEX_BUF_SIZE); + + if (yytext[1] == 0) + syntax_error("malformed regular expression"); + + *yyextra->lex_buf_ptr++ = yytext[0]; + *yyextra->lex_buf_ptr++ = yytext[1]; + yyextra->lex_buf_len += 2; +} + YY_BREAK +case 68: +YY_RULE_SETUP +#line 679 "lexer.l" +{ yytext_to_buffer; } + YY_BREAK +case 69: +/* rule 69 can match eol */ +YY_RULE_SETUP +#line 682 "lexer.l" +{ + syntax_error("unterminated regular expression"); +} + YY_BREAK +case 70: +YY_RULE_SETUP +#line 687 "lexer.l" +{ + + yylval->sized_string = NULL; + yyextra->lex_buf_ptr = yyextra->lex_buf; + yyextra->lex_buf_len = 0; + BEGIN(str); +} + YY_BREAK +case 71: +YY_RULE_SETUP +#line 696 "lexer.l" +{ + + yylval->sized_string = NULL; + yyextra->lex_buf_ptr = yyextra->lex_buf; + yyextra->lex_buf_len = 0; + BEGIN(regexp); +} + YY_BREAK +case 72: +/* rule 72 can match eol */ +YY_RULE_SETUP +#line 705 "lexer.l" +{ + // Match hex-digits with whitespace or comments. The latter are stripped + // out by hex_lexer.l + + alloc_sized_string(s, strlen(yytext)); + + strlcpy(s->c_string, yytext, s->length + 1); + yylval->sized_string = s; + + return _HEX_STRING_; +} + YY_BREAK +case 73: +/* rule 73 can match eol */ +YY_RULE_SETUP +#line 718 "lexer.l" +/* skip whitespace */ + YY_BREAK +case 74: +YY_RULE_SETUP +#line 720 "lexer.l" +{ + + if (yytext[0] >= 32 && yytext[0] < 127) + { + return yytext[0]; + } + else + { + syntax_error("non-ascii character"); + } +} + YY_BREAK +case 75: +YY_RULE_SETUP +#line 732 "lexer.l" +ECHO; + YY_BREAK +#line 2193 "lexer.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 248 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 248 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 247); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 732 "lexer.l" + + + +void yywarning( + yyscan_t yyscanner, + const char *message_fmt, + ...) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + + char* file_name; + char message[512]; + va_list message_args; + + if (compiler->callback == NULL) + return; + + va_start(message_args, message_fmt); + + if (compiler->file_name_stack_ptr > 0) + file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; + else + file_name = NULL; + + vsnprintf(message, sizeof(message), message_fmt, message_args); + + compiler->callback( + YARA_ERROR_LEVEL_WARNING, + file_name, + compiler->current_line ? compiler->current_line : yyget_lineno(yyscanner), + message, + compiler->user_data); + + va_end(message_args); +} + + +void yyfatal( + yyscan_t yyscanner, + const char *error_message) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + + yyerror(yyscanner, compiler, error_message); + longjmp(compiler->error_recovery, 1); +} + + +void yyerror( + yyscan_t yyscanner, + YR_COMPILER* compiler, + const char *error_message) +{ + char message[512] = {'\0'}; + char* file_name = NULL; + + /* + if error_message != NULL the error comes from yyparse internal code + else the error comes from my code and the error code is set in + compiler->last_result + */ + + compiler->errors++; + + if (compiler->current_line != 0) + compiler->last_error_line = compiler->current_line; + else + compiler->last_error_line = yyget_lineno(yyscanner); + + compiler->current_line = 0; + + if (compiler->file_name_stack_ptr > 0) + { + file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; + } + else + { + file_name = NULL; + } + + if (error_message != NULL) + { + yr_compiler_set_error_extra_info(compiler, error_message); + compiler->last_error = ERROR_SYNTAX_ERROR; + + if (compiler->callback != NULL) + { + compiler->callback( + YARA_ERROR_LEVEL_ERROR, + file_name, + compiler->last_error_line, + error_message, + compiler->user_data); + } + } + else + { + compiler->last_error = compiler->last_result; + + if (compiler->callback != NULL) + { + yr_compiler_get_error_message(compiler, message, sizeof(message)); + + compiler->callback( + YARA_ERROR_LEVEL_ERROR, + file_name, + compiler->last_error_line, + message, + compiler->user_data); + } + } + + compiler->last_result = ERROR_SUCCESS; +} + + +int yr_lex_parse_rules_string( + const char* rules_string, + YR_COMPILER* compiler) +{ + yyscan_t yyscanner; + + compiler->errors = 0; + + if (setjmp(compiler->error_recovery) != 0) + return compiler->errors; + + yylex_init(&yyscanner); + + #if YYDEBUG + yydebug = 1; + #endif + + yyset_extra(compiler, yyscanner); + yy_scan_string(rules_string, yyscanner); + yyset_lineno(1, yyscanner); + yyparse(yyscanner, compiler); + yylex_destroy(yyscanner); + + return compiler->errors; +} + + +int yr_lex_parse_rules_file( + FILE* rules_file, + YR_COMPILER* compiler) +{ + yyscan_t yyscanner; + + compiler->errors = 0; + + if (setjmp(compiler->error_recovery) != 0) + return compiler->errors; + + yylex_init(&yyscanner); + + #if YYDEBUG + yydebug = 1; + #endif + + yyset_in(rules_file, yyscanner); + yyset_extra(compiler, yyscanner); + yyparse(yyscanner, compiler); + yylex_destroy(yyscanner); + + return compiler->errors; +} + + +int yr_lex_parse_rules_fd( + YR_FILE_DESCRIPTOR rules_fd, + YR_COMPILER* compiler) +{ + yyscan_t yyscanner; + char buf[1024]; + + compiler->errors = 0; + + if (setjmp(compiler->error_recovery) != 0) + return compiler->errors; + + yylex_init(&yyscanner); + + #if YYDEBUG + yydebug = 1; + #endif + + yyset_extra(compiler, yyscanner); + + while (1) + { +#if defined(_WIN32) || defined(__CYGWIN__) + DWORD len; + if (!ReadFile(rules_fd, buf, sizeof(buf), &len, NULL)) + break; +#else + int len = (int) read(rules_fd, buf, sizeof(buf)); + if (len < 0) + { + if (errno == EINTR) + continue; + else + break; + } +#endif + if (len == 0) + break; + yy_scan_bytes(buf, len, yyscanner); + } + + yyparse(yyscanner, compiler); + yylex_destroy(yyscanner); + + return compiler->errors; +} + diff --git a/yara-master/libyara/lexer.l b/yara-master/libyara/lexer.l new file mode 100644 index 0000000..57193de --- /dev/null +++ b/yara-master/libyara/lexer.l @@ -0,0 +1,946 @@ +/* +Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +/* Lexical analyzer for YARA */ + +%{ + +/* Disable warnings for unused functions in this file. + +As we redefine YY_FATAL_ERROR macro to use our own function yara_yyfatal, the +yy_fatal_error function generated by Flex is not actually used, causing a +compiler warning. Flex doesn't offer any options to remove the yy_fatal_error +function. When they include something like %option noyy_fatal_error as they do +with noyywrap then we can remove this pragma. +*/ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#define strtoll _strtoi64 +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "grammar.h" + +#define error(error_code) \ + { \ + compiler->last_result = error_code; \ + yyerror(yyscanner, compiler, NULL); \ + yyterminate(); \ + } + +#define syntax_error(error_msg) \ + { \ + yr_compiler_set_error_extra_info(compiler, error_msg); \ + error(ERROR_SYNTAX_ERROR); \ + } + +#define lex_check_space_ok(data, current_size, max_length) \ + if (strlen(data) + current_size >= max_length - 1) \ + { \ + yyerror(yyscanner, compiler, "out of space in lex_buf"); \ + yyterminate(); \ + } + +#define yytext_to_buffer \ + { \ + char *yptr = yytext; \ + lex_check_space_ok(yptr, yyextra->lex_buf_len, LEX_BUF_SIZE); \ + while(*yptr) \ + { \ + *yyextra->lex_buf_ptr++ = *yptr++; \ + yyextra->lex_buf_len++; \ + } \ + } + +#define alloc_sized_string(str, str_len) \ + SIZED_STRING* str = (SIZED_STRING*) yr_malloc( \ + str_len + sizeof(SIZED_STRING)); \ + if (str == NULL) \ + { \ + yyerror(yyscanner, compiler, "not enough memory"); \ + yyterminate(); \ + } \ + else \ + { \ + str->length = (uint32_t) (str_len); \ + str->flags = 0; \ + } \ + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +static int is_absolute_path( + char* path) +{ + if (path == NULL) + return FALSE; + + #if defined(_WIN32) || defined(__CYGWIN__) + return strlen(path) > 2 && + path[1] == ':' && (path[2] == '/' || path[2] == '\\'); + #else + return strlen(path) > 0 && path[0] == '/'; + #endif +} + +%} + +%option reentrant bison-bridge +%option noyywrap +%option nounistd +%option noinput +%option nounput +%option never-interactive +%option yylineno +%option prefix="yara_yy" +%option outfile="lex.yy.c" + +%option verbose +%option warn + +%x str +%x regexp +%x include +%x comment + +digit [0-9] +letter [a-zA-Z] +hexdigit [a-fA-F0-9] +octdigit [0-7] + +%% + +".." { return _DOT_DOT_; } +"<" { return _LT_; } +">" { return _GT_; } +"<=" { return _LE_; } +">=" { return _GE_; } +"==" { return _EQ_; } +"!=" { return _NEQ_; } +"<<" { return _SHIFT_LEFT_; } +">>" { return _SHIFT_RIGHT_; } +"private" { return _PRIVATE_; } +"global" { return _GLOBAL_; } +"rule" { return _RULE_; } +"meta" { return _META_; } +"strings" { return _STRINGS_; } +"ascii" { return _ASCII_; } +"wide" { return _WIDE_; } +"xor" { return _XOR_; } +"fullword" { return _FULLWORD_; } +"nocase" { return _NOCASE_; } +"condition" { return _CONDITION_; } +"true" { return _TRUE_; } +"false" { return _FALSE_; } +"not" { return _NOT_; } +"and" { return _AND_; } +"or" { return _OR_; } +"at" { return _AT_; } +"in" { return _IN_; } +"of" { return _OF_; } +"them" { return _THEM_; } +"for" { return _FOR_; } +"all" { return _ALL_; } +"any" { return _ANY_; } +"entrypoint" { return _ENTRYPOINT_; } +"filesize" { return _FILESIZE_; } +"matches" { return _MATCHES_; } +"contains" { return _CONTAINS_; } +"import" { return _IMPORT_; } + + +"/*" { BEGIN(comment); } +"*/" { BEGIN(INITIAL); } +(.|\n) { /* skip comments */ } + + +"//"[^\n]* { /* skip single-line comments */ } + + +include[ \t]+\" { + yyextra->lex_buf_ptr = yyextra->lex_buf; + yyextra->lex_buf_len = 0; + BEGIN(include); + } + + +[^\"]+ { yytext_to_buffer; } + + +\" { + + if (compiler->include_callback != NULL) + { + #ifdef _MSC_VER + char* b = NULL; + #endif + char* s = NULL; + char* f; + + char buffer[1024]; + const char* included_rules; + char* current_file_name; + char* include_path; + + *yyextra->lex_buf_ptr = '\0'; // null-terminate included file path + + current_file_name = yr_compiler_get_current_file_name(compiler); + + if (current_file_name == NULL || + compiler->include_callback != _yr_compiler_default_include_callback || + is_absolute_path(yyextra->lex_buf)) + { + include_path = yyextra->lex_buf; + } + else + { + strlcpy(buffer, current_file_name, sizeof(buffer)); + s = strrchr(buffer, '/'); + + #ifdef _MSC_VER + b = strrchr(buffer, '\\'); // in Windows both path delimiters are accepted + #endif + + #ifdef _MSC_VER + if (s != NULL || b != NULL) + #else + if (s != NULL) + #endif + { + #ifdef _MSC_VER + f = (b > s) ? (b + 1) : (s + 1); + #else + f = s + 1; + #endif + + strlcpy(f, yyextra->lex_buf, sizeof(buffer) - (f - buffer)); + include_path = buffer; + } + else + { + include_path = yyextra->lex_buf; + } + } + + included_rules = compiler->include_callback( + include_path, + current_file_name, + compiler->current_namespace->name, + compiler->incl_clbk_user_data); + + if (included_rules != NULL) + { + int error_code = _yr_compiler_push_file_name(compiler, include_path); + + if (error_code != ERROR_SUCCESS) + { + if (error_code == ERROR_INCLUDES_CIRCULAR_REFERENCE) + { + yyerror(yyscanner, compiler, "includes circular reference"); + } + else if (error_code == ERROR_INCLUDE_DEPTH_EXCEEDED) + { + yyerror(yyscanner, compiler, "includes depth exceeded"); + } + + if (compiler->include_free != NULL) + { + compiler->include_free(included_rules, compiler->incl_clbk_user_data); + } + + yyterminate(); + } + + // Workaround for flex issue: https://github.com/westes/flex/issues/58 + yypush_buffer_state(YY_CURRENT_BUFFER, yyscanner); + yy_scan_string(included_rules, yyscanner); + yyset_lineno(1, yyscanner); + + if (compiler->include_free != NULL) + { + compiler->include_free(included_rules, compiler->incl_clbk_user_data); + } + } + else + { + char* err_msg_fmt; + char err_msg[512]; + + if (compiler->include_callback == _yr_compiler_default_include_callback) + { + err_msg_fmt = "can't open include file: %s"; + } + else + { + err_msg_fmt = "callback failed to provide include resource: %s"; + } + + snprintf( + err_msg, + sizeof(err_msg), + err_msg_fmt, + yyextra->lex_buf); + + yyerror(yyscanner, compiler, err_msg); + } + + } + else // not allowing includes + { + yyerror(yyscanner, compiler, "includes are disabled"); + } + + BEGIN(INITIAL); +} + + +<> { + + YR_COMPILER* compiler = yyget_extra(yyscanner); + + _yr_compiler_pop_file_name(compiler); + yypop_buffer_state(yyscanner); + + if (!YY_CURRENT_BUFFER) + { + yyterminate(); + } +} + + +$({letter}|{digit}|_)*"*" { + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + error(ERROR_INSUFFICIENT_MEMORY); + + return _STRING_IDENTIFIER_WITH_WILDCARD_; +} + + +$({letter}|{digit}|_)* { + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + error(ERROR_INSUFFICIENT_MEMORY); + + return _STRING_IDENTIFIER_; +} + + +#({letter}|{digit}|_)* { + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + { + error(ERROR_INSUFFICIENT_MEMORY); + } + else + { + yylval->c_string[0] = '$'; /* replace # by $*/ + } + + return _STRING_COUNT_; +} + + +@({letter}|{digit}|_)* { + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + { + error(ERROR_INSUFFICIENT_MEMORY); + } + else + { + yylval->c_string[0] = '$'; /* replace @ by $*/ + } + + return _STRING_OFFSET_; +} + + +!({letter}|{digit}|_)* { + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + { + error(ERROR_INSUFFICIENT_MEMORY); + } + else + { + yylval->c_string[0] = '$'; /* replace ! by $*/ + } + + return _STRING_LENGTH_; +} + + +u?int(8|16|32)(be)? { + + char* text = yytext; + + if (*text == 'u') + { + yylval->integer = 3; + text++; + } + else + { + yylval->integer = 0; + } + + if (strstr(text, "int8") == text) + { + yylval->integer += 0; + text += 4; + } + else if (strstr(text, "int16") == text) + { + yylval->integer += 1; + text += 5; + } + else if (strstr(text, "int32") == text) + { + yylval->integer += 2; + text += 5; + } + + if (strcmp(text, "be") == 0) + { + yylval->integer += 6; + } + + return _INTEGER_FUNCTION_; +} + + +({letter}|_)({letter}|{digit}|_)* { + + if (strlen(yytext) > 128) + syntax_error("identifier too long"); + + yylval->c_string = yr_strdup(yytext); + + if (yylval->c_string == NULL) + error(ERROR_INSUFFICIENT_MEMORY); + + return _IDENTIFIER_; +} + + +{digit}+(MB|KB){0,1} { + + char *endptr; + + errno = 0; + yylval->integer = strtoll(yytext, &endptr, 10); + + if (yylval->integer == LLONG_MAX && errno == ERANGE) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + else if (strstr(yytext, "KB") != NULL) + { + if (yylval->integer > LLONG_MAX / 1024) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + else + { + yylval->integer *= 1024; + } + } + else if (strstr(yytext, "MB") != NULL) + { + if (yylval->integer > LLONG_MAX / 1048576) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + else + { + yylval->integer *= 1048576; + } + } + + return _NUMBER_; +} + +{digit}+"."{digit}+ { + yylval->double_ = atof(yytext); + return _DOUBLE_; +} + +0x{hexdigit}+ { + + char *endptr; + + errno = 0; + yylval->integer = strtoll(yytext, &endptr, 16); + + if (yylval->integer == LLONG_MAX && errno == ERANGE) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + + return _NUMBER_; +} + +0o{octdigit}+ { + + char *endptr; + + errno = 0; + yylval->integer = strtoll(yytext + 2, &endptr, 8); + + if (yylval->integer == LLONG_MAX && errno == ERANGE) + { + yr_compiler_set_error_extra_info(compiler, yytext); + error(ERROR_INTEGER_OVERFLOW); + } + + return _NUMBER_; +} + + +\" { /* saw closing quote - all done */ + + alloc_sized_string(s, yyextra->lex_buf_len); + + *yyextra->lex_buf_ptr = '\0'; + memcpy(s->c_string, yyextra->lex_buf, yyextra->lex_buf_len + 1); + yylval->sized_string = s; + + BEGIN(INITIAL); + + return _TEXT_STRING_; +} + + +\\t { + + lex_check_space_ok("\t", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '\t'; + yyextra->lex_buf_len++; +} + + +\\n { + + lex_check_space_ok("\n", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '\n'; + yyextra->lex_buf_len++; +} + + +\\\" { + + lex_check_space_ok("\"", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '\"'; + yyextra->lex_buf_len++; +} + + +\\\\ { + + lex_check_space_ok("\\", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '\\'; + yyextra->lex_buf_len++; +} + + +\\x{hexdigit}{2} { + + int result; + + sscanf( yytext + 2, "%x", &result ); + lex_check_space_ok("X", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = result; + yyextra->lex_buf_len++; +} + + +[^\\\n\"]+ { yytext_to_buffer; } + + +\n { + syntax_error("unterminated string"); +} + + +\\(.|\n) { + syntax_error("illegal escape sequence"); +} + + +\/i?s? { + + if (yyextra->lex_buf_len > 0) + { + alloc_sized_string(s, yyextra->lex_buf_len); + + if (yytext[1] == 'i') + s->flags |= SIZED_STRING_FLAGS_NO_CASE; + + if (yytext[1] == 's' || yytext[2] == 's') + s->flags |= SIZED_STRING_FLAGS_DOT_ALL; + + *yyextra->lex_buf_ptr = '\0'; + strlcpy(s->c_string, yyextra->lex_buf, s->length + 1); + yylval->sized_string = s; + } + else + { + syntax_error("empty regular expression"); + } + + BEGIN(INITIAL); + return _REGEXP_; +} + + +\\\/ { + + lex_check_space_ok("/", yyextra->lex_buf_len, LEX_BUF_SIZE); + *yyextra->lex_buf_ptr++ = '/'; + yyextra->lex_buf_len++ ; +} + + +\\. { + + lex_check_space_ok("\\.", yyextra->lex_buf_len, LEX_BUF_SIZE); + + if (yytext[1] == 0) + syntax_error("malformed regular expression"); + + *yyextra->lex_buf_ptr++ = yytext[0]; + *yyextra->lex_buf_ptr++ = yytext[1]; + yyextra->lex_buf_len += 2; +} + + +[^/\n\\]+ { yytext_to_buffer; } + + +\n { + syntax_error("unterminated regular expression"); +} + + +\" { + + yylval->sized_string = NULL; + yyextra->lex_buf_ptr = yyextra->lex_buf; + yyextra->lex_buf_len = 0; + BEGIN(str); +} + + +"/" { + + yylval->sized_string = NULL; + yyextra->lex_buf_ptr = yyextra->lex_buf; + yyextra->lex_buf_len = 0; + BEGIN(regexp); +} + + +\{(({hexdigit}|[ \-|\?\[\]\(\)\n\r\t]|\/\*[^*]*\*\/)+|\/\/.*)+\} { + // Match hex-digits with whitespace or comments. The latter are stripped + // out by hex_lexer.l + + alloc_sized_string(s, strlen(yytext)); + + strlcpy(s->c_string, yytext, s->length + 1); + yylval->sized_string = s; + + return _HEX_STRING_; +} + + +[ \t\r\n] /* skip whitespace */ + +. { + + if (yytext[0] >= 32 && yytext[0] < 127) + { + return yytext[0]; + } + else + { + syntax_error("non-ascii character"); + } +} + +%% + + +void yywarning( + yyscan_t yyscanner, + const char *message_fmt, + ...) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + + char* file_name; + char message[512]; + va_list message_args; + + if (compiler->callback == NULL) + return; + + va_start(message_args, message_fmt); + + if (compiler->file_name_stack_ptr > 0) + file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; + else + file_name = NULL; + + vsnprintf(message, sizeof(message), message_fmt, message_args); + + compiler->callback( + YARA_ERROR_LEVEL_WARNING, + file_name, + compiler->current_line ? compiler->current_line : yyget_lineno(yyscanner), + message, + compiler->user_data); + + va_end(message_args); +} + + +void yyfatal( + yyscan_t yyscanner, + const char *error_message) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + + yyerror(yyscanner, compiler, error_message); + longjmp(compiler->error_recovery, 1); +} + + +void yyerror( + yyscan_t yyscanner, + YR_COMPILER* compiler, + const char *error_message) +{ + char message[512] = {'\0'}; + char* file_name = NULL; + + /* + if error_message != NULL the error comes from yyparse internal code + else the error comes from my code and the error code is set in + compiler->last_result + */ + + compiler->errors++; + + if (compiler->current_line != 0) + compiler->last_error_line = compiler->current_line; + else + compiler->last_error_line = yyget_lineno(yyscanner); + + compiler->current_line = 0; + + if (compiler->file_name_stack_ptr > 0) + { + file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; + } + else + { + file_name = NULL; + } + + if (error_message != NULL) + { + yr_compiler_set_error_extra_info(compiler, error_message); + compiler->last_error = ERROR_SYNTAX_ERROR; + + if (compiler->callback != NULL) + { + compiler->callback( + YARA_ERROR_LEVEL_ERROR, + file_name, + compiler->last_error_line, + error_message, + compiler->user_data); + } + } + else + { + compiler->last_error = compiler->last_result; + + if (compiler->callback != NULL) + { + yr_compiler_get_error_message(compiler, message, sizeof(message)); + + compiler->callback( + YARA_ERROR_LEVEL_ERROR, + file_name, + compiler->last_error_line, + message, + compiler->user_data); + } + } + + compiler->last_result = ERROR_SUCCESS; +} + + +int yr_lex_parse_rules_string( + const char* rules_string, + YR_COMPILER* compiler) +{ + yyscan_t yyscanner; + + compiler->errors = 0; + + if (setjmp(compiler->error_recovery) != 0) + return compiler->errors; + + yylex_init(&yyscanner); + + #if YYDEBUG + yydebug = 1; + #endif + + yyset_extra(compiler, yyscanner); + yy_scan_string(rules_string, yyscanner); + yyset_lineno(1, yyscanner); + yyparse(yyscanner, compiler); + yylex_destroy(yyscanner); + + return compiler->errors; +} + + +int yr_lex_parse_rules_file( + FILE* rules_file, + YR_COMPILER* compiler) +{ + yyscan_t yyscanner; + + compiler->errors = 0; + + if (setjmp(compiler->error_recovery) != 0) + return compiler->errors; + + yylex_init(&yyscanner); + + #if YYDEBUG + yydebug = 1; + #endif + + yyset_in(rules_file, yyscanner); + yyset_extra(compiler, yyscanner); + yyparse(yyscanner, compiler); + yylex_destroy(yyscanner); + + return compiler->errors; +} + + +int yr_lex_parse_rules_fd( + YR_FILE_DESCRIPTOR rules_fd, + YR_COMPILER* compiler) +{ + yyscan_t yyscanner; + char buf[1024]; + + compiler->errors = 0; + + if (setjmp(compiler->error_recovery) != 0) + return compiler->errors; + + yylex_init(&yyscanner); + + #if YYDEBUG + yydebug = 1; + #endif + + yyset_extra(compiler, yyscanner); + + while (1) + { +#if defined(_WIN32) || defined(__CYGWIN__) + DWORD len; + if (!ReadFile(rules_fd, buf, sizeof(buf), &len, NULL)) + break; +#else + int len = (int) read(rules_fd, buf, sizeof(buf)); + if (len < 0) + { + if (errno == EINTR) + continue; + else + break; + } +#endif + if (len == 0) + break; + yy_scan_bytes(buf, len, yyscanner); + } + + yyparse(yyscanner, compiler); + yylex_destroy(yyscanner); + + return compiler->errors; +} diff --git a/yara-master/libyara/libyara.c b/yara-master/libyara/libyara.c new file mode 100644 index 0000000..f1fd83a --- /dev/null +++ b/yara-master/libyara/libyara.c @@ -0,0 +1,339 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#if defined(JEMALLOC) +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "crypto.h" + +#if defined(_WIN32) || defined(__CYGWIN__) +#if !defined(_MSC_VER) || (defined(_MSC_VER) && (_MSC_VER < 1900)) +#define snprintf _snprintf +#endif +#endif + + +YR_THREAD_STORAGE_KEY yr_tidx_key; +YR_THREAD_STORAGE_KEY yr_recovery_state_key; + + +static int init_count = 0; + +static struct yr_config_var +{ + union + { + size_t sz; + uint32_t ui32; + uint64_t ui64; + char* str; + }; + +} yr_cfgs[YR_CONFIG_LAST]; + + +char yr_lowercase[256]; +char yr_altercase[256]; + + +#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER < 0x10100000L + +// The OpenSSL library before version 1.1 requires some locks in order +// to be thread-safe. These locks are initialized in yr_initialize +// function. + +static YR_MUTEX *openssl_locks; + + +static unsigned long _thread_id(void) +{ + return (unsigned long) yr_current_thread_id(); +} + + +static void _locking_function( + int mode, + int n, + const char *file, + int line) +{ + if (mode & CRYPTO_LOCK) + yr_mutex_lock(&openssl_locks[n]); + else + yr_mutex_unlock(&openssl_locks[n]); +} + +#endif + +// +// yr_initialize +// +// Should be called by main thread before using any other +// function from libyara. +// + +YR_API int yr_initialize(void) +{ + uint32_t def_stack_size = DEFAULT_STACK_SIZE; + uint32_t def_max_strings_per_rule = DEFAULT_MAX_STRINGS_PER_RULE; + uint32_t def_max_match_data = DEFAULT_MAX_MATCH_DATA; + + int i; + + init_count++; + + if (init_count > 1) + return ERROR_SUCCESS; + + for (i = 0; i < 256; i++) + { + if (i >= 'a' && i <= 'z') + yr_altercase[i] = i - 32; + else if (i >= 'A' && i <= 'Z') + yr_altercase[i] = i + 32; + else + yr_altercase[i] = i; + + yr_lowercase[i] = tolower(i); + } + + FAIL_ON_ERROR(yr_heap_alloc()); + FAIL_ON_ERROR(yr_thread_storage_create(&yr_tidx_key)); + FAIL_ON_ERROR(yr_thread_storage_create(&yr_recovery_state_key)); + + #if defined HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER < 0x10100000L + + openssl_locks = (YR_MUTEX*) OPENSSL_malloc( + CRYPTO_num_locks() * sizeof(YR_MUTEX)); + + for (i = 0; i < CRYPTO_num_locks(); i++) + yr_mutex_create(&openssl_locks[i]); + + CRYPTO_set_id_callback(_thread_id); + CRYPTO_set_locking_callback(_locking_function); + + #elif defined(HAVE_WINCRYPT_H) + + if (!CryptAcquireContext(&yr_cryptprov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + return ERROR_INTERNAL_FATAL_ERROR; + } + + #elif defined(HAVE_COMMON_CRYPTO) + + ... + + #endif + + FAIL_ON_ERROR(yr_modules_initialize()); + + // Initialize default configuration options + FAIL_ON_ERROR(yr_set_configuration( + YR_CONFIG_STACK_SIZE, &def_stack_size)); + + FAIL_ON_ERROR(yr_set_configuration( + YR_CONFIG_MAX_STRINGS_PER_RULE, &def_max_strings_per_rule)); + + FAIL_ON_ERROR(yr_set_configuration( + YR_CONFIG_MAX_MATCH_DATA, &def_max_match_data)); + + return ERROR_SUCCESS; +} + + +// +// yr_finalize_thread +// +// This function is deprecated, it's maintained only for backward compatibility +// with programs that already use it. Calling yr_finalize_thread from each +// thread using libyara is not required anymore. + +YR_DEPRECATED_API void yr_finalize_thread(void) +{ +} + + +// +// yr_finalize +// +// Should be called by main thread before exiting. +// + +YR_API int yr_finalize(void) +{ + #if defined HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER < 0x10100000L + int i; + #endif + + // yr_finalize shouldn't be called without calling yr_initialize first + + if (init_count == 0) + return ERROR_INTERNAL_FATAL_ERROR; + + init_count--; + + if (init_count > 0) + return ERROR_SUCCESS; + + #if defined HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER < 0x10100000L + + for (i = 0; i < CRYPTO_num_locks(); i ++) + yr_mutex_destroy(&openssl_locks[i]); + + OPENSSL_free(openssl_locks); + CRYPTO_set_id_callback(NULL); + CRYPTO_set_locking_callback(NULL); + + #elif defined(HAVE_WINCRYPT_H) + + CryptReleaseContext(yr_cryptprov, 0); + + #endif + + FAIL_ON_ERROR(yr_thread_storage_destroy(&yr_tidx_key)); + FAIL_ON_ERROR(yr_thread_storage_destroy(&yr_recovery_state_key)); + FAIL_ON_ERROR(yr_modules_finalize()); + FAIL_ON_ERROR(yr_heap_free()); + + #if defined(JEMALLOC) + malloc_stats_print(NULL, NULL, NULL); + mallctl("prof.dump", NULL, NULL, NULL, 0); + #endif + + return ERROR_SUCCESS; +} + +// +// yr_set_tidx +// +// Set the thread index (tidx) for the current thread. The tidx is the index +// that will be used by the thread to access thread-specific data stored in +// YR_RULES structure. +// +// Args: +// int tidx - The zero-based tidx that will be associated to the current +// thread. +// + +YR_API void yr_set_tidx(int tidx) +{ + yr_thread_storage_set_value(&yr_tidx_key, (void*) (size_t) (tidx + 1)); +} + + +// +// yr_get_tidx +// +// Get the thread index (tidx) for the current thread. +// +// Returns: +// The tidx for the current thread or -1 if the current thread doesn't +// have any tidx associated. +// + +YR_API int yr_get_tidx(void) +{ + return (int) (size_t) yr_thread_storage_get_value(&yr_tidx_key) - 1; +} + + +// +// yr_set_configuration +// +// Sets a configuration option. This function receives a configuration name, +// as defined by the YR_CONFIG_NAME enum, and a pointer to the value being +// set. The type of the value depends on the configuration name. +// +// Args: +// YR_CONFIG_NAME name - Any of the values defined by the YR_CONFIG_NAME +// enum. Posible values are: +// +// YR_CONFIG_STACK_SIZE data type: uint32_t +// YR_CONFIG_MAX_STRINGS_PER_RULE data type: uint32_t +// YR_CONFIG_MAX_MATCH_DATA data type: uint32_t +// +// void *src - Pointer to the value being set for the option. +// +// Returns: +// An error code. + +YR_API int yr_set_configuration( + YR_CONFIG_NAME name, + void *src) +{ + if (src == NULL) + return ERROR_INTERNAL_FATAL_ERROR; + + switch (name) + { // lump all the cases using same types together in one cascade + case YR_CONFIG_STACK_SIZE: + case YR_CONFIG_MAX_STRINGS_PER_RULE: + case YR_CONFIG_MAX_MATCH_DATA: + yr_cfgs[name].ui32 = *(uint32_t*) src; + break; + + default: + return ERROR_INTERNAL_FATAL_ERROR; + } + + return ERROR_SUCCESS; +} + + +YR_API int yr_get_configuration( + YR_CONFIG_NAME name, + void *dest) +{ + if (dest == NULL) + return ERROR_INTERNAL_FATAL_ERROR; + + switch (name) + { // lump all the cases using same types together in one cascade + case YR_CONFIG_STACK_SIZE: + case YR_CONFIG_MAX_STRINGS_PER_RULE: + case YR_CONFIG_MAX_MATCH_DATA: + *(uint32_t*) dest = yr_cfgs[name].ui32; + break; + + default: + return ERROR_INTERNAL_FATAL_ERROR; + } + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/mem.c b/yara-master/libyara/mem.c new file mode 100644 index 0000000..f0420cf --- /dev/null +++ b/yara-master/libyara/mem.c @@ -0,0 +1,168 @@ +/* +Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#if defined(_WIN32) || defined(__CYGWIN__) + +#include +#include + +static HANDLE hHeap; + +int yr_heap_alloc(void) +{ + hHeap = HeapCreate(0, 0x8000, 0); + + if (hHeap == NULL) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_heap_free(void) +{ + if (HeapDestroy(hHeap)) + return ERROR_SUCCESS; + else + return ERROR_INTERNAL_FATAL_ERROR; +} + + +void* yr_calloc(size_t count, size_t size) +{ + return (void*) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, count * size); +} + + +void* yr_malloc(size_t size) +{ + return (void*) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, size); +} + + +void* yr_realloc(void* ptr, size_t size) +{ + return (void*) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, ptr, size); +} + + +void yr_free(void* ptr) +{ + HeapFree(hHeap, 0, ptr); +} + + +char* yr_strdup(const char *str) +{ + size_t len = strlen(str); + char *dup = (char*) yr_malloc(len + 1); + + if (dup == NULL) + return NULL; + + memcpy(dup, str, len); + dup[len] = '\0'; + + return (char*) dup; +} + + +char* yr_strndup(const char *str, size_t n) +{ + size_t len = strnlen(str, n); + char *dup = (char*) yr_malloc(len + 1); + + if (dup == NULL) + return NULL; + + memcpy(dup, str, len); + dup[len] = '\0'; + + return (char *) dup; +} + +#else + +#define _GNU_SOURCE + +#include +#include +#include + +int yr_heap_alloc(void) +{ + return ERROR_SUCCESS; +} + + +int yr_heap_free(void) +{ + return ERROR_SUCCESS; +} + + +void* yr_calloc(size_t count, size_t size) +{ + return calloc(count, size); +} + + +void* yr_malloc(size_t size) +{ + return malloc(size); +} + + +void* yr_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +void yr_free(void *ptr) +{ + free(ptr); +} + + +char* yr_strdup(const char *str) +{ + return strdup(str); +} + + +char* yr_strndup(const char *str, size_t n) +{ + return strndup(str, n); +} + +#endif diff --git a/yara-master/libyara/modules.c b/yara-master/libyara/modules.c new file mode 100644 index 0000000..c6461a0 --- /dev/null +++ b/yara-master/libyara/modules.c @@ -0,0 +1,218 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include + + +#define MODULE(name) \ + int name ## __declarations(YR_OBJECT* module); \ + int name ## __load(YR_SCAN_CONTEXT* context, \ + YR_OBJECT* module, \ + void* module_data, \ + size_t module_data_size); \ + int name ## __unload(YR_OBJECT* main_structure); \ + int name ## __initialize(YR_MODULE* module); \ + int name ## __finalize(YR_MODULE* module); + + +#include + +#undef MODULE + + +#define MODULE(name) \ + { \ + #name, \ + name##__declarations, \ + name##__load, \ + name##__unload, \ + name##__initialize, \ + name##__finalize \ + }, + +YR_MODULE yr_modules_table[] = +{ + #include +}; + +#undef MODULE + + +int yr_modules_initialize() +{ + int i; + + for (i = 0; i < sizeof(yr_modules_table) / sizeof(YR_MODULE); i++) + { + int result = yr_modules_table[i].initialize(&yr_modules_table[i]); + + if (result != ERROR_SUCCESS) + return result; + } + + return ERROR_SUCCESS; +} + + +int yr_modules_finalize() +{ + int i; + + for (i = 0; i < sizeof(yr_modules_table) / sizeof(YR_MODULE); i++) + { + int result = yr_modules_table[i].finalize(&yr_modules_table[i]); + + if (result != ERROR_SUCCESS) + return result; + } + + return ERROR_SUCCESS; +} + + +int yr_modules_do_declarations( + const char* module_name, + YR_OBJECT* main_structure) +{ + int i; + + for (i = 0; i < sizeof(yr_modules_table) / sizeof(YR_MODULE); i++) + { + if (strcmp(yr_modules_table[i].name, module_name) == 0) + return yr_modules_table[i].declarations(main_structure); + } + + return ERROR_UNKNOWN_MODULE; +} + + +int yr_modules_load( + const char* module_name, + YR_SCAN_CONTEXT* context) +{ + int i, result; + + YR_MODULE_IMPORT mi; + + YR_OBJECT* module_structure = (YR_OBJECT*) yr_hash_table_lookup( + context->objects_table, + module_name, + NULL); + + // if module_structure != NULL, the module was already + // loaded, return successfully without doing nothing. + + if (module_structure != NULL) + return ERROR_SUCCESS; + + // not loaded yet + + FAIL_ON_ERROR(yr_object_create( + OBJECT_TYPE_STRUCTURE, + module_name, + NULL, + &module_structure)); + + mi.module_name = module_name; + mi.module_data = NULL; + mi.module_data_size = 0; + + result = context->callback( + CALLBACK_MSG_IMPORT_MODULE, + &mi, + context->user_data); + + if (result == CALLBACK_ERROR) + { + yr_object_destroy(module_structure); + return ERROR_CALLBACK_ERROR; + } + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_modules_do_declarations(module_name, module_structure), + yr_object_destroy(module_structure)); + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_hash_table_add( + context->objects_table, + module_name, + NULL, + module_structure), + yr_object_destroy(module_structure)); + + for (i = 0; i < sizeof(yr_modules_table) / sizeof(YR_MODULE); i++) + { + if (strcmp(yr_modules_table[i].name, module_name) == 0) + { + result = yr_modules_table[i].load( + context, + module_structure, + mi.module_data, + mi.module_data_size); + + if (result != ERROR_SUCCESS) + return result; + } + } + + result = context->callback( + CALLBACK_MSG_MODULE_IMPORTED, + module_structure, + context->user_data); + + if (result == CALLBACK_ERROR) + return ERROR_CALLBACK_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_modules_unload_all( + YR_SCAN_CONTEXT* context) +{ + int i; + + for (i = 0; i < sizeof(yr_modules_table) / sizeof(YR_MODULE); i++) + { + YR_OBJECT* module_structure = (YR_OBJECT*) yr_hash_table_remove( + context->objects_table, + yr_modules_table[i].name, + NULL); + + if (module_structure != NULL) + { + yr_modules_table[i].unload(module_structure); + yr_object_destroy(module_structure); + } + } + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/cuckoo.c b/yara-master/libyara/modules/cuckoo.c new file mode 100644 index 0000000..71f99d2 --- /dev/null +++ b/yara-master/libyara/modules/cuckoo.c @@ -0,0 +1,346 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + + +#include +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +#define strcasecmp _stricmp +#endif + +#define MODULE_NAME cuckoo + + +define_function(network_dns_lookup) +{ + YR_SCAN_CONTEXT* context = scan_context(); + YR_OBJECT* network_obj = parent(); + + json_t* network_json = (json_t*) network_obj->data; + json_t* value; + + uint64_t result = 0; + size_t index; + + // Recent versions of Cuckoo generate domain resolution information with + // this format: + // + // "domains": [ + // { + // "ip": "192.168.0.1", + // "domain": "foo.bar.com" + // } + // ] + // + // But older versions with this other format: + // + // "dns": [ + // { + // "ip": "192.168.0.1", + // "hostname": "foo.bar.com" + // } + // ] + // + // Additionally, the newer versions also have a "dns" field. So, let's try + // to locate the "domains" field first, if not found fall back to the older + // format. + + char* field_name = "domain"; + char* hostname; + char* ip; + + json_t* dns_info_json = json_object_get(network_json, "domains"); + + if (dns_info_json == NULL) + { + dns_info_json = json_object_get(network_json, "dns"); + field_name = "hostname"; + } + + json_array_foreach(dns_info_json, index, value) + { + if (json_unpack(value, "{s:s, s:s}", "ip", &ip, field_name, &hostname) == 0) + { + if (yr_re_match(context, regexp_argument(1), hostname) > 0) + { + result = 1; + break; + } + } + } + + return_integer(result); +} + + +#define METHOD_GET 0x01 +#define METHOD_POST 0x02 + + +uint64_t http_request( + YR_SCAN_CONTEXT* context, + YR_OBJECT* network_obj, + RE* uri_regexp, + int methods) +{ + json_t* network_json = (json_t*) network_obj->data; + json_t* http_json = json_object_get(network_json, "http"); + json_t* value; + + uint64_t result = 0; + size_t index; + + char* method; + char* uri; + + json_array_foreach(http_json, index, value) + { + if (json_unpack(value, "{s:s, s:s}", "uri", &uri, "method", &method) == 0) + { + if (((methods & METHOD_GET && strcasecmp(method, "get") == 0) || + (methods & METHOD_POST && strcasecmp(method, "post") == 0)) && + yr_re_match(context, uri_regexp, uri) > 0) + { + result = 1; + break; + } + } + } + + return result; +} + + +define_function(network_http_request) +{ + return_integer( + http_request( + scan_context(), + parent(), + regexp_argument(1), + METHOD_GET | METHOD_POST)); +} + + +define_function(network_http_get) +{ + return_integer( + http_request( + scan_context(), + parent(), + regexp_argument(1), + METHOD_GET)); +} + + +define_function(network_http_post) +{ + return_integer( + http_request( + scan_context(), + parent(), + regexp_argument(1), + METHOD_POST)); +} + + +define_function(registry_key_access) +{ + YR_SCAN_CONTEXT* context = scan_context(); + YR_OBJECT* registry_obj = parent(); + + json_t* keys_json = (json_t*) registry_obj->data; + json_t* value; + + uint64_t result = 0; + size_t index; + + json_array_foreach(keys_json, index, value) + { + if (yr_re_match(context, regexp_argument(1), json_string_value(value)) > 0) + { + result = 1; + break; + } + } + + return_integer(result); +} + + +define_function(filesystem_file_access) +{ + YR_SCAN_CONTEXT* context = scan_context(); + YR_OBJECT* filesystem_obj = parent(); + + json_t* files_json = (json_t*) filesystem_obj->data; + json_t* value; + + uint64_t result = 0; + size_t index; + + json_array_foreach(files_json, index, value) + { + if (yr_re_match(context, regexp_argument(1), json_string_value(value)) > 0) + { + result = 1; + break; + } + } + + return_integer(result); +} + + + +define_function(sync_mutex) +{ + YR_SCAN_CONTEXT* context = scan_context(); + YR_OBJECT* sync_obj = parent(); + + json_t* mutexes_json = (json_t*) sync_obj->data; + json_t* value; + + uint64_t result = 0; + size_t index; + + json_array_foreach(mutexes_json, index, value) + { + if (yr_re_match(context, regexp_argument(1), json_string_value(value)) > 0) + { + result = 1; + break; + } + } + + return_integer(result); +} + + +begin_declarations; + + begin_struct("network"); + declare_function("dns_lookup", "r", "i", network_dns_lookup); + declare_function("http_get", "r", "i", network_http_get); + declare_function("http_post", "r", "i", network_http_post); + declare_function("http_request", "r", "i", network_http_request); + end_struct("network"); + + begin_struct("registry"); + declare_function("key_access", "r", "i", registry_key_access); + end_struct("registry"); + + begin_struct("filesystem"); + declare_function("file_access", "r", "i", filesystem_file_access); + end_struct("filesystem"); + + begin_struct("sync"); + declare_function("mutex", "r", "i", sync_mutex); + end_struct("sync"); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + YR_OBJECT* network_obj; + YR_OBJECT* registry_obj; + YR_OBJECT* filesystem_obj; + YR_OBJECT* sync_obj; + + json_error_t json_error; + + json_t* summary_json; + json_t* json; + + if (module_data == NULL) + return ERROR_SUCCESS; + + json = json_loadb( + (const char*) module_data, + module_data_size, + #if JANSSON_VERSION_HEX >= 0x020600 + JSON_ALLOW_NUL, + #else + 0, + #endif + &json_error); + + if (json == NULL) + return ERROR_INVALID_FILE; + + module_object->data = (void*) json; + + network_obj = get_object(module_object, "network"); + registry_obj = get_object(module_object, "registry"); + filesystem_obj = get_object(module_object, "filesystem"); + sync_obj = get_object(module_object, "sync"); + + network_obj->data = (void*) json_object_get(json, "network"); + + json = json_object_get(json, "behavior"); + summary_json = json_object_get(json, "summary"); + + registry_obj->data = (void*) json_object_get(summary_json, "keys"); + filesystem_obj->data = (void*) json_object_get(summary_json, "files"); + sync_obj->data = (void*) json_object_get(summary_json, "mutexes"); + + return ERROR_SUCCESS; +} + + +int module_unload(YR_OBJECT* module) +{ + if (module->data != NULL) + json_decref((json_t*) module->data); + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/demo.c b/yara-master/libyara/modules/demo.c new file mode 100644 index 0000000..af8a8e7 --- /dev/null +++ b/yara-master/libyara/modules/demo.c @@ -0,0 +1,71 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#define MODULE_NAME demo + +begin_declarations; + + declare_string("greeting"); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + set_string("Hello World!", module_object, "greeting"); + + return ERROR_SUCCESS; +} + + +int module_unload( + YR_OBJECT* module_object) +{ + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/dex.c b/yara-master/libyara/modules/dex.c new file mode 100644 index 0000000..8afa4d4 --- /dev/null +++ b/yara-master/libyara/modules/dex.c @@ -0,0 +1,1149 @@ +/* +Copyright (c) 2018. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#define _GNU_SOURCE + +#include + +#include +#include +#include +#include + +#define MODULE_NAME dex + +// DEX File layout information: +// https://source.android.com/devices/tech/dalvik/dex-format + +begin_declarations; + + declare_string("DEX_FILE_MAGIC_035"); + declare_string("DEX_FILE_MAGIC_036"); + declare_string("DEX_FILE_MAGIC_037"); + declare_string("DEX_FILE_MAGIC_038"); + + declare_integer("ENDIAN_CONSTANT"); + declare_integer("REVERSE_ENDIAN_CONSTANT"); + declare_integer("NO_INDEX"); + declare_integer("ACC_PUBLIC"); + declare_integer("ACC_PRIVATE"); + declare_integer("ACC_PROTECTED"); + declare_integer("ACC_STATIC"); + declare_integer("ACC_FINAL"); + declare_integer("ACC_SYNCHRONIZED"); + declare_integer("ACC_VOLATILE"); + declare_integer("ACC_BRIDGE"); + declare_integer("ACC_TRANSIENT"); + declare_integer("ACC_VARARGS"); + declare_integer("ACC_NATIVE"); + declare_integer("ACC_INTERFACE"); + declare_integer("ACC_ABSTRACT"); + declare_integer("ACC_STRICT"); + declare_integer("ACC_SYNTHETIC"); + declare_integer("ACC_ANNOTATION"); + declare_integer("ACC_ENUM"); + declare_integer("ACC_CONSTRUCTOR"); + declare_integer("ACC_DECLARED_SYNCHRONIZED"); + + declare_integer("TYPE_HEADER_ITEM"); + declare_integer("TYPE_STRING_ID_ITEM"); + declare_integer("TYPE_TYPE_ID_ITEM"); + declare_integer("TYPE_PROTO_ID_ITEM"); + declare_integer("TYPE_FIELD_ID_ITEM"); + declare_integer("TYPE_METHOD_ID_ITEM"); + declare_integer("TYPE_CLASS_DEF_ITEM"); + declare_integer("TYPE_CALL_SITE_ID_ITEM"); + declare_integer("TYPE_METHOD_HANDLE_ITEM"); + declare_integer("TYPE_MAP_LIST"); + declare_integer("TYPE_TYPE_LIST"); + declare_integer("TYPE_ANNOTATION_SET_REF_LIST"); + declare_integer("TYPE_ANNOTATION_SET_ITEM"); + declare_integer("TYPE_CLASS_DATA_ITEM"); + declare_integer("TYPE_CODE_ITEM"); + declare_integer("TYPE_STRING_DATA_ITEM"); + declare_integer("TYPE_DEBUG_INFO_ITEM"); + declare_integer("TYPE_ANNOTATION_ITEM"); + declare_integer("TYPE_ENCODED_ARRAY_ITEM"); + declare_integer("TYPE_ANNOTATIONS_DIRECTORY_ITEM"); + + begin_struct("header"); + declare_string("magic"); + declare_integer("checksum"); + declare_string("signature"); + declare_integer("file_size"); + declare_integer("header_size"); + declare_integer("endian_tag"); + declare_integer("link_size"); + declare_integer("link_offset"); + declare_integer("map_offset"); + declare_integer("string_ids_size"); + declare_integer("string_ids_offset"); + declare_integer("type_ids_size"); + declare_integer("type_ids_offset"); + declare_integer("proto_ids_size"); + declare_integer("proto_ids_offset"); + declare_integer("field_ids_size"); + declare_integer("field_ids_offset"); + declare_integer("method_ids_size"); + declare_integer("method_ids_offset"); + declare_integer("class_defs_size"); + declare_integer("class_defs_offset"); + declare_integer("data_size"); + declare_integer("data_offset"); + end_struct("header"); + + begin_struct_array("string_ids"); + declare_integer("offset"); + declare_integer("size"); + declare_string("value"); + end_struct_array("string_ids"); + + begin_struct_array("type_ids"); + declare_integer("descriptor_idx"); + end_struct_array("type_ids"); + + begin_struct_array("proto_ids"); + declare_integer("shorty_idx"); + declare_integer("return_type_idx"); + declare_integer("parameters_offset"); + end_struct_array("proto_ids"); + + begin_struct_array("field_ids"); + declare_integer("class_idx"); + declare_integer("type_idx"); + declare_integer("name_idx"); + end_struct_array("field_ids"); + + begin_struct_array("method_ids"); + declare_integer("class_idx"); + declare_integer("proto_idx"); + declare_integer("name_idx"); + end_struct_array("method_ids"); + + begin_struct_array("class_defs"); + declare_integer("class_idx"); + declare_integer("access_flags"); + declare_integer("superclass_idx"); + declare_integer("interfaces_offset"); + declare_integer("source_file_idx"); + declare_integer("annotations_offset"); + declare_integer("class_data_offset"); + declare_integer("static_values_offset"); + end_struct_array("class_defs"); + + begin_struct_array("class_data_item"); + declare_integer("static_fields_size"); + declare_integer("instance_fields_size"); + declare_integer("direct_methods_size"); + declare_integer("virtual_methods_size"); + end_struct_array("class_data_item"); + + begin_struct("map_list"); + declare_integer("size"); + begin_struct_array("map_item"); + declare_integer("type"); + declare_integer("unused"); + declare_integer("size"); + declare_integer("offset"); + end_struct_array("map_item"); + end_struct("map_list"); + + declare_integer("number_of_fields"); + begin_struct_array("field"); + declare_string("class_name"); + declare_string("name"); + declare_string("proto"); + + declare_integer("field_idx_diff"); + declare_integer("access_flags"); + end_struct_array("field"); + + declare_integer("number_of_methods"); + begin_struct_array("method"); + declare_string("class_name"); + declare_string("name"); + declare_string("proto"); + declare_integer("direct"); + declare_integer("virtual"); + + declare_integer("method_idx_diff"); + declare_integer("access_flags"); + declare_integer("code_off"); + begin_struct("code_item"); + declare_integer("registers_size"); + declare_integer("ins_size"); + declare_integer("outs_size"); + declare_integer("tries_size"); + declare_integer("debug_info_off"); + declare_integer("insns_size"); + declare_string("insns"); + declare_integer("padding"); + begin_struct("tries"); + end_struct("tries"); + begin_struct_array("handlers"); + end_struct_array("handlers"); + end_struct("code_item"); + end_struct_array("method"); + +end_declarations; + +// https://android.googlesource.com/platform/dalvik/+/android-4.4.2_r2/libdex/Leb128.cpp + +int32_t read_uleb128( + const uint8_t* pStream, + uint32_t *size) +{ + const uint8_t* ptr = pStream; + + int32_t result = *(ptr++); + *size = *size + 1; + + if (result > 0x7f) + { + int cur = *(ptr++); + *size = *size + 1; + result = (result & 0x7f) | ((cur & 0x7f) << 7); + + if (cur > 0x7f) + { + cur = *(ptr++); + *size = *size + 1; + result |= (cur & 0x7f) << 14; + + if (cur > 0x7f) + { + cur = *(ptr++); + *size = *size + 1; + result |= (cur & 0x7f) << 21; + + if (cur > 0x7f) + { + /* + * Note: We don't check to see if cur is out of + * range here, meaning we tolerate garbage in the + * high four-order bits. + */ + cur = *(ptr++); + *size = *size + 1; + result |= cur << 28; + } + } + } + } + + return result; +} + + +dex_header_t* dex_get_header( + const uint8_t* data, + size_t data_size) +{ + dex_header_t* dex_header; + + if (data_size < sizeof(dex_header_t)) + return NULL; + + // Check if we have a valid DEX file + dex_header = (dex_header_t*) data; + + if (memcmp(dex_header->magic, DEX_FILE_MAGIC_035, 8) != 0 && + memcmp(dex_header->magic, DEX_FILE_MAGIC_036, 8) != 0 && + memcmp(dex_header->magic, DEX_FILE_MAGIC_037, 8) != 0 && + memcmp(dex_header->magic, DEX_FILE_MAGIC_038, 8) != 0) + { + return NULL; + } + + return dex_header; +} + +void dex_parse_header( + dex_header_t* dex_header, + YR_OBJECT* module_object) +{ + set_sized_string( + (char*) dex_header->magic, + strnlen((char*) dex_header->magic, 8 * sizeof(char)), + module_object, + "header.magic"); + + set_integer( + dex_header->checksum, + module_object, + "header.checksum"); + + set_sized_string( + (char*) dex_header->signature, + strnlen((char *) dex_header->signature, 20 * sizeof(char)), + module_object, + "header.signature"); + + set_integer(dex_header->file_size, module_object, + "header.file_size"); + set_integer(dex_header->header_size, module_object, + "header.header_size"); + set_integer(dex_header->endian_tag, module_object, + "header.endian_tag"); + set_integer(dex_header->link_size, module_object, + "header.link_size"); + set_integer(dex_header->link_offset, module_object, + "header.link_offset"); + set_integer(dex_header->map_offset, module_object, + "header.map_offset"); + set_integer(dex_header->string_ids_size, module_object, + "header.string_ids_size"); + set_integer(dex_header->string_ids_offset, module_object, + "header.string_ids_offset"); + set_integer(dex_header->type_ids_size, module_object, + "header.type_ids_size"); + set_integer(dex_header->type_ids_offset, module_object, + "header.type_ids_offset"); + set_integer(dex_header->proto_ids_size, module_object, + "header.proto_ids_size"); + set_integer(dex_header->proto_ids_offset, module_object, + "header.proto_ids_offset"); + set_integer(dex_header->field_ids_size, module_object, + "header.field_ids_size"); + set_integer(dex_header->field_ids_offset, module_object, + "header.field_ids_offset"); + set_integer(dex_header->method_ids_size, module_object, + "header.method_ids_size"); + set_integer(dex_header->method_ids_offset, module_object, + "header.method_ids_offset"); + set_integer(dex_header->class_defs_size, module_object, + "header.class_defs_size"); + set_integer(dex_header->class_defs_offset, module_object, + "header.class_defs_offset"); + set_integer(dex_header->data_size, module_object, + "header.data_size"); + set_integer(dex_header->data_offset, module_object, + "header.data_offset"); +} + +uint32_t load_encoded_field( + DEX* dex, + size_t start_offset, + uint32_t *previous_field_idx, + int index_encoded_field, + int static_field, + int instance_field) +{ + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse encoded field start_offset:0x%zx\n", start_offset); + #endif + + if (!fits_in_dex(dex, dex->data + start_offset, sizeof(uint32_t) * 2)) + return 0; + + uint32_t current_size = 0; + + encoded_field_t encoded_field; + + encoded_field.field_idx_diff = (uint32_t) read_uleb128( + (dex->data + start_offset + current_size), ¤t_size); + + encoded_field.access_flags = (uint32_t) read_uleb128( + (dex->data + start_offset + current_size), ¤t_size); + + *previous_field_idx = encoded_field.field_idx_diff + *previous_field_idx; + + set_integer( + encoded_field.field_idx_diff, + dex->object, + "field[%i].field_idx_diff", + index_encoded_field); + + set_integer( + encoded_field.access_flags, + dex->object, + "field[%i].access_flags", + index_encoded_field); + + set_integer( + static_field, + dex->object, + "field[%i].static", + index_encoded_field); + + set_integer( + instance_field, + dex->object, + "field[%i].instance", + index_encoded_field); + + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tEncoded field field_idx:0x%x field_idx_diff:0x%x access_flags:0x%x\n", + *previous_field_idx, + encoded_field.field_idx_diff, + encoded_field.access_flags); + #endif + + uint32_t name_idx = get_integer( + dex->object, "field_ids[%i].name_idx", *previous_field_idx); + + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tNAME_IDX 0x%x\n", name_idx); + #endif + + SIZED_STRING* field_name = get_string( + dex->object, "string_ids[%i].value", name_idx); + + if (field_name != NULL) + { + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tFIELD_NAME %s NAME_IDX 0x%x\n", + field_name->c_string, + name_idx); + #endif + + set_sized_string( + field_name->c_string, + field_name->length, + dex->object, + "field[%i].name", + index_encoded_field); + } + + uint32_t class_idx = get_integer( + dex->object, "field_ids[%i].class_idx", *previous_field_idx); + + uint32_t descriptor_idx = get_integer( + dex->object, "type_ids[%i].descriptor_idx", class_idx); + + SIZED_STRING* class_name = get_string( + dex->object, "string_ids[%i].value", descriptor_idx); + + if (class_name != NULL) + { + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tCLASS_NAME %s CLASS_IDX 0x%x DESCRIPTOR_IDX 0x%x\n", + class_name->c_string, + class_idx, + descriptor_idx); + #endif + + set_sized_string( + class_name->c_string, + class_name->length, + dex->object, + "field[%i].class_name", + index_encoded_field); + } + + uint32_t type_idx = get_integer(dex->object, + "field_ids[%i].type_idx", *previous_field_idx); + + uint32_t shorty_idx = get_integer(dex->object, + "type_ids[%i].descriptor_idx", type_idx); + + SIZED_STRING* proto_name = get_string(dex->object, + "string_ids[%i].value", shorty_idx); + + if (proto_name != NULL) + { + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tPROTO_NAME %s TYPE_IDX 0x%x SHORTY_IDX 0x%x\n", + proto_name->c_string, + type_idx, + shorty_idx); + #endif + + set_sized_string( + proto_name->c_string, + proto_name->length, + dex->object, + "field[%i].proto", + index_encoded_field); + } + + return current_size; +} + +uint32_t load_encoded_method( + DEX* dex, + size_t start_offset, + uint32_t *previous_method_idx, + int index_encoded_method, + int direct_method, + int virtual_method) +{ + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse encoded method start_offset:0x%zx\n", start_offset); + #endif + + if (!fits_in_dex(dex, dex->data + start_offset, sizeof(uint32_t) * 3)) + return 0; + + uint32_t current_size = 0; + encoded_method_t encoded_method; + + encoded_method.method_idx_diff = (uint32_t) read_uleb128( + (dex->data + start_offset + current_size), ¤t_size); + + encoded_method.access_flags = (uint32_t) read_uleb128( + (dex->data + start_offset + current_size), ¤t_size); + + encoded_method.code_off = (uint32_t) read_uleb128( + (dex->data + start_offset + current_size), ¤t_size); + + *previous_method_idx = encoded_method.method_idx_diff + *previous_method_idx; + + set_integer( + encoded_method.method_idx_diff, + dex->object, + "method[%i].method_idx_diff", + index_encoded_method); + + set_integer( + encoded_method.access_flags, + dex->object, + "method[%i].access_flags", + index_encoded_method); + + set_integer( + encoded_method.code_off, + dex->object, + "method[%i].code_off", + index_encoded_method); + + set_integer( + direct_method, + dex->object, + "method[%i].direct", + index_encoded_method); + + set_integer( + virtual_method, + dex->object, + "method[%i].virtual", + index_encoded_method); + + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tEncoded method method_idx:0x%x method_idx_diff:0x%x access_flags:0x%x code_off:0x%x\n", + *previous_method_idx, + encoded_method.method_idx_diff, + encoded_method.access_flags, + encoded_method.code_off); + #endif + + uint32_t name_idx = get_integer( + dex->object, "method_ids[%i].name_idx", *previous_method_idx); + + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tNAME_IDX 0x%x\n", name_idx); + #endif + + SIZED_STRING* method_name = get_string( + dex->object, "string_ids[%i].value", name_idx); + + if (method_name != NULL) + { + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tMETHOD_NAME %s NAME_IDX 0x%x\n", + method_name->c_string, + name_idx); + #endif + + set_sized_string( + method_name->c_string, + method_name->length, + dex->object, + "method[%i].name", + index_encoded_method); + } + + uint32_t class_idx = get_integer( + dex->object, "method_ids[%i].class_idx", *previous_method_idx); + + uint32_t descriptor_idx = get_integer( + dex->object, "type_ids[%i].descriptor_idx", class_idx); + + SIZED_STRING* class_name = get_string( + dex->object, "string_ids[%i].value", descriptor_idx); + + if (class_name != NULL) + { + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tCLASS_NAME %s CLASS_IDX 0x%x DESCRIPTOR_IDX:0x%x\n", + class_name->c_string, + class_idx, + descriptor_idx); + #endif + + set_sized_string( + class_name->c_string, + class_name->length, + dex->object, + "method[%i].class_name", + index_encoded_method); + } + + uint32_t proto_idx = get_integer( + dex->object, "method_ids[%i].proto_idx", *previous_method_idx); + + uint32_t shorty_idx = get_integer( + dex->object, "proto_ids[%i].shorty_idx", proto_idx); + + SIZED_STRING* proto_name = get_string( + dex->object, "string_ids[%i].value", shorty_idx); + + if (proto_name != NULL) + { + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\tPROTO_NAME %s CLASS_IDX 0x%x DESCRIPTOR_IDX:0x%x\n", + proto_name->c_string, + class_idx, + descriptor_idx); + #endif + + set_sized_string( + proto_name->c_string, + proto_name->length, dex->object, + "method[%i].proto", + index_encoded_method); + } + + if (encoded_method.code_off != 0) + { + #ifdef DEBUG_DEX_MODULE + printf("[DEX]\t\tParse CODE item\n"); + #endif + + if (struct_fits_in_dex( + dex, dex->data + encoded_method.code_off, sizeof(code_item_t))) + { + code_item_t* code_item = (code_item_t*) ( + dex->data + encoded_method.code_off); + + set_integer(code_item->registers_size, dex->object, + "method[%i].code_item.registers_size", index_encoded_method); + set_integer(code_item->ins_size, dex->object, + "method[%i].code_item.ins_size", index_encoded_method); + set_integer(code_item->outs_size, dex->object, + "method[%i].code_item.outs_size", index_encoded_method); + set_integer(code_item->tries_size, dex->object, + "method[%i].code_item.tries_size", index_encoded_method); + set_integer(code_item->debug_info_off, dex->object, + "method[%i].code_item.debug_info_off", index_encoded_method); + set_integer(code_item->insns_size, dex->object, + "method[%i].code_item.insns_size", index_encoded_method); + + if (fits_in_dex( + dex, + dex->data + encoded_method.code_off + sizeof(code_item_t), + code_item->insns_size * 2)) + { + set_sized_string( + (const char *)(dex->data + encoded_method.code_off + sizeof(code_item_t)), + code_item->insns_size * 2, + dex->object, "method[%i].code_item.insns", index_encoded_method); + } + } + } + + return current_size; +} + +void dex_parse( + DEX* dex, + size_t base_address) +{ + dex_header_t* dex_header; + + int i, j; + + uint32_t uleb128_size = 0; + uint32_t index_class_data_item = 0; + uint32_t index_encoded_method = 0; + uint32_t index_encoded_field = 0; + + if (!struct_fits_in_dex(dex, dex->data, dex_header_t)) + return; + + dex_parse_header(dex->header, dex->object); + + dex_header = dex->header; + + if (!fits_in_dex(dex, dex->data + dex_header->string_ids_offset, + dex_header->string_ids_size * sizeof(string_id_item_t))) + return; + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse STRING ID section\n"); + #endif + + // Get information about the String ID section + for (i = 0; i < dex_header->string_ids_size; i++) + { + string_id_item_t* string_id_item = (string_id_item_t*) ( + dex->data + + dex_header->string_ids_offset + + i * sizeof(string_id_item_t)); + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] STRING ID item data_offset:0x%x\n", + string_id_item->string_data_offset); + #endif + + if (!fits_in_dex(dex, dex->data + string_id_item->string_data_offset, + sizeof(uint32_t))) + continue; + + uint32_t value = (uint32_t)read_uleb128( + (dex->data + string_id_item->string_data_offset), &uleb128_size); + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] STRING ID item size:0x%x\n", value); + #endif + + if (!fits_in_dex(dex, dex->data + string_id_item->string_data_offset, + value)) + continue; + + set_integer( + string_id_item->string_data_offset, dex->object, + "string_ids[%i].offset", i); + + set_integer(string_id_item->string_data_offset, dex->object, + "string_ids[%i].size", value); + + set_sized_string( + (const char*)((dex->data + string_id_item->string_data_offset + 1)), + value, + dex->object, + "string_ids[%i].value", + i); + } + + if (!fits_in_dex(dex, dex->data + dex_header->type_ids_offset, + dex_header->type_ids_size * sizeof(type_id_item_t))) + return; + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse TYPE ID section\n"); + #endif + + // Get information about the Type ID section + for (i = 0; i < dex_header->type_ids_size; i++) + { + type_id_item_t* type_id_item = (type_id_item_t*) ( + dex->data + dex_header->type_ids_offset + i * sizeof(type_id_item_t)); + + set_integer( + type_id_item->descriptor_idx, + dex->object, + "type_ids[%i].descriptor_idx", + i); + } + + if (!fits_in_dex(dex, dex->data + dex_header->proto_ids_offset, + dex_header->proto_ids_size * sizeof(proto_id_item_t))) + return; + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse PROTO ID section\n"); + #endif + + // Get information about the Proto ID section + for (i = 0; i < dex_header->proto_ids_size; i++) + { + proto_id_item_t* proto_id_item = (proto_id_item_t*) ( + dex->data + dex_header->proto_ids_offset + i * sizeof(proto_id_item_t)); + + set_integer(proto_id_item->shorty_idx, dex->object, + "proto_ids[%i].shorty_idx", i); + set_integer(proto_id_item->return_type_idx, dex->object, + "proto_ids[%i].return_type_idx", i); + set_integer(proto_id_item->parameters_offset, dex->object, + "proto_ids[%i].parameters_offset", i); + } + + if (!fits_in_dex(dex, dex->data + dex_header->field_ids_offset, + dex_header->field_ids_size * sizeof(field_id_item_t))) + return; + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse FIELD ID section\n"); + #endif + + // Get information about the Field ID section + for (i = 0; i < dex_header->field_ids_size; i++) + { + field_id_item_t* field_id_item = (field_id_item_t*) ( + dex->data + dex_header->field_ids_offset + i * sizeof(field_id_item_t)); + + set_integer(field_id_item->class_idx, dex->object, + "field_ids[%i].class_idx", i); + set_integer(field_id_item->type_idx, dex->object, + "field_ids[%i].type_idx", i); + set_integer(field_id_item->name_idx, dex->object, + "field_ids[%i].name_idx", i); + } + + if (!fits_in_dex(dex, dex->data + dex_header->method_ids_offset, + dex_header->method_ids_size * sizeof(method_id_item_t))) + return; + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse METHOD ID section\n"); + #endif + + // Get information about the Method ID section + for (i = 0; i < dex_header->method_ids_size; i++) + { + method_id_item_t* method_id_item = (method_id_item_t*) ( + dex->data + + dex_header->method_ids_offset + + i * sizeof(method_id_item_t)); + + set_integer(method_id_item->class_idx, dex->object, + "method_ids[%i].class_idx", i); + set_integer(method_id_item->proto_idx, dex->object, + "method_ids[%i].proto_idx", i); + set_integer(method_id_item->name_idx, dex->object, + "method_ids[%i].name_idx", i); + } + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse MAP List ID section\n"); + #endif + + // Get information about the Map List ID section + if (dex_header->map_offset != 0 && + fits_in_dex(dex, dex->data + dex_header->map_offset, sizeof(uint32_t))) + { + uint32_t* map_list_size = (uint32_t *) (dex->data + dex_header->map_offset); + + set_integer(*map_list_size, dex->object, "map_list.size"); + + if (!fits_in_dex(dex, dex->data + dex_header->map_offset, + sizeof(uint32_t) + *map_list_size * sizeof(map_item_t))) + return; + + for (i = 0; i < *map_list_size; i++) + { + map_item_t* map_item = (map_item_t*) ( + dex->data + + dex_header->map_offset + + sizeof(uint32_t) + + i * sizeof(map_item_t)); + + set_integer(map_item->type, dex->object, + "map_list.map_item[%i].type", i); + set_integer(map_item->unused, dex->object, + "map_list.map_item[%i].unused", i); + set_integer(map_item->size, dex->object, + "map_list.map_item[%i].size", i); + set_integer(map_item->offset, dex->object, + "map_list.map_item[%i].offset", i); + } + } + + if (!fits_in_dex(dex, dex->data + dex_header->class_defs_offset, + dex_header->class_defs_size * sizeof(class_id_item_t))) + return; + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] Parse CLASS ID section\n"); + #endif + + // Get information about the Class ID section + for (i = 0; i < dex_header->class_defs_size; i++) + { + class_id_item_t* class_id_item = (class_id_item_t*) ( + dex->data + + dex_header->class_defs_offset + + i * sizeof(class_id_item_t)); + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] CLASS ID item class_idx:0x%x access_flags:0x%x " \ + "super_class_idx:0x%x interfaces_off:0x%x source_file_idx:0x%x "\ + "annotations_offset:0x%x class_data_offset:0x%x "\ + "static_values_offset:0x%x\n", + class_id_item->class_idx, + class_id_item->access_flags, + class_id_item->super_class_idx, + class_id_item->interfaces_off, + class_id_item->source_file_idx, + class_id_item->annotations_offset, + class_id_item->class_data_offset, + class_id_item->static_values_offset); + #endif + + set_integer(class_id_item->class_idx, dex->object, + "class_defs[%i].class_idx", i); + set_integer(class_id_item->access_flags, dex->object, + "class_defs[%i].access_flags", i); + set_integer(class_id_item->super_class_idx, dex->object, + "class_defs[%i].super_class_idx", i); + set_integer(class_id_item->interfaces_off, dex->object, + "class_defs[%i].interfaces_off", i); + set_integer(class_id_item->source_file_idx, dex->object, + "class_defs[%i].source_file_idx", i); + set_integer(class_id_item->annotations_offset, dex->object, + "class_defs[%i].annotations_offset", i); + set_integer(class_id_item->class_data_offset, dex->object, + "class_defs[%i].class_data_off", i); + set_integer(class_id_item->static_values_offset, dex->object, + "class_defs[%i].static_values_offset", i); + + if (class_id_item->class_data_offset != 0) + { + class_data_item_t class_data_item; + + if (!fits_in_dex(dex, dex->data + class_id_item->class_data_offset, + 4 * sizeof(uint32_t))) + return; + + uleb128_size = 0; + + class_data_item.static_fields_size = (uint32_t) read_uleb128( + (dex->data + class_id_item->class_data_offset), + &uleb128_size); + + class_data_item.instance_fields_size = (uint32_t) read_uleb128( + (dex->data + class_id_item->class_data_offset + uleb128_size), + &uleb128_size); + + class_data_item.direct_methods_size = (uint32_t) read_uleb128( + (dex->data + class_id_item->class_data_offset + uleb128_size), + &uleb128_size); + + class_data_item.virtual_methods_size = (uint32_t) read_uleb128( + (dex->data + class_id_item->class_data_offset + uleb128_size), + &uleb128_size); + + set_integer( + class_data_item.static_fields_size, dex->object, + "class_data_item[%i].static_fields_size", index_class_data_item); + + set_integer( + class_data_item.instance_fields_size, dex->object, + "class_data_item[%i].instance_fields_size", index_class_data_item); + + set_integer( + class_data_item.direct_methods_size, dex->object, + "class_data_item[%i].direct_methods_size", index_class_data_item); + + set_integer( + class_data_item.virtual_methods_size, dex->object, + "class_data_item[%i].virtual_methods_size", index_class_data_item); + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] CLASS DATA item static fields\n"); + #endif + + uint32_t previous_field_idx = 0; + for (j = 0; j < class_data_item.static_fields_size; j++) + { + uleb128_size += load_encoded_field( + dex, + class_id_item->class_data_offset + uleb128_size, + &previous_field_idx, + index_encoded_field, + 1,0); + + index_encoded_field += 1; + } + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] CLASS DATA item instance fields\n"); + #endif + + previous_field_idx = 0; + for (j = 0; j < class_data_item.instance_fields_size; j++) + { + uleb128_size += load_encoded_field( + dex, + class_id_item->class_data_offset + uleb128_size, + &previous_field_idx, + index_encoded_field, + 0, 1); + + index_encoded_field += 1; + } + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] CLASS DATA item direct methods\n"); + #endif + + uint32_t previous_method_idx = 0; + for (j = 0; j < class_data_item.direct_methods_size; j++) + { + uleb128_size += load_encoded_method( + dex, + class_id_item->class_data_offset + uleb128_size, + &previous_method_idx, + index_encoded_method, + 1, 0); + + index_encoded_method += 1; + } + + #ifdef DEBUG_DEX_MODULE + printf("[DEX] CLASS DATA item virtual methods\n"); + #endif + + previous_method_idx = 0; + for (j = 0; j < class_data_item.virtual_methods_size; j++) + { + uleb128_size += load_encoded_method( + dex, + class_id_item->class_data_offset + uleb128_size, + &previous_method_idx, + index_encoded_method, + 0, 1); + + index_encoded_method += 1; + } + + index_class_data_item++; + } + } + + set_integer(index_encoded_method, dex->object, "number_of_methods"); + set_integer(index_encoded_field, dex->object, "number_of_fields"); +} + +int module_initialize(YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + +int module_finalize(YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + YR_MEMORY_BLOCK* block; + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + dex_header_t* dex_header; + + set_string(DEX_FILE_MAGIC_035, module_object, "DEX_FILE_MAGIC_035"); + set_string(DEX_FILE_MAGIC_036, module_object, "DEX_FILE_MAGIC_036"); + set_string(DEX_FILE_MAGIC_037, module_object, "DEX_FILE_MAGIC_037"); + set_string(DEX_FILE_MAGIC_038, module_object, "DEX_FILE_MAGIC_038"); + + set_integer(0x12345678, module_object, "ENDIAN_CONSTANT"); + set_integer(0x78563412, module_object, "REVERSE_ENDIAN_CONSTANT"); + + set_integer(0xffffffff, module_object, "NO_INDEX"); + set_integer(0x1, module_object, "ACC_PUBLIC"); + set_integer(0x2, module_object, "ACC_PRIVATE"); + set_integer(0x4, module_object, "ACC_PROTECTED"); + set_integer(0x8, module_object, "ACC_STATIC"); + set_integer(0x10, module_object, "ACC_FINAL"); + set_integer(0x20, module_object, "ACC_SYNCHRONIZED"); + set_integer(0x40, module_object, "ACC_VOLATILE"); + set_integer(0x40, module_object, "ACC_BRIDGE"); + set_integer(0x80, module_object, "ACC_TRANSIENT"); + set_integer(0x80, module_object, "ACC_VARARGS"); + set_integer(0x100, module_object, "ACC_NATIVE"); + set_integer(0x200, module_object, "ACC_INTERFACE"); + set_integer(0x400, module_object, "ACC_ABSTRACT"); + set_integer(0x800, module_object, "ACC_STRICT"); + set_integer(0x1000, module_object, "ACC_SYNTHETIC"); + set_integer(0x2000, module_object, "ACC_ANNOTATION"); + set_integer(0x4000, module_object, "ACC_ENUM"); + set_integer(0x10000, module_object, "ACC_CONSTRUCTOR"); + set_integer(0x20000, module_object, "ACC_DECLARED_SYNCHRONIZED"); + + set_integer(0x0000, module_object, "TYPE_HEADER_ITEM"); + set_integer(0x0001, module_object, "TYPE_STRING_ID_ITEM"); + set_integer(0x0002, module_object, "TYPE_TYPE_ID_ITEM"); + set_integer(0x0003, module_object, "TYPE_PROTO_ID_ITEM"); + set_integer(0x0004, module_object, "TYPE_FIELD_ID_ITEM"); + set_integer(0x0005, module_object, "TYPE_METHOD_ID_ITEM"); + set_integer(0x0006, module_object, "TYPE_CLASS_DEF_ITEM"); + set_integer(0x0007, module_object, "TYPE_CALL_SITE_ID_ITEM"); + set_integer(0x0008, module_object, "TYPE_METHOD_HANDLE_ITEM"); + set_integer(0x1000, module_object, "TYPE_MAP_LIST"); + set_integer(0x1001, module_object, "TYPE_TYPE_LIST"); + set_integer(0x1002, module_object, "TYPE_ANNOTATION_SET_REF_LIST"); + set_integer(0x1003, module_object, "TYPE_ANNOTATION_SET_ITEM"); + set_integer(0x2000, module_object, "TYPE_CLASS_DATA_ITEM"); + set_integer(0x2001, module_object, "TYPE_CODE_ITEM"); + set_integer(0x2002, module_object, "TYPE_STRING_DATA_ITEM"); + set_integer(0x2003, module_object, "TYPE_DEBUG_INFO_ITEM"); + set_integer(0x2004, module_object, "TYPE_ANNOTATION_ITEM"); + set_integer(0x2005, module_object, "TYPE_ENCODED_ARRAY_ITEM"); + set_integer(0x2006, module_object, "TYPE_ANNOTATIONS_DIRECTORY_ITEM"); + + foreach_memory_block(iterator, block) + { + const uint8_t* block_data = block->fetch_data(block); + + if (block_data == NULL) + continue; + + dex_header = dex_get_header(block_data, block->size); + + if (dex_header != NULL) + { + DEX* dex = (DEX*) yr_malloc(sizeof(DEX)); + + if (dex == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + dex->data = block_data; + dex->data_size = block->size; + dex->object = module_object; + dex->header = dex_header; + + module_object->data = dex; + + dex_parse(dex, block->base); + break; + } + } + + return ERROR_SUCCESS; +} + +int module_unload(YR_OBJECT* module_object) +{ + DEX* dex = (DEX*) module_object->data; + + if (dex == NULL) + return ERROR_SUCCESS; + + yr_free(dex); + + return ERROR_SUCCESS; +} + +#undef MODULE_NAME diff --git a/yara-master/libyara/modules/dotnet.c b/yara-master/libyara/modules/dotnet.c new file mode 100644 index 0000000..1fb1f0e --- /dev/null +++ b/yara-master/libyara/modules/dotnet.c @@ -0,0 +1,1738 @@ +/* +Copyright (c) 2015. The YARA Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MODULE_NAME dotnet + + +char* pe_get_dotnet_string( + PE* pe, + const uint8_t* string_offset, + DWORD string_index) +{ + size_t remaining; + + char* start; + char* eos; + + // Start of string must be within boundary + if (!(string_offset + string_index >= pe->data && + string_offset + string_index < pe->data + pe->data_size)) + return NULL; + + // Calculate how much until end of boundary, don't scan past that. + remaining = (pe->data + pe->data_size) - (string_offset + string_index); + + // Search for a NULL terminator from start of string, up to remaining. + start = (char*) (string_offset + string_index); + eos = (char*) memmem((void*) start, remaining, "\0", 1); + + if (eos == NULL) + return eos; + + return start; +} + + +uint32_t max_rows(int count, ...) +{ + va_list ap; + int i; + uint32_t biggest; + uint32_t x; + + if (count == 0) + return 0; + + va_start(ap, count); + biggest = va_arg(ap, uint32_t); + + for (i = 1; i < count; i++) + { + x = va_arg(ap, uint32_t); + biggest = (x > biggest) ? x : biggest; + } + + va_end(ap); + return biggest; +} + + +void dotnet_parse_guid( + PE* pe, + int64_t metadata_root, + PSTREAM_HEADER guid_header) +{ + // GUIDs are 16 bytes each, converted to hex format plus separators and NULL. + char guid[37]; + int i = 0; + + const uint8_t* guid_offset = pe->data + metadata_root + guid_header->Offset; + DWORD guid_size = guid_header->Size; + + // Parse GUIDs if we have them. + // GUIDs are 16 bytes each. + while (guid_size >= 16 && fits_in_pe(pe, guid_offset, 16)) + { + sprintf(guid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + *(uint32_t*) guid_offset, + *(uint16_t*) (guid_offset + 4), + *(uint16_t*) (guid_offset + 6), + *(guid_offset + 8), + *(guid_offset + 9), + *(guid_offset + 10), + *(guid_offset + 11), + *(guid_offset + 12), + *(guid_offset + 13), + *(guid_offset + 14), + *(guid_offset + 15)); + + guid[(16 * 2) + 4] = '\0'; + + set_string(guid, pe->object, "guids[%i]", i); + + i++; + guid_size -= 16; + } + + set_integer(i, pe->object, "number_of_guids"); +} + + +// Given an offset into a #US or #Blob stream, parse the entry at that position. +// The offset is relative to the start of the PE file. +BLOB_PARSE_RESULT dotnet_parse_blob_entry( + PE* pe, + const uint8_t* offset) +{ + BLOB_PARSE_RESULT result; + + // Blob size is encoded in the first 1, 2 or 4 bytes of the blob. + // + // If the high bit is not set the length is encoded in one byte. + // + // If the high 2 bits are 10 (base 2) then the length is encoded in + // the rest of the bits and the next byte. + // + // If the high 3 bits are 110 (base 2) then the length is encoded + // in the rest of the bits and the next 3 bytes. + // + // See ECMA-335 II.24.2.4 for details. + + // Make sure we have at least one byte. + + if (!fits_in_pe(pe, offset, 1)) + { + result.size = 0; + return result; + } + + if ((*offset & 0x80) == 0x00) + { + result.length = (DWORD) *offset; + result.size = 1; + } + else if ((*offset & 0xC0) == 0x80) + { + // Make sure we have one more byte. + if (!fits_in_pe(pe, offset, 2)) + { + result.size = 0; + return result; + } + + // Shift remaining 6 bits left by 8 and OR in the remaining byte. + result.length = ((*offset & 0x3F) << 8) | *(offset + 1); + result.size = 2; + } + else if (offset + 4 < pe->data + pe->data_size && (*offset & 0xE0) == 0xC0) + { + // Make sure we have 3 more bytes. + if (!fits_in_pe(pe, offset, 4)) + { + result.size = 0; + return result; + } + + result.length = ((*offset & 0x1F) << 24) | + (*(offset + 1) << 16) | + (*(offset + 2) << 8) | + *(offset + 3); + result.size = 4; + } + else + { + // Return a 0 size as an error. + result.size = 0; + } + + return result; +} + + +void dotnet_parse_us( + PE* pe, + int64_t metadata_root, + PSTREAM_HEADER us_header) +{ + BLOB_PARSE_RESULT blob_result; + int i = 0; + + const uint8_t* offset = pe->data + metadata_root + us_header->Offset; + const uint8_t* end_of_header = offset + us_header->Size; + + // Make sure end of header is not past end of PE, and the first entry MUST be + // a single NULL byte. + if (!fits_in_pe(pe, offset, us_header->Size) || *offset != 0x00) + return; + + offset++; + + while (offset < end_of_header) + { + blob_result = dotnet_parse_blob_entry(pe, offset); + + if (blob_result.size == 0 || !fits_in_pe(pe, offset, blob_result.length)) + { + set_integer(i, pe->object, "number_of_user_strings"); + return; + } + + offset += blob_result.size; + // Avoid empty strings, which usually happen as padding at the end of the + // stream. + + if (blob_result.length > 0) + { + set_sized_string( + (char*) offset, + blob_result.length, + pe->object, + "user_strings[%i]", + i); + + offset += blob_result.length; + i++; + } + } + + set_integer(i, pe->object, "number_of_user_strings"); +} + + +STREAMS dotnet_parse_stream_headers( + PE* pe, + int64_t offset, + int64_t metadata_root, + DWORD num_streams) +{ + PSTREAM_HEADER stream_header; + STREAMS headers; + + char *start; + char *eos; + char stream_name[DOTNET_STREAM_NAME_SIZE + 1]; + unsigned int i; + + memset(&headers, '\0', sizeof(STREAMS)); + + stream_header = (PSTREAM_HEADER) (pe->data + offset); + + for (i = 0; i < num_streams; i++) + { + if (!struct_fits_in_pe(pe, stream_header, STREAM_HEADER)) + break; + + start = (char*) stream_header->Name; + + if (!fits_in_pe(pe, start, DOTNET_STREAM_NAME_SIZE)) + break; + + eos = (char*) memmem((void*) start, DOTNET_STREAM_NAME_SIZE, "\0", 1); + + if (eos == NULL) + break; + + strncpy(stream_name, stream_header->Name, DOTNET_STREAM_NAME_SIZE); + stream_name[DOTNET_STREAM_NAME_SIZE] = '\0'; + + set_string(stream_name, + pe->object, "streams[%i].name", i); + // Offset is relative to metadata_root. + set_integer(metadata_root + stream_header->Offset, + pe->object, "streams[%i].offset", i); + set_integer(stream_header->Size, + pe->object, "streams[%i].size", i); + + // Store necessary bits to parse these later. Not all tables will be + // parsed, but are referenced from others. For example, the #Strings + // stream is referenced from various tables in the #~ heap. + // + // #- is not documented but it represents unoptimized metadata stream. It + // may contain additional tables such as FieldPtr, ParamPtr, MethodPtr or + // PropertyPtr for indirect referencing. We already take into account these + // tables and they do not interfere with anything we parse in this module. + + if ((strncmp(stream_name, "#~", 2) == 0 || + strncmp(stream_name, "#-", 2) == 0) && headers.tilde == NULL) + headers.tilde = stream_header; + else if (strncmp(stream_name, "#GUID", 5) == 0) + headers.guid = stream_header; + else if (strncmp(stream_name, "#Strings", 8) == 0 && headers.string == NULL) + headers.string = stream_header; + else if (strncmp(stream_name, "#Blob", 5) == 0) + headers.blob = stream_header; + else if (strncmp(stream_name, "#US", 3) == 0 && headers.us == NULL) + headers.us = stream_header; + + // Stream name is padded to a multiple of 4. + stream_header = (PSTREAM_HEADER) ((uint8_t*) stream_header + + sizeof(STREAM_HEADER) + + strlen(stream_name) + + 4 - (strlen(stream_name) % 4)); + } + + set_integer(i, pe->object, "number_of_streams"); + + return headers; +} + + +// This is the second pass through the data for #~. The first pass collects +// information on the number of rows for tables which have coded indexes. +// This pass uses that information and the index_sizes to parse the tables +// of interest. +// +// Because the indexes can vary in size depending upon the number of rows in +// other tables it is impossible to use static sized structures. To deal with +// this hardcode the sizes of each table based upon the documentation (for the +// static sized portions) and use the variable sizes accordingly. + +void dotnet_parse_tilde_2( + PE* pe, + PTILDE_HEADER tilde_header, + int64_t resource_base, + int64_t metadata_root, + ROWS rows, + INDEX_SIZES index_sizes, + PSTREAMS streams) +{ + PMODULE_TABLE module_table; + PASSEMBLY_TABLE assembly_table; + PASSEMBLYREF_TABLE assemblyref_table; + PMANIFESTRESOURCE_TABLE manifestresource_table; + PMODULEREF_TABLE moduleref_table; + PCUSTOMATTRIBUTE_TABLE customattribute_table; + PCONSTANT_TABLE constant_table; + DWORD resource_size, implementation; + + char *name; + char typelib[MAX_TYPELIB_SIZE + 1]; + unsigned int i; + int bit_check; + int matched_bits = 0; + + int64_t resource_offset; + uint32_t row_size, row_count, counter; + + const uint8_t* string_offset; + const uint8_t* blob_offset; + + uint32_t num_rows = 0; + uint32_t valid_rows = 0; + uint32_t* row_offset = NULL; + uint8_t* table_offset = NULL; + uint8_t* row_ptr = NULL; + + // These are pointers and row sizes for tables of interest to us for special + // parsing. For example, we are interested in pulling out any CustomAttributes + // that are GUIDs so we need to be able to walk these tables. To find GUID + // CustomAttributes you need to walk the CustomAttribute table and look for + // any row with a Parent that indexes into the Assembly table and Type indexes + // into the MemberRef table. Then you follow the index into the MemberRef + // table and check the Class to make sure it indexes into TypeRef table. If it + // does you follow that index and make sure the Name is "GuidAttribute". If + // all that is valid then you can take the Value from the CustomAttribute + // table to find out the index into the Blob stream and parse that. + // + // Luckily we can abuse the fact that the order of the tables is guaranteed + // consistent (though some may not exist, but if they do exist they must exist + // in a certain order). The order is defined by their position in the Valid + // member of the tilde_header structure. By the time we are parsing the + // CustomAttribute table we have already recorded the location of the TypeRef + // and MemberRef tables, so we can follow the chain back up from + // CustomAttribute through MemberRef to TypeRef. + + uint8_t* typeref_ptr = NULL; + uint8_t* memberref_ptr = NULL; + uint32_t typeref_row_size = 0; + uint32_t memberref_row_size = 0; + uint8_t* typeref_row = NULL; + uint8_t* memberref_row = NULL; + + DWORD type_index; + DWORD class_index; + BLOB_PARSE_RESULT blob_result; + DWORD blob_index; + DWORD blob_length; + + // These are used to determine the size of coded indexes, which are the + // dynamically sized columns for some tables. The coded indexes are + // documented in ECMA-335 Section II.24.2.6. + uint8_t index_size, index_size2; + + // Number of rows is the number of bits set to 1 in Valid. + // Should use this technique: + // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan + for (i = 0; i < 64; i++) + valid_rows += ((tilde_header->Valid >> i) & 0x01); + + row_offset = (uint32_t*) (tilde_header + 1); + table_offset = (uint8_t*) row_offset; + table_offset += sizeof(uint32_t) * valid_rows; + +#define DOTNET_STRING_INDEX(Name) \ + index_sizes.string == 2 ? Name.Name_Short : Name.Name_Long + + string_offset = pe->data + metadata_root + streams->string->Offset; + + // Now walk again this time parsing out what we care about. + for (bit_check = 0; bit_check < 64; bit_check++) + { + // If the Valid bit is not set for this table, skip it... + if (!((tilde_header->Valid >> bit_check) & 0x01)) + continue; + + // Make sure table_offset doesn't go crazy by inserting a large value + // for num_rows. For example edc05e49dd3810be67942b983455fd43 sets a + // large value for number of rows for the BIT_MODULE section. + if (!fits_in_pe(pe, table_offset, 1)) + return; + + num_rows = *(row_offset + matched_bits); + + // Those tables which exist, but that we don't care about must be + // skipped. + // + // Sadly, given the dynamic sizes of some columns we can not have well + // defined structures for all tables and use them accordingly. To deal + // with this manually move the table_offset pointer by the appropriate + // number of bytes as described in the documentation for each table. + // + // The table structures are documented in ECMA-335 Section II.22. + + switch (bit_check) + { + case BIT_MODULE: + module_table = (PMODULE_TABLE) table_offset; + + name = pe_get_dotnet_string(pe, + string_offset, + DOTNET_STRING_INDEX(module_table->Name)); + + if (name != NULL) + set_string(name, pe->object, "module_name"); + + table_offset += ( + 2 + index_sizes.string + (index_sizes.guid * 3)) * num_rows; + + break; + + case BIT_TYPEREF: + row_count = max_rows(4, + rows.module, + rows.moduleref, + rows.assemblyref, + rows.typeref); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + row_size = (index_size + (index_sizes.string * 2)); + typeref_row_size = row_size; + typeref_ptr = table_offset; + table_offset += row_size * num_rows; + break; + + case BIT_TYPEDEF: + row_count = max_rows(3, + rows.typedef_, + rows.typeref, + rows.typespec); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + table_offset += ( + 4 + (index_sizes.string * 2) + index_size + + index_sizes.field + index_sizes.methoddef) * num_rows; + break; + + case BIT_FIELDPTR: + // This one is not documented in ECMA-335. + table_offset += (index_sizes.field) * num_rows; + break; + + case BIT_FIELD: + table_offset += ( + 2 + (index_sizes.string) + index_sizes.blob) * num_rows; + break; + + case BIT_METHODDEFPTR: + // This one is not documented in ECMA-335. + table_offset += (index_sizes.methoddef) * num_rows; + break; + + case BIT_METHODDEF: + table_offset += ( + 4 + 2 + 2 + + index_sizes.string + + index_sizes.blob + + index_sizes.param) * num_rows; + break; + + case BIT_PARAM: + table_offset += (2 + 2 + index_sizes.string) * num_rows; + break; + + case BIT_INTERFACEIMPL: + row_count = max_rows(3, + rows.typedef_, + rows.typeref, + rows.typespec); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + table_offset += (index_sizes.typedef_ + index_size) * num_rows; + break; + + case BIT_MEMBERREF: + row_count = max_rows(4, + rows.methoddef, + rows.moduleref, + rows.typeref, + rows.typespec); + + if (row_count > (0xFFFF >> 0x03)) + index_size = 4; + else + index_size = 2; + + row_size = (index_size + index_sizes.string + index_sizes.blob); + memberref_row_size = row_size; + memberref_ptr = table_offset; + table_offset += row_size * num_rows; + break; + + case BIT_CONSTANT: + row_count = max_rows(3, rows.param, rows.field, rows.property); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + // Using 'i' is insufficent since we may skip certain constants and + // it would give an inaccurate count in that case. + counter = 0; + row_size = (1 + 1 + index_size + index_sizes.blob); + row_ptr = table_offset; + + for (i = 0; i < num_rows; i++) + { + if (!fits_in_pe(pe, row_ptr, row_size)) + break; + + constant_table = (PCONSTANT_TABLE) row_ptr; + + // Only look for constants of type string. + if (constant_table->Type != ELEMENT_TYPE_STRING) + { + row_ptr += row_size; + continue; + } + + // Get the blob offset and pull it out of the blob table. + blob_offset = ((uint8_t*) constant_table) + 2 + index_size; + + if (index_sizes.blob == 4) + blob_index = *(DWORD*) blob_offset; + else + // Cast the value (index into blob table) to a 32bit value. + blob_index = (DWORD) (*(WORD*) blob_offset); + + // Everything checks out. Make sure the index into the blob field + // is valid (non-null and within range). + blob_offset = \ + pe->data + metadata_root + + streams->blob->Offset + blob_index; + + blob_result = dotnet_parse_blob_entry(pe, blob_offset); + + if (blob_result.size == 0) + { + row_ptr += row_size; + continue; + } + + blob_length = blob_result.length; + blob_offset += blob_result.size; + + // Quick sanity check to make sure the blob entry is within bounds. + if (blob_offset + blob_length >= pe->data + pe->data_size) + { + row_ptr += row_size; + continue; + } + + set_sized_string( + (char*) blob_offset, + blob_result.length, + pe->object, + "constants[%i]", + counter); + + counter++; + row_ptr += row_size; + } + + set_integer(counter, pe->object, "number_of_constants"); + table_offset += row_size * num_rows; + break; + + case BIT_CUSTOMATTRIBUTE: + // index_size is size of the parent column. + row_count = max_rows(21, + rows.methoddef, + rows.field, + rows.typeref, + rows.typedef_, + rows.param, + rows.interfaceimpl, + rows.memberref, + rows.module, + rows.property, + rows.event, + rows.standalonesig, + rows.moduleref, + rows.typespec, + rows.assembly, + rows.assemblyref, + rows.file, + rows.exportedtype, + rows.manifestresource, + rows.genericparam, + rows.genericparamconstraint, + rows.methodspec); + + if (row_count > (0xFFFF >> 0x05)) + index_size = 4; + else + index_size = 2; + + // index_size2 is size of the type column. + row_count = max_rows(2, + rows.methoddef, + rows.memberref); + + if (row_count > (0xFFFF >> 0x03)) + index_size2 = 4; + else + index_size2 = 2; + + row_size = (index_size + index_size2 + index_sizes.blob); + + if (typeref_ptr != NULL && memberref_ptr != NULL) + { + row_ptr = table_offset; + + for (i = 0; i < num_rows; i++) + { + if (!fits_in_pe(pe, row_ptr, row_size)) + break; + + // Check the Parent field. + customattribute_table = (PCUSTOMATTRIBUTE_TABLE) row_ptr; + + if (index_size == 4) + { + // Low 5 bits tell us what this is an index into. Remaining bits + // tell us the index value. + // Parent must be an index into the Assembly (0x0E) table. + if ((*(DWORD*) customattribute_table & 0x1F) != 0x0E) + { + row_ptr += row_size; + continue; + } + } + else + { + // Low 5 bits tell us what this is an index into. Remaining bits + // tell us the index value. + // Parent must be an index into the Assembly (0x0E) table. + if ((*(WORD*) customattribute_table & 0x1F) != 0x0E) + { + row_ptr += row_size; + continue; + } + } + + // Check the Type field. + customattribute_table = (PCUSTOMATTRIBUTE_TABLE) \ + (row_ptr + index_size); + + if (index_size2 == 4) + { + // Low 3 bits tell us what this is an index into. Remaining bits + // tell us the index value. Only values 2 and 3 are defined. + // Type must be an index into the MemberRef table. + if ((*(DWORD*) customattribute_table & 0x07) != 0x03) + { + row_ptr += row_size; + continue; + } + + type_index = *(DWORD*) customattribute_table >> 3; + } + else + { + // Low 3 bits tell us what this is an index into. Remaining bits + // tell us the index value. Only values 2 and 3 are defined. + // Type must be an index into the MemberRef table. + if ((*(WORD*) customattribute_table & 0x07) != 0x03) + { + row_ptr += row_size; + continue; + } + + // Cast the index to a 32bit value. + type_index = (DWORD) ((*(WORD*) customattribute_table >> 3)); + } + + if (type_index > 0) + type_index--; + + // Now follow the Type index into the MemberRef table. + memberref_row = memberref_ptr + (memberref_row_size * type_index); + + if (index_sizes.memberref == 4) + { + // Low 3 bits tell us what this is an index into. Remaining bits + // tell us the index value. Class must be an index into the + // TypeRef table. + if ((*(DWORD*) memberref_row & 0x07) != 0x01) + { + row_ptr += row_size; + continue; + } + + class_index = *(DWORD*) memberref_row >> 3; + } + else + { + // Low 3 bits tell us what this is an index into. Remaining bits + // tell us the index value. Class must be an index into the + // TypeRef table. + if ((*(WORD*) memberref_row & 0x07) != 0x01) + { + row_ptr += row_size; + continue; + } + + // Cast the index to a 32bit value. + class_index = (DWORD) (*(WORD*) memberref_row >> 3); + } + + if (class_index > 0) + class_index--; + + // Now follow the Class index into the TypeRef table. + typeref_row = typeref_ptr + (typeref_row_size * class_index); + + // Skip over the ResolutionScope and check the Name field, + // which is an index into the Strings heap. + row_count = max_rows(4, + rows.module, + rows.moduleref, + rows.assemblyref, + rows.typeref); + + if (row_count > (0xFFFF >> 0x02)) + typeref_row += 4; + else + typeref_row += 2; + + if (index_sizes.string == 4) + { + name = pe_get_dotnet_string( + pe, string_offset, *(DWORD*) typeref_row); + } + else + { + name = pe_get_dotnet_string( + pe, string_offset, *(WORD*) typeref_row); + } + + if (name != NULL && strncmp(name, "GuidAttribute", 13) != 0) + { + row_ptr += row_size; + continue; + } + + // Get the Value field. + customattribute_table = (PCUSTOMATTRIBUTE_TABLE) \ + (row_ptr + index_size + index_size2); + + if (index_sizes.blob == 4) + blob_index = *(DWORD*) customattribute_table; + else + // Cast the value (index into blob table) to a 32bit value. + blob_index = (DWORD) (*(WORD*) customattribute_table); + + // Everything checks out. Make sure the index into the blob field + // is valid (non-null and within range). + blob_offset = \ + pe->data + metadata_root + streams->blob->Offset + blob_index; + + // If index into blob is 0 or past the end of the blob stream, skip + // it. We don't know the size of the blob entry yet because that is + // encoded in the start. + if (blob_index == 0x00 || blob_offset >= pe->data + pe->data_size) + { + row_ptr += row_size; + continue; + } + + blob_result = dotnet_parse_blob_entry(pe, blob_offset); + + if (blob_result.size == 0) + { + row_ptr += row_size; + continue; + } + + blob_length = blob_result.length; + blob_offset += blob_result.size; + + // Quick sanity check to make sure the blob entry is within bounds. + if (blob_offset + blob_length >= pe->data + pe->data_size) + { + row_ptr += row_size; + continue; + } + + // Custom attributes MUST have a 16 bit prolog of 0x0001 + if (*(WORD*) blob_offset != 0x0001) + { + row_ptr += row_size; + continue; + } + + // The next byte is the length of the string. + blob_offset += 2; + + if (blob_offset + *blob_offset >= pe->data + pe->data_size) + { + row_ptr += row_size; + continue; + } + + blob_offset += 1; + + if (*blob_offset == 0xFF || *blob_offset == 0x00) + { + typelib[0] = '\0'; + } + else + { + strncpy(typelib, (char*) blob_offset, MAX_TYPELIB_SIZE); + typelib[MAX_TYPELIB_SIZE] = '\0'; + } + + set_string(typelib, pe->object, "typelib"); + + row_ptr += row_size; + } + } + + table_offset += row_size * num_rows; + break; + + case BIT_FIELDMARSHAL: + row_count = max_rows(2, + rows.field, + rows.param); + + if (row_count > (0xFFFF >> 0x01)) + index_size = 4; + else + index_size = 2; + + table_offset += (index_size + index_sizes.blob) * num_rows; + break; + + case BIT_DECLSECURITY: + row_count = max_rows(3, + rows.typedef_, + rows.methoddef, + rows.assembly); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + table_offset += (2 + index_size + index_sizes.blob) * num_rows; + break; + + case BIT_CLASSLAYOUT: + table_offset += (2 + 4 + index_sizes.typedef_) * num_rows; + break; + + case BIT_FIELDLAYOUT: + table_offset += (4 + index_sizes.field) * num_rows; + break; + + case BIT_STANDALONESIG: + table_offset += (index_sizes.blob) * num_rows; + break; + + case BIT_EVENTMAP: + table_offset += (index_sizes.typedef_ + index_sizes.event) * num_rows; + break; + + case BIT_EVENTPTR: + // This one is not documented in ECMA-335. + table_offset += (index_sizes.event) * num_rows; + break; + + case BIT_EVENT: + row_count = max_rows(3, + rows.typedef_, + rows.typeref, + rows.typespec); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + table_offset += (2 + index_sizes.string + index_size) * num_rows; + break; + + case BIT_PROPERTYMAP: + table_offset += (index_sizes.typedef_ + index_sizes.property) * num_rows; + break; + + case BIT_PROPERTYPTR: + // This one is not documented in ECMA-335. + table_offset += (index_sizes.property) * num_rows; + break; + + case BIT_PROPERTY: + table_offset += (2 + index_sizes.string + index_sizes.blob) * num_rows; + break; + + case BIT_METHODSEMANTICS: + row_count = max_rows(2, + rows.event, + rows.property); + + if (row_count > (0xFFFF >> 0x01)) + index_size = 4; + else + index_size = 2; + + table_offset += (2 + index_sizes.methoddef + index_size) * num_rows; + break; + + case BIT_METHODIMPL: + row_count = max_rows(2, + rows.methoddef, + rows.memberref); + + if (row_count > (0xFFFF >> 0x01)) + index_size = 4; + else + index_size = 2; + + table_offset += (index_sizes.typedef_ + (index_size * 2)) * num_rows; + break; + + case BIT_MODULEREF: + row_ptr = table_offset; + + // Can't use 'i' here because we only set the string if it is not + // NULL. Instead use 'counter'. + counter = 0; + + for (i = 0; i < num_rows; i++) + { + moduleref_table = (PMODULEREF_TABLE) row_ptr; + + name = pe_get_dotnet_string(pe, + string_offset, + DOTNET_STRING_INDEX(moduleref_table->Name)); + + if (name != NULL) + { + set_string(name, pe->object, "modulerefs[%i]", counter); + counter++; + } + + row_ptr += index_sizes.string; + } + + set_integer(counter, pe->object, "number_of_modulerefs"); + + table_offset += (index_sizes.string) * num_rows; + break; + + case BIT_TYPESPEC: + table_offset += (index_sizes.blob) * num_rows; + break; + + case BIT_IMPLMAP: + row_count = max_rows(2, + rows.field, + rows.methoddef); + + if (row_count > (0xFFFF >> 0x01)) + index_size = 4; + else + index_size = 2; + + table_offset += ( + 2 + index_size + index_sizes.string + + index_sizes.moduleref) * num_rows; + break; + + case BIT_FIELDRVA: + table_offset += (4 + index_sizes.field) * num_rows; + break; + + case BIT_ENCLOG: + table_offset += (4 + 4) * num_rows; + break; + + case BIT_ENCMAP: + table_offset += (4) * num_rows; + break; + + case BIT_ASSEMBLY: + row_size = ( + 4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob + + (index_sizes.string * 2)); + + if (!fits_in_pe(pe, table_offset, row_size)) + break; + + row_ptr = table_offset; + assembly_table = (PASSEMBLY_TABLE) table_offset; + + set_integer(assembly_table->MajorVersion, + pe->object, "assembly.version.major"); + set_integer(assembly_table->MinorVersion, + pe->object, "assembly.version.minor"); + set_integer(assembly_table->BuildNumber, + pe->object, "assembly.version.build_number"); + set_integer(assembly_table->RevisionNumber, + pe->object, "assembly.version.revision_number"); + + // Can't use assembly_table here because the PublicKey comes before + // Name and is a variable length field. + + if (index_sizes.string == 4) + name = pe_get_dotnet_string( + pe, + string_offset, + *(DWORD*) ( + row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + + index_sizes.blob)); + else + name = pe_get_dotnet_string( + pe, + string_offset, + *(WORD*) ( + row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + + index_sizes.blob)); + + if (name != NULL) + set_string(name, pe->object, "assembly.name"); + + // Culture comes after Name. + if (index_sizes.string == 4) + { + name = pe_get_dotnet_string( + pe, + string_offset, + *(DWORD*) ( + row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + + index_sizes.blob + + index_sizes.string)); + } + else + { + name = pe_get_dotnet_string( + pe, + string_offset, + *(WORD*) ( + row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + + index_sizes.blob + + index_sizes.string)); + } + + // Sometimes it will be a zero length string. This is technically + // against the specification but happens from time to time. + if (name != NULL && strlen(name) > 0) + set_string(name, pe->object, "assembly.culture"); + + table_offset += row_size * num_rows; + break; + + case BIT_ASSEMBLYPROCESSOR: + table_offset += (4) * num_rows; + break; + + case BIT_ASSEMBLYOS: + table_offset += (4 + 4 + 4) * num_rows; + break; + + case BIT_ASSEMBLYREF: + row_size = (2 + 2 + 2 + 2 + 4 + (index_sizes.blob * 2) + (index_sizes.string * 2)); + row_ptr = table_offset; + + for (i = 0; i < num_rows; i++) + { + if (!fits_in_pe(pe, table_offset, row_size)) + break; + + assemblyref_table = (PASSEMBLYREF_TABLE) row_ptr; + + set_integer(assemblyref_table->MajorVersion, + pe->object, "assembly_refs[%i].version.major", i); + set_integer(assemblyref_table->MinorVersion, + pe->object, "assembly_refs[%i].version.minor", i); + set_integer(assemblyref_table->BuildNumber, + pe->object, "assembly_refs[%i].version.build_number", i); + set_integer(assemblyref_table->RevisionNumber, + pe->object, "assembly_refs[%i].version.revision_number", i); + + blob_offset = pe->data + metadata_root + streams->blob->Offset; + + if (index_sizes.blob == 4) + blob_offset += \ + assemblyref_table->PublicKeyOrToken.PublicKeyOrToken_Long; + else + blob_offset += \ + assemblyref_table->PublicKeyOrToken.PublicKeyOrToken_Short; + + blob_result = dotnet_parse_blob_entry(pe, blob_offset); + + if (blob_result.size == 0 || + !fits_in_pe(pe, blob_offset, blob_result.length)) + { + row_ptr += row_size; + continue; + } + + // Avoid empty strings. + if (blob_result.length > 0) + { + blob_offset += blob_result.size; + set_sized_string((char*) blob_offset, + blob_result.length, pe->object, + "assembly_refs[%i].public_key_or_token", i); + } + + // Can't use assemblyref_table here because the PublicKey comes before + // Name and is a variable length field. + + if (index_sizes.string == 4) + name = pe_get_dotnet_string(pe, + string_offset, + *(DWORD*) (row_ptr + 2 + 2 + 2 + 2 + 4 + index_sizes.blob)); + else + name = pe_get_dotnet_string(pe, + string_offset, + *(WORD*) (row_ptr + 2 + 2 + 2 + 2 + 4 + index_sizes.blob)); + + if (name != NULL) + set_string(name, pe->object, "assembly_refs[%i].name", i); + + row_ptr += row_size; + } + + set_integer(i, pe->object, "number_of_assembly_refs"); + table_offset += row_size * num_rows; + break; + + case BIT_ASSEMBLYREFPROCESSOR: + table_offset += (4 + index_sizes.assemblyrefprocessor) * num_rows; + break; + + case BIT_ASSEMBLYREFOS: + table_offset += (4 + 4 + 4 + index_sizes.assemblyref) * num_rows; + break; + + case BIT_FILE: + table_offset += (4 + index_sizes.string + index_sizes.blob) * num_rows; + break; + + case BIT_EXPORTEDTYPE: + row_count = max_rows(3, rows.file, rows.assemblyref, rows.exportedtype); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + table_offset += (4 + 4 + (index_sizes.string * 2) + index_size) * num_rows; + break; + + case BIT_MANIFESTRESOURCE: + // This is an Implementation coded index with no 3rd bit specified. + row_count = max_rows(2, rows.file, rows.assemblyref); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + row_size = (4 + 4 + index_sizes.string + index_size); + + // Using 'i' is insufficent since we may skip certain resources and + // it would give an inaccurate count in that case. + counter = 0; + row_ptr = table_offset; + // First DWORD is the offset. + for (i = 0; i < num_rows; i++) + { + if (!fits_in_pe(pe, row_ptr, row_size)) + break; + + manifestresource_table = (PMANIFESTRESOURCE_TABLE) row_ptr; + resource_offset = manifestresource_table->Offset; + + // Only set offset if it is in this file (implementation != 0). + // Can't use manifestresource_table here because the Name and + // Implementation fields are variable size. + if (index_size == 4) + implementation = *(DWORD*) (row_ptr + 4 + 4 + index_sizes.string); + else + implementation = *(WORD*) (row_ptr + 4 + 4 + index_sizes.string); + + if (implementation != 0) + { + row_ptr += row_size; + continue; + } + + if (!fits_in_pe( + pe, + pe->data + resource_base + resource_offset, + sizeof(DWORD))) + { + row_ptr += row_size; + continue; + } + + resource_size = *(DWORD*)(pe->data + resource_base + resource_offset); + + if (!fits_in_pe( + pe, pe->data + resource_base + + resource_offset, + resource_size)) + { + row_ptr += row_size; + continue; + } + + // Add 4 to skip the size. + set_integer(resource_base + resource_offset + 4, + pe->object, "resources[%i].offset", counter); + + set_integer(resource_size, + pe->object, "resources[%i].length", counter); + + name = pe_get_dotnet_string(pe, + string_offset, + DOTNET_STRING_INDEX(manifestresource_table->Name)); + + if (name != NULL) + set_string(name, pe->object, "resources[%i].name", counter); + + row_ptr += row_size; + counter++; + } + + set_integer(counter, pe->object, "number_of_resources"); + + table_offset += row_size * num_rows; + break; + + case BIT_NESTEDCLASS: + table_offset += (index_sizes.typedef_ * 2) * num_rows; + break; + + case BIT_GENERICPARAM: + row_count = max_rows(2, rows.typedef_, rows.methoddef); + + if (row_count > (0xFFFF >> 0x01)) + index_size = 4; + else + index_size = 2; + + table_offset += (2 + 2 + index_size + index_sizes.string) * num_rows; + break; + + case BIT_METHODSPEC: + row_count = max_rows(2, rows.methoddef, rows.memberref); + + if (row_count > (0xFFFF >> 0x01)) + index_size = 4; + else + index_size = 2; + + table_offset += (index_size + index_sizes.blob) * num_rows; + break; + + case BIT_GENERICPARAMCONSTRAINT: + row_count = max_rows(3, rows.typedef_, rows.typeref, rows.typespec); + + if (row_count > (0xFFFF >> 0x02)) + index_size = 4; + else + index_size = 2; + + table_offset += (index_sizes.genericparam + index_size) * num_rows; + break; + + default: + //printf("Unknown bit: %i\n", bit_check); + return; + } + + matched_bits++; + } +} + + +// Parsing the #~ stream is done in two parts. The first part (this function) +// parses enough of the Stream to provide context for the second pass. In +// particular it is collecting the number of rows for each of the tables. The +// second part parses the actual tables of interest. + +void dotnet_parse_tilde( + PE* pe, + int64_t metadata_root, + PCLI_HEADER cli_header, + PSTREAMS streams) +{ + PTILDE_HEADER tilde_header; + int64_t resource_base; + uint32_t* row_offset = NULL; + + int bit_check; + + // This is used as an offset into the rows and tables. For every bit set in + // Valid this will be incremented. This is because the bit position doesn't + // matter, just the number of bits that are set, when determining how many + // rows and what the table structure is. + int matched_bits = 0; + + // We need to know the number of rows for some tables, because they are + // indexed into. The index will be either 2 or 4 bytes, depending upon the + // number of rows being indexed into. + ROWS rows; + INDEX_SIZES index_sizes; + + // Default all rows to 0. They will be set to actual values later on, if + // they exist in the file. + memset(&rows, '\0', sizeof(ROWS)); + + // Default index sizes are 2. Will be bumped to 4 if necessary. + memset(&index_sizes, 2, sizeof(index_sizes)); + + tilde_header = (PTILDE_HEADER) ( + pe->data + + metadata_root + + streams->tilde->Offset); + + if (!struct_fits_in_pe(pe, tilde_header, TILDE_HEADER)) + return; + + // Set index sizes for various heaps. + if (tilde_header->HeapSizes & 0x01) + index_sizes.string = 4; + if (tilde_header->HeapSizes & 0x02) + index_sizes.guid = 4; + if (tilde_header->HeapSizes & 0x04) + index_sizes.blob = 4; + + // Immediately after the tilde header is an array of 32bit values which + // indicate how many rows are in each table. The tables are immediately + // after the rows array. + // + // Save the row offset. + row_offset = (uint32_t*) (tilde_header + 1); + + // Walk all the bits first because we need to know the number of rows for + // some tables in order to parse others. In particular this applies to + // coded indexes, which are documented in ECMA-335 II.24.2.6. + for (bit_check = 0; bit_check < 64; bit_check++) + { + if (!((tilde_header->Valid >> bit_check) & 0x01)) + continue; + +#define ROW_CHECK(name) \ + if (fits_in_pe(pe, row_offset, (matched_bits + 1) * sizeof(uint32_t))) \ + rows.name = *(row_offset + matched_bits); + +#define ROW_CHECK_WITH_INDEX(name) \ + ROW_CHECK(name); \ + if (rows.name > 0xFFFF) \ + index_sizes.name = 4; + + switch (bit_check) + { + case BIT_MODULE: + ROW_CHECK(module); + break; + case BIT_MODULEREF: + ROW_CHECK_WITH_INDEX(moduleref); + break; + case BIT_ASSEMBLYREF: + ROW_CHECK_WITH_INDEX(assemblyref); + break; + case BIT_ASSEMBLYREFPROCESSOR: + ROW_CHECK_WITH_INDEX(assemblyrefprocessor); + break; + case BIT_TYPEREF: + ROW_CHECK(typeref); + break; + case BIT_METHODDEF: + ROW_CHECK_WITH_INDEX(methoddef); + break; + case BIT_MEMBERREF: + ROW_CHECK_WITH_INDEX(memberref); + break; + case BIT_TYPEDEF: + ROW_CHECK_WITH_INDEX(typedef_); + break; + case BIT_TYPESPEC: + ROW_CHECK(typespec); + break; + case BIT_FIELD: + ROW_CHECK_WITH_INDEX(field); + break; + case BIT_PARAM: + ROW_CHECK_WITH_INDEX(param); + break; + case BIT_PROPERTY: + ROW_CHECK_WITH_INDEX(property); + break; + case BIT_INTERFACEIMPL: + ROW_CHECK(interfaceimpl); + break; + case BIT_EVENT: + ROW_CHECK_WITH_INDEX(event); + break; + case BIT_STANDALONESIG: + ROW_CHECK(standalonesig); + break; + case BIT_ASSEMBLY: + ROW_CHECK(assembly); + break; + case BIT_FILE: + ROW_CHECK(file); + break; + case BIT_EXPORTEDTYPE: + ROW_CHECK(exportedtype); + break; + case BIT_MANIFESTRESOURCE: + ROW_CHECK(manifestresource); + break; + case BIT_GENERICPARAM: + ROW_CHECK_WITH_INDEX(genericparam); + break; + case BIT_GENERICPARAMCONSTRAINT: + ROW_CHECK(genericparamconstraint); + break; + case BIT_METHODSPEC: + ROW_CHECK(methodspec); + break; + default: + break; + } + + matched_bits++; + } + + // This is used when parsing the MANIFEST RESOURCE table. + resource_base = pe_rva_to_offset(pe, cli_header->Resources.VirtualAddress); + + dotnet_parse_tilde_2( + pe, + tilde_header, + resource_base, + metadata_root, + rows, + index_sizes, + streams); +} + + +void dotnet_parse_com( + PE* pe, + size_t base_address) +{ + PIMAGE_DATA_DIRECTORY directory; + PCLI_HEADER cli_header; + PNET_METADATA metadata; + int64_t metadata_root, offset; + char* end; + STREAMS headers; + WORD num_streams; + + directory = pe_get_directory_entry(pe, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR); + if (directory == NULL) + return; + + offset = pe_rva_to_offset(pe, directory->VirtualAddress); + + if (offset < 0 || !struct_fits_in_pe(pe, pe->data + offset, CLI_HEADER)) + return; + + cli_header = (PCLI_HEADER) (pe->data + offset); + + offset = metadata_root = pe_rva_to_offset( + pe, cli_header->MetaData.VirtualAddress); + + if (!struct_fits_in_pe(pe, pe->data + offset, NET_METADATA)) + return; + + metadata = (PNET_METADATA) (pe->data + offset); + + if (metadata->Magic != NET_METADATA_MAGIC) + return; + + // Version length must be between 1 and 255, and be a multiple of 4. + // Also make sure it fits in pe. + if (metadata->Length == 0 || + metadata->Length > 255 || + metadata->Length % 4 != 0 || + !fits_in_pe(pe, pe->data + offset, metadata->Length)) + { + return; + } + + // The length includes the NULL terminator and is rounded up to a multiple of + // 4. We need to exclude the terminator and the padding, so search for the + // first NULL byte. + end = (char*) memmem((void*) metadata->Version, metadata->Length, "\0", 1); + if (end != NULL) + set_sized_string(metadata->Version, + (end - metadata->Version), + pe->object, + "version"); + + // The metadata structure has some variable length records after the version. + // We must manually parse things from here on out. + // + // Flags are 2 bytes (always 0). + offset += sizeof(NET_METADATA) + metadata->Length + 2; + + // 2 bytes for Streams. + if (!fits_in_pe(pe, pe->data + offset, 2)) + return; + + num_streams = (WORD) *(pe->data + offset); + offset += 2; + + headers = dotnet_parse_stream_headers(pe, offset, metadata_root, num_streams); + + if (headers.guid != NULL) + dotnet_parse_guid(pe, metadata_root, headers.guid); + + // Parse the #~ stream, which includes various tables of interest. + // These tables reference the blob and string streams, so we need to ensure + // those are not NULL also. + if (headers.tilde != NULL && headers.string != NULL && headers.blob != NULL) + dotnet_parse_tilde(pe, metadata_root, cli_header, &headers); + + if (headers.us != NULL) + dotnet_parse_us(pe, metadata_root, headers.us); +} + + +begin_declarations; + + declare_string("version"); + declare_string("module_name"); + + begin_struct_array("streams"); + declare_string("name"); + declare_integer("offset"); + declare_integer("size"); + end_struct_array("streams"); + + declare_integer("number_of_streams"); + + declare_string_array("guids"); + declare_integer("number_of_guids"); + + begin_struct_array("resources"); + declare_integer("offset"); + declare_integer("length"); + declare_string("name"); + end_struct_array("resources"); + + declare_integer("number_of_resources"); + + begin_struct_array("assembly_refs"); + begin_struct("version"); + declare_integer("major"); + declare_integer("minor"); + declare_integer("build_number"); + declare_integer("revision_number"); + end_struct("version"); + declare_string("public_key_or_token"); + declare_string("name"); + end_struct_array("assembly_refs"); + + declare_integer("number_of_assembly_refs"); + + begin_struct("assembly"); + begin_struct("version"); + declare_integer("major"); + declare_integer("minor"); + declare_integer("build_number"); + declare_integer("revision_number"); + end_struct("version"); + declare_string("name"); + declare_string("culture"); + end_struct("assembly"); + + declare_string_array("modulerefs"); + declare_integer("number_of_modulerefs"); + declare_string_array("user_strings"); + declare_integer("number_of_user_strings"); + declare_string("typelib"); + declare_string_array("constants"); + declare_integer("number_of_constants"); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + YR_MEMORY_BLOCK* block; + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + const uint8_t* block_data = NULL; + + foreach_memory_block(iterator, block) + { + PIMAGE_NT_HEADERS32 pe_header; + + block_data = block->fetch_data(block); + + if (block_data == NULL) + continue; + + pe_header = pe_get_header(block_data, block->size); + + if (pe_header != NULL) + { + // Ignore DLLs while scanning a process + + if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || + !(pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) + { + PE* pe = (PE*) yr_malloc(sizeof(PE)); + + if (pe == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + pe->data = block_data; + pe->data_size = block->size; + pe->object = module_object; + pe->header = pe_header; + + module_object->data = pe; + + dotnet_parse_com(pe, block->base); + + break; + } + } + } + + return ERROR_SUCCESS; +} + + +int module_unload( + YR_OBJECT* module_object) +{ + PE* pe = (PE *) module_object->data; + + if (pe == NULL) + return ERROR_SUCCESS; + + yr_free(pe); + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/elf.c b/yara-master/libyara/modules/elf.c new file mode 100644 index 0000000..bc5ca73 --- /dev/null +++ b/yara-master/libyara/modules/elf.c @@ -0,0 +1,796 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#define _GNU_SOURCE + +#include +#include + +#include +#include +#include +#include + + +#define MODULE_NAME elf + +#define CLASS_DATA(c,d) ((c << 8) | d) + +int get_elf_class_data( + const uint8_t* buffer, + size_t buffer_length) +{ + elf_ident_t* elf_ident; + + if (buffer_length < sizeof(elf_ident_t)) + return 0; + + elf_ident = (elf_ident_t*) buffer; + + if (yr_le32toh(elf_ident->magic) == ELF_MAGIC) + { + return CLASS_DATA(elf_ident->_class, elf_ident->data); + } + else + { + return 0; + } +} + +static int is_valid_ptr( + const void* base, + size_t size, + const void* ptr, + uint64_t ptr_size) // ptr_size can be 64bit even in 32bit systems. +{ + return ptr >= base && ptr_size <= size && + ((char*) ptr) + ptr_size <= ((char*) base) + size; +} + +#define IS_VALID_PTR(base, size, ptr) \ + is_valid_ptr(base, size, ptr, sizeof(*ptr)) + +/* + * Returns a string table entry for the index or NULL if the entry is out + * of bounds. A non-null return value will be a null-terminated C string. + */ +static const char* str_table_entry(const char* str_table_base, + const char* str_table_limit, + int index) { + size_t len; + const char* str_entry = str_table_base + index; + + if (index < 0) + { + return NULL; + } + + if (str_entry >= str_table_limit) + { + return NULL; + } + + len = strnlen(str_entry, str_table_limit - str_entry); + + if (str_entry + len == str_table_limit) + { + /* Entry is clamped by extent of string table, not null-terminated. */ + return NULL; + } + + return str_entry; +} + +#define ELF_SIZE_OF_SECTION_TABLE(bits,bo,h) \ + (sizeof(elf##bits##_section_header_t) * yr_##bo##16toh(h->sh_entry_count)) + +#define ELF_SIZE_OF_PROGRAM_TABLE(bits,bo,h) \ + (sizeof(elf##bits##_program_header_t) * yr_##bo##16toh(h->ph_entry_count)) + +#define ELF_RVA_TO_OFFSET(bits,bo) \ +uint64_t elf_rva_to_offset_##bits##_##bo( \ + elf##bits##_header_t* elf_header, \ + uint64_t rva, \ + size_t elf_size) \ +{ \ + if (yr_##bo##16toh(elf_header->type) == ELF_ET_EXEC) \ + { \ + int i; \ + \ + elf##bits##_program_header_t* program; \ + \ + /* check that ph_offset doesn't wrap when added to SIZE_OF_PROGRAM_TABLE */\ + \ + if(ULONG_MAX - yr_##bo##bits##toh(elf_header->ph_offset) < \ + ELF_SIZE_OF_PROGRAM_TABLE(bits,bo,elf_header)) \ + { \ + return UNDEFINED; \ + } \ + \ + if (yr_##bo##bits##toh(elf_header->ph_offset) == 0 || \ + yr_##bo##bits##toh(elf_header->ph_offset) > elf_size || \ + yr_##bo##bits##toh(elf_header->ph_offset) + \ + ELF_SIZE_OF_PROGRAM_TABLE(bits,bo,elf_header) > elf_size || \ + yr_##bo##16toh(elf_header->ph_entry_count) == 0) \ + { \ + return UNDEFINED; \ + } \ + \ + program = (elf##bits##_program_header_t*) \ + ((uint8_t*) elf_header + yr_##bo##bits##toh(elf_header->ph_offset)); \ + \ + for (i = 0; i < yr_##bo##16toh(elf_header->ph_entry_count); i++) \ + { \ + if (rva >= yr_##bo##bits##toh(program->virt_addr) && \ + rva < yr_##bo##bits##toh(program->virt_addr) + \ + yr_##bo##bits##toh(program->mem_size)) \ + { \ + return yr_##bo##bits##toh(program->offset) + \ + (rva - yr_##bo##bits##toh(program->virt_addr)); \ + } \ + \ + program++; \ + } \ + } \ + else \ + { \ + int i; \ + \ + elf##bits##_section_header_t* section; \ + \ + /* check that sh_offset doesn't wrap when added to SIZE_OF_SECTION_TABLE */\ + \ + if(ULONG_MAX - yr_##bo##bits##toh(elf_header->sh_offset) < \ + ELF_SIZE_OF_SECTION_TABLE(bits,bo,elf_header)) \ + { \ + return UNDEFINED; \ + } \ + \ + if (yr_##bo##bits##toh(elf_header->sh_offset) == 0 || \ + yr_##bo##bits##toh(elf_header->sh_offset) > elf_size || \ + yr_##bo##bits##toh(elf_header->sh_offset) + \ + ELF_SIZE_OF_SECTION_TABLE(bits,bo,elf_header) > elf_size || \ + yr_##bo##16toh(elf_header->sh_entry_count) == 0) \ + { \ + return UNDEFINED; \ + } \ + \ + section = (elf##bits##_section_header_t*) \ + ((uint8_t*) elf_header + yr_##bo##bits##toh(elf_header->sh_offset)); \ + \ + for (i = 0; i < yr_##bo##16toh(elf_header->sh_entry_count); i++) \ + { \ + if (yr_##bo##32toh(section->type) != ELF_SHT_NULL && \ + yr_##bo##32toh(section->type) != ELF_SHT_NOBITS && \ + rva >= yr_##bo##bits##toh(section->addr) && \ + rva < yr_##bo##bits##toh(section->addr) + \ + yr_##bo##bits##toh(section->size)) \ + { \ + return yr_##bo##bits##toh(section->offset) + \ + (rva - yr_##bo##bits##toh(section->addr)); \ + } \ + \ + section++; \ + } \ + } \ + return UNDEFINED; \ +} + +#define PARSE_ELF_HEADER(bits,bo) \ +void parse_elf_header_##bits##_##bo( \ + elf##bits##_header_t* elf, \ + uint64_t base_address, \ + size_t elf_size, \ + int flags, \ + YR_OBJECT* elf_obj) \ +{ \ + unsigned int i, j; \ + const char* elf_raw = (const char*) elf; \ + uint16_t str_table_index = yr_##bo##16toh(elf->sh_str_table_index); \ + \ + const char* sym_table = NULL; \ + const char* sym_str_table = NULL; \ + \ + uint##bits##_t sym_table_size = 0; \ + uint##bits##_t sym_str_table_size = 0; \ + \ + elf##bits##_section_header_t* section_table; \ + elf##bits##_section_header_t* section; \ + elf##bits##_program_header_t* segment; \ + \ + set_integer(yr_##bo##16toh(elf->type), elf_obj, "type"); \ + set_integer(yr_##bo##16toh(elf->machine), elf_obj, "machine"); \ + set_integer(yr_##bo##bits##toh(elf->sh_offset), elf_obj, \ + "sh_offset"); \ + set_integer(yr_##bo##16toh(elf->sh_entry_size), elf_obj, \ + "sh_entry_size"); \ + set_integer(yr_##bo##16toh(elf->sh_entry_count), elf_obj, \ + "number_of_sections"); \ + set_integer(yr_##bo##bits##toh(elf->ph_offset), elf_obj, \ + "ph_offset"); \ + set_integer(yr_##bo##16toh(elf->ph_entry_size), elf_obj, \ + "ph_entry_size"); \ + set_integer(yr_##bo##16toh(elf->ph_entry_count), elf_obj, \ + "number_of_segments"); \ + \ + if (yr_##bo##bits##toh(elf->entry) != 0) \ + { \ + set_integer( \ + flags & SCAN_FLAGS_PROCESS_MEMORY ? \ + base_address + yr_##bo##bits##toh(elf->entry) : \ + elf_rva_to_offset_##bits##_##bo( \ + elf, yr_##bo##bits##toh(elf->entry), elf_size), \ + elf_obj, "entry_point"); \ + } \ + \ + if (yr_##bo##16toh(elf->sh_entry_count) < ELF_SHN_LORESERVE && \ + str_table_index < yr_##bo##16toh(elf->sh_entry_count) && \ + yr_##bo##bits##toh(elf->sh_offset) < elf_size && \ + yr_##bo##bits##toh(elf->sh_offset) + \ + yr_##bo##16toh(elf->sh_entry_count) * \ + sizeof(elf##bits##_section_header_t) <= elf_size) \ + { \ + const char* str_table = NULL; \ + \ + section_table = (elf##bits##_section_header_t*) \ + (elf_raw + yr_##bo##bits##toh(elf->sh_offset)); \ + \ + if (yr_##bo##bits##toh(section_table[str_table_index].offset) < elf_size) \ + { \ + str_table = elf_raw + yr_##bo##bits##toh( \ + section_table[str_table_index].offset); \ + } \ + \ + section = section_table; \ + \ + for (i = 0; i < yr_##bo##16toh(elf->sh_entry_count); i++, section++) \ + { \ + set_integer(yr_##bo##32toh(section->type), elf_obj, \ + "sections[%i].type", i); \ + set_integer(yr_##bo##bits##toh(section->flags), elf_obj, \ + "sections[%i].flags", i); \ + set_integer(yr_##bo##bits##toh(section->addr), elf_obj, \ + "sections[%i].address", i); \ + set_integer(yr_##bo##bits##toh(section->size), elf_obj, \ + "sections[%i].size", i); \ + set_integer(yr_##bo##bits##toh(section->offset), elf_obj, \ + "sections[%i].offset", i); \ + \ + if (yr_##bo##32toh(section->name) < elf_size && \ + str_table > elf_raw && \ + str_table + yr_##bo##32toh(section->name) < elf_raw + elf_size) \ + { \ + const char* str_entry = str_table_entry( \ + str_table, \ + elf_raw + elf_size, \ + yr_##bo##32toh(section->name)); \ + \ + if (str_entry) \ + set_string(str_entry, elf_obj, "sections[%i].name", i); \ + } \ + \ + if (yr_##bo##32toh(section->type) == ELF_SHT_SYMTAB && \ + yr_##bo##32toh(section->link) < elf->sh_entry_count) \ + { \ + elf##bits##_section_header_t* string_section = \ + section_table + yr_##bo##32toh(section->link); \ + \ + if (IS_VALID_PTR(elf, elf_size, string_section) && \ + yr_##bo##32toh(string_section->type) == ELF_SHT_STRTAB) \ + { \ + sym_table = elf_raw + yr_##bo##bits##toh(section->offset); \ + sym_str_table = elf_raw + yr_##bo##bits##toh(string_section->offset);\ + sym_table_size = yr_##bo##bits##toh(section->size); \ + sym_str_table_size = yr_##bo##bits##toh(string_section->size); \ + } \ + } \ + } \ + \ + if (is_valid_ptr(elf, elf_size, sym_str_table, sym_str_table_size) && \ + is_valid_ptr(elf, elf_size, sym_table, sym_table_size)) \ + { \ + elf##bits##_sym_t* sym = (elf##bits##_sym_t*) sym_table; \ + \ + for (j = 0; j < sym_table_size / sizeof(elf##bits##_sym_t); j++, sym++) \ + { \ + uint32_t sym_name_offset = yr_##bo##32toh(sym->name); \ + \ + if (sym_name_offset < sym_str_table_size) \ + { \ + const char* sym_name = sym_str_table + sym_name_offset; \ + \ + set_sized_string( \ + sym_name, \ + strnlen( \ + sym_name, (size_t) (sym_str_table_size - sym_name_offset)), \ + elf_obj, \ + "symtab[%i].name", \ + j); \ + } \ + \ + set_integer(sym->info >> 4, elf_obj, \ + "symtab[%i].bind", j); \ + set_integer(sym->info & 0xf, elf_obj, \ + "symtab[%i].type", j); \ + set_integer(yr_##bo##16toh(sym->shndx), elf_obj, \ + "symtab[%i].shndx", j); \ + set_integer(yr_##bo##bits##toh(sym->value), elf_obj, \ + "symtab[%i].value", j); \ + set_integer(yr_##bo##bits##toh(sym->size), elf_obj, \ + "symtab[%i].size", j); \ + } \ + \ + set_integer(j, elf_obj, "symtab_entries"); \ + } \ + } \ + \ + if (yr_##bo##16toh(elf->ph_entry_count) > 0 && \ + yr_##bo##16toh(elf->ph_entry_count) < ELF_PN_XNUM && \ + yr_##bo##bits##toh(elf->ph_offset) < elf_size && \ + yr_##bo##bits##toh(elf->ph_offset) + \ + yr_##bo##16toh(elf->ph_entry_count) * \ + sizeof(elf##bits##_program_header_t) <= elf_size) \ + { \ + segment = (elf##bits##_program_header_t*) \ + (elf_raw + yr_##bo##bits##toh(elf->ph_offset)); \ + \ + for (i = 0; i < yr_##bo##16toh(elf->ph_entry_count); i++, segment++) \ + { \ + set_integer( \ + yr_##bo##32toh(segment->type), elf_obj, "segments[%i].type", i); \ + set_integer( \ + yr_##bo##32toh(segment->flags), elf_obj, "segments[%i].flags", i); \ + set_integer( \ + yr_##bo##bits##toh(segment->offset), elf_obj, \ + "segments[%i].offset", i); \ + set_integer( \ + yr_##bo##bits##toh(segment->virt_addr), elf_obj, \ + "segments[%i].virtual_address", i); \ + set_integer( \ + yr_##bo##bits##toh(segment->phys_addr), elf_obj, \ + "segments[%i].physical_address", i); \ + set_integer( \ + yr_##bo##bits##toh(segment->file_size), elf_obj, \ + "segments[%i].file_size", i); \ + set_integer( \ + yr_##bo##bits##toh(segment->mem_size), elf_obj, \ + "segments[%i].memory_size", i); \ + set_integer( \ + yr_##bo##bits##toh(segment->alignment), elf_obj, \ + "segments[%i].alignment", i); \ + \ + if (yr_##bo##32toh(segment->type) == ELF_PT_DYNAMIC) \ + { \ + elf##bits##_dyn_t* dyn = (elf##bits##_dyn_t*) \ + (elf_raw + yr_##bo##bits##toh(segment->offset)); \ + \ + for (j = 0; IS_VALID_PTR(elf, elf_size, dyn); dyn++, j++) \ + { \ + set_integer( \ + yr_##bo##bits##toh(dyn->tag), elf_obj, "dynamic[%i].type", j); \ + set_integer( \ + yr_##bo##bits##toh(dyn->val), elf_obj, "dynamic[%i].val", j); \ + \ + if (dyn->tag == ELF_DT_NULL) \ + { \ + j++; \ + break; \ + } \ + } \ + set_integer(j, elf_obj, "dynamic_section_entries"); \ + } \ + } \ + } \ +} + +ELF_RVA_TO_OFFSET(32,le); +ELF_RVA_TO_OFFSET(64,le); +ELF_RVA_TO_OFFSET(32,be); +ELF_RVA_TO_OFFSET(64,be); + +PARSE_ELF_HEADER(32,le); +PARSE_ELF_HEADER(64,le); +PARSE_ELF_HEADER(32,be); +PARSE_ELF_HEADER(64,be); + + +begin_declarations; + + declare_integer("ET_NONE"); + declare_integer("ET_REL"); + declare_integer("ET_EXEC"); + declare_integer("ET_DYN"); + declare_integer("ET_CORE"); + + declare_integer("EM_NONE"); + declare_integer("EM_M32"); + declare_integer("EM_SPARC"); + declare_integer("EM_386"); + declare_integer("EM_68K"); + declare_integer("EM_88K"); + declare_integer("EM_860"); + declare_integer("EM_MIPS"); + declare_integer("EM_MIPS_RS3_LE"); + declare_integer("EM_PPC"); + declare_integer("EM_PPC64"); + declare_integer("EM_ARM"); + declare_integer("EM_X86_64"); + declare_integer("EM_AARCH64"); + + declare_integer("SHT_NULL"); + declare_integer("SHT_PROGBITS"); + declare_integer("SHT_SYMTAB"); + declare_integer("SHT_STRTAB"); + declare_integer("SHT_RELA"); + declare_integer("SHT_HASH"); + declare_integer("SHT_DYNAMIC"); + declare_integer("SHT_NOTE"); + declare_integer("SHT_NOBITS"); + declare_integer("SHT_REL"); + declare_integer("SHT_SHLIB"); + declare_integer("SHT_DYNSYM"); + + declare_integer("SHF_WRITE"); + declare_integer("SHF_ALLOC"); + declare_integer("SHF_EXECINSTR"); + + declare_integer("type"); + declare_integer("machine"); + declare_integer("entry_point"); + + declare_integer("number_of_sections"); + declare_integer("sh_offset"); + declare_integer("sh_entry_size"); + + declare_integer("number_of_segments"); + declare_integer("ph_offset"); + declare_integer("ph_entry_size"); + + begin_struct_array("sections"); + declare_integer("type"); + declare_integer("flags"); + declare_integer("address"); + declare_string("name"); + declare_integer("size"); + declare_integer("offset"); + end_struct_array("sections"); + + declare_integer("PT_NULL"); + declare_integer("PT_LOAD"); + declare_integer("PT_DYNAMIC"); + declare_integer("PT_INTERP"); + declare_integer("PT_NOTE"); + declare_integer("PT_SHLIB"); + declare_integer("PT_PHDR"); + declare_integer("PT_TLS"); + declare_integer("PT_GNU_EH_FRAME"); + declare_integer("PT_GNU_STACK"); + + declare_integer("DT_NULL"); + declare_integer("DT_NEEDED"); + declare_integer("DT_PLTRELSZ"); + declare_integer("DT_PLTGOT"); + declare_integer("DT_HASH"); + declare_integer("DT_STRTAB"); + declare_integer("DT_SYMTAB"); + declare_integer("DT_RELA"); + declare_integer("DT_RELASZ"); + declare_integer("DT_RELAENT"); + declare_integer("DT_STRSZ"); + declare_integer("DT_SYMENT"); + declare_integer("DT_INIT"); + declare_integer("DT_FINI"); + declare_integer("DT_SONAME"); + declare_integer("DT_RPATH"); + declare_integer("DT_SYMBOLIC"); + declare_integer("DT_REL"); + declare_integer("DT_RELSZ"); + declare_integer("DT_RELENT"); + declare_integer("DT_PLTREL"); + declare_integer("DT_DEBUG"); + declare_integer("DT_TEXTREL"); + declare_integer("DT_JMPREL"); + declare_integer("DT_BIND_NOW"); + declare_integer("DT_INIT_ARRAY"); + declare_integer("DT_FINI_ARRAY"); + declare_integer("DT_INIT_ARRAYSZ"); + declare_integer("DT_FINI_ARRAYSZ"); + declare_integer("DT_RUNPATH"); + declare_integer("DT_FLAGS"); + declare_integer("DT_ENCODING"); + + declare_integer("STT_NOTYPE"); + declare_integer("STT_OBJECT"); + declare_integer("STT_FUNC"); + declare_integer("STT_SECTION"); + declare_integer("STT_FILE"); + declare_integer("STT_COMMON"); + declare_integer("STT_TLS"); + + declare_integer("STB_LOCAL"); + declare_integer("STB_GLOBAL"); + declare_integer("STB_WEAK"); + + declare_integer("PF_X"); + declare_integer("PF_W"); + declare_integer("PF_R"); + + begin_struct_array("segments"); + declare_integer("type"); + declare_integer("flags"); + declare_integer("offset"); + declare_integer("virtual_address"); + declare_integer("physical_address"); + declare_integer("file_size"); + declare_integer("memory_size"); + declare_integer("alignment"); + end_struct_array("segments"); + + declare_integer("dynamic_section_entries"); + begin_struct_array("dynamic"); + declare_integer("type"); + declare_integer("val"); + end_struct_array("dynamic"); + + declare_integer("symtab_entries"); + begin_struct_array("symtab"); + declare_string("name"); + declare_integer("value"); + declare_integer("size"); + declare_integer("type"); + declare_integer("bind"); + declare_integer("shndx"); + end_struct_array("symtab"); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + YR_MEMORY_BLOCK* block; + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + elf32_header_t* elf_header32; + elf64_header_t* elf_header64; + + set_integer(ELF_ET_NONE, module_object, "ET_NONE"); + set_integer(ELF_ET_REL, module_object, "ET_REL"); + set_integer(ELF_ET_EXEC, module_object, "ET_EXEC"); + set_integer(ELF_ET_DYN, module_object, "ET_DYN"); + set_integer(ELF_ET_CORE, module_object, "ET_CORE"); + + set_integer(ELF_EM_NONE, module_object, "EM_NONE"); + set_integer(ELF_EM_M32, module_object, "EM_M32"); + set_integer(ELF_EM_SPARC, module_object, "EM_SPARC"); + set_integer(ELF_EM_386, module_object, "EM_386"); + set_integer(ELF_EM_68K, module_object, "EM_68K"); + set_integer(ELF_EM_88K, module_object, "EM_88K"); + set_integer(ELF_EM_860, module_object, "EM_860"); + set_integer(ELF_EM_MIPS, module_object, "EM_MIPS"); + set_integer(ELF_EM_MIPS_RS3_LE, module_object, "EM_MIPS_RS3_LE"); + set_integer(ELF_EM_PPC, module_object, "EM_PPC"); + set_integer(ELF_EM_PPC64, module_object, "EM_PPC64"); + set_integer(ELF_EM_ARM, module_object, "EM_ARM"); + set_integer(ELF_EM_X86_64, module_object, "EM_X86_64"); + set_integer(ELF_EM_AARCH64, module_object, "EM_AARCH64"); + + set_integer(ELF_SHT_NULL, module_object, "SHT_NULL"); + set_integer(ELF_SHT_PROGBITS, module_object, "SHT_PROGBITS"); + set_integer(ELF_SHT_SYMTAB, module_object, "SHT_SYMTAB"); + set_integer(ELF_SHT_STRTAB, module_object, "SHT_STRTAB"); + set_integer(ELF_SHT_RELA, module_object, "SHT_RELA"); + set_integer(ELF_SHT_HASH, module_object, "SHT_HASH"); + set_integer(ELF_SHT_DYNAMIC, module_object, "SHT_DYNAMIC"); + set_integer(ELF_SHT_NOTE, module_object, "SHT_NOTE"); + set_integer(ELF_SHT_NOBITS, module_object, "SHT_NOBITS"); + set_integer(ELF_SHT_REL, module_object, "SHT_REL"); + set_integer(ELF_SHT_SHLIB, module_object, "SHT_SHLIB"); + set_integer(ELF_SHT_DYNSYM, module_object, "SHT_DYNSYM"); + + set_integer(ELF_SHF_WRITE, module_object, "SHF_WRITE"); + set_integer(ELF_SHF_ALLOC, module_object, "SHF_ALLOC"); + set_integer(ELF_SHF_EXECINSTR, module_object, "SHF_EXECINSTR"); + + set_integer(ELF_PT_NULL, module_object, "PT_NULL"); + set_integer(ELF_PT_LOAD, module_object, "PT_LOAD"); + set_integer(ELF_PT_DYNAMIC, module_object, "PT_DYNAMIC"); + set_integer(ELF_PT_INTERP, module_object, "PT_INTERP"); + set_integer(ELF_PT_NOTE, module_object, "PT_NOTE"); + set_integer(ELF_PT_SHLIB, module_object, "PT_SHLIB"); + set_integer(ELF_PT_PHDR, module_object, "PT_PHDR"); + set_integer(ELF_PT_TLS, module_object, "PT_TLS"); + set_integer(ELF_PT_GNU_EH_FRAME, module_object, "PT_GNU_EH_FRAME"); + set_integer(ELF_PT_GNU_STACK, module_object, "PT_GNU_STACK"); + + set_integer(ELF_DT_NULL, module_object, "DT_NULL"); + set_integer(ELF_DT_NEEDED, module_object, "DT_NEEDED"); + set_integer(ELF_DT_PLTRELSZ, module_object, "DT_PLTRELSZ"); + set_integer(ELF_DT_PLTGOT, module_object, "DT_PLTGOT"); + set_integer(ELF_DT_HASH, module_object, "DT_HASH"); + set_integer(ELF_DT_STRTAB, module_object, "DT_STRTAB"); + set_integer(ELF_DT_SYMTAB, module_object, "DT_SYMTAB"); + set_integer(ELF_DT_RELA, module_object, "DT_RELA"); + set_integer(ELF_DT_RELASZ, module_object, "DT_RELASZ"); + set_integer(ELF_DT_RELAENT, module_object, "DT_RELAENT"); + set_integer(ELF_DT_STRSZ, module_object, "DT_STRSZ"); + set_integer(ELF_DT_SYMENT, module_object, "DT_SYMENT"); + set_integer(ELF_DT_INIT, module_object, "DT_INIT"); + set_integer(ELF_DT_FINI, module_object, "DT_FINI"); + set_integer(ELF_DT_SONAME, module_object, "DT_SONAME"); + set_integer(ELF_DT_RPATH, module_object, "DT_RPATH"); + set_integer(ELF_DT_SYMBOLIC, module_object, "DT_SYMBOLIC"); + set_integer(ELF_DT_REL, module_object, "DT_REL"); + set_integer(ELF_DT_RELSZ, module_object, "DT_RELSZ"); + set_integer(ELF_DT_RELENT, module_object, "DT_RELENT"); + set_integer(ELF_DT_PLTREL, module_object, "DT_PLTREL"); + set_integer(ELF_DT_DEBUG, module_object, "DT_DEBUG"); + set_integer(ELF_DT_TEXTREL, module_object, "DT_TEXTREL"); + set_integer(ELF_DT_JMPREL, module_object, "DT_JMPREL"); + set_integer(ELF_DT_BIND_NOW, module_object, "DT_BIND_NOW"); + set_integer(ELF_DT_INIT_ARRAY, module_object, "DT_INIT_ARRAY"); + set_integer(ELF_DT_FINI_ARRAY, module_object, "DT_FINI_ARRAY"); + set_integer(ELF_DT_INIT_ARRAYSZ, module_object, "DT_INIT_ARRAYSZ"); + set_integer(ELF_DT_FINI_ARRAYSZ, module_object, "DT_FINI_ARRAYSZ"); + set_integer(ELF_DT_RUNPATH, module_object, "DT_RUNPATH"); + set_integer(ELF_DT_FLAGS, module_object, "DT_FLAGS"); + set_integer(ELF_DT_ENCODING, module_object, "DT_ENCODING"); + + set_integer(ELF_STT_NOTYPE, module_object, "STT_NOTYPE"); + set_integer(ELF_STT_OBJECT, module_object, "STT_OBJECT"); + set_integer(ELF_STT_FUNC, module_object, "STT_FUNC"); + set_integer(ELF_STT_SECTION, module_object, "STT_SECTION"); + set_integer(ELF_STT_FILE, module_object, "STT_FILE"); + set_integer(ELF_STT_COMMON, module_object, "STT_COMMON"); + set_integer(ELF_STT_TLS, module_object, "STT_TLS"); + + set_integer(ELF_STB_LOCAL, module_object, "STB_LOCAL"); + set_integer(ELF_STB_GLOBAL, module_object, "STB_GLOBAL"); + set_integer(ELF_STB_WEAK, module_object, "STB_WEAK"); + + set_integer(ELF_PF_X, module_object, "PF_X"); + set_integer(ELF_PF_W, module_object, "PF_W"); + set_integer(ELF_PF_R, module_object, "PF_R"); + + foreach_memory_block(iterator, block) + { + const uint8_t* block_data = block->fetch_data(block); + + if (block_data == NULL) + continue; + + switch(get_elf_class_data(block_data, block->size)) + { + case CLASS_DATA(ELF_CLASS_32, ELF_DATA_2LSB): + + if (block->size > sizeof(elf32_header_t)) + { + elf_header32 = (elf32_header_t*) block_data; + + if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || + yr_le16toh(elf_header32->type) == ELF_ET_EXEC) + { + parse_elf_header_32_le( + elf_header32, + block->base, + block->size, + context->flags, + module_object); + } + } + + break; + + case CLASS_DATA(ELF_CLASS_32, ELF_DATA_2MSB): + + if (block->size > sizeof(elf32_header_t)) + { + elf_header32 = (elf32_header_t*) block_data; + + if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || + yr_be16toh(elf_header32->type) == ELF_ET_EXEC) + { + parse_elf_header_32_be( + elf_header32, + block->base, + block->size, + context->flags, + module_object); + } + } + + break; + + case CLASS_DATA(ELF_CLASS_64,ELF_DATA_2LSB): + + if (block->size > sizeof(elf64_header_t)) + { + elf_header64 = (elf64_header_t*) block_data; + + if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || + yr_le16toh(elf_header64->type) == ELF_ET_EXEC) + { + parse_elf_header_64_le( + elf_header64, + block->base, + block->size, + context->flags, + module_object); + } + } + + break; + + case CLASS_DATA(ELF_CLASS_64,ELF_DATA_2MSB): + + if (block->size > sizeof(elf64_header_t)) + { + elf_header64 = (elf64_header_t*) block_data; + + if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || + yr_be16toh(elf_header64->type) == ELF_ET_EXEC) + { + parse_elf_header_64_be( + elf_header64, + block->base, + block->size, + context->flags, + module_object); + } + } + + break; + } + } + + return ERROR_SUCCESS; +} + + +int module_unload(YR_OBJECT* module_object) +{ + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/hash.c b/yara-master/libyara/modules/hash.c new file mode 100644 index 0000000..f1fea82 --- /dev/null +++ b/yara-master/libyara/modules/hash.c @@ -0,0 +1,540 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include "../crypto.h" + +#include +#include + +#define MODULE_NAME hash + + +typedef struct _CACHE_KEY +{ + int64_t offset; + int64_t length; + +} CACHE_KEY; + + +void digest_to_ascii( + unsigned char* digest, + char* digest_ascii, + size_t digest_length) +{ + size_t i; + + for (i = 0; i < digest_length; i++) + sprintf(digest_ascii + (i * 2), "%02x", digest[i]); + + digest_ascii[digest_length * 2] = '\0'; +} + + +char* get_from_cache( + YR_OBJECT* module_object, + const char* ns, + int64_t offset, + int64_t length) +{ + CACHE_KEY key; + YR_HASH_TABLE* hash_table = (YR_HASH_TABLE*) module_object->data; + + key.offset = offset; + key.length = length; + + return (char*) yr_hash_table_lookup_raw_key( + hash_table, + &key, + sizeof(key), + ns); +} + + +int add_to_cache( + YR_OBJECT* module_object, + const char* ns, + int64_t offset, + int64_t length, + const char* digest) +{ + CACHE_KEY key; + YR_HASH_TABLE* hash_table = (YR_HASH_TABLE*) module_object->data; + + char* copy = yr_strdup(digest); + + key.offset = offset; + key.length = length; + + if (copy == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + return yr_hash_table_add_raw_key( + hash_table, + &key, + sizeof(key), + ns, + (void*) copy); +} + + +define_function(string_md5) +{ + unsigned char digest[YR_MD5_LEN]; + char digest_ascii[YR_MD5_LEN * 2 + 1]; + + yr_md5_ctx md5_context; + SIZED_STRING* s = sized_string_argument(1); + + yr_md5_init(&md5_context); + yr_md5_update(&md5_context, s->c_string, s->length); + yr_md5_final(digest, &md5_context); + + digest_to_ascii(digest, digest_ascii, YR_MD5_LEN); + + return_string(digest_ascii); +} + + +define_function(string_sha256) +{ + unsigned char digest[YR_SHA256_LEN]; + char digest_ascii[YR_SHA256_LEN * 2 + 1]; + + yr_sha256_ctx sha256_context; + SIZED_STRING* s = sized_string_argument(1); + + yr_sha256_init(&sha256_context); + yr_sha256_update(&sha256_context, s->c_string, s->length); + yr_sha256_final(digest, &sha256_context); + + digest_to_ascii(digest, digest_ascii, YR_SHA256_LEN); + + return_string(digest_ascii); +} + + +define_function(string_sha1) +{ + unsigned char digest[YR_SHA1_LEN]; + char digest_ascii[YR_SHA1_LEN * 2 + 1]; + + yr_sha1_ctx sha_context; + SIZED_STRING* s = sized_string_argument(1); + + yr_sha1_init(&sha_context); + yr_sha1_update(&sha_context, s->c_string, s->length); + yr_sha1_final(digest, &sha_context); + + digest_to_ascii(digest, digest_ascii, YR_SHA1_LEN); + + return_string(digest_ascii); +} + + +define_function(string_checksum32) +{ + size_t i; + + SIZED_STRING* s = sized_string_argument(1); + uint32_t checksum = 0; + + for (i = 0; i < s->length; i++) + checksum += (uint8_t)(s->c_string[i]); + + return_integer(checksum); +} + + +define_function(data_md5) +{ + yr_md5_ctx md5_context; + + unsigned char digest[YR_MD5_LEN]; + char digest_ascii[YR_MD5_LEN * 2 + 1]; + char* cached_ascii_digest; + + int past_first_block = FALSE; + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + int64_t arg_offset = integer_argument(1); // offset where to start + int64_t arg_length = integer_argument(2); // length of bytes we want hash on + + int64_t offset = arg_offset; + int64_t length = arg_length; + + yr_md5_init(&md5_context); + + if (offset < 0 || length < 0 || offset < block->base) + return_string(UNDEFINED); + + cached_ascii_digest = get_from_cache( + module(), "md5", arg_offset, arg_length); + + if (cached_ascii_digest != NULL) + return_string(cached_ascii_digest); + + foreach_memory_block(iterator, block) + { + // if desired block within current block + + if (offset >= block->base && + offset < block->base + block->size) + { + const uint8_t* block_data = block->fetch_data(block); + + if (block_data != NULL) + { + size_t data_offset = (size_t) (offset - block->base); + size_t data_len = (size_t) yr_min( + length, (size_t) (block->size - data_offset)); + + offset += data_len; + length -= data_len; + + yr_md5_update(&md5_context, block_data + data_offset, data_len); + } + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + + return_string(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block) + return_string(UNDEFINED); + + yr_md5_final(digest, &md5_context); + + digest_to_ascii(digest, digest_ascii, YR_MD5_LEN); + + FAIL_ON_ERROR( + add_to_cache(module(), "md5", arg_offset, arg_length, digest_ascii)); + + return_string(digest_ascii); +} + + +define_function(data_sha1) +{ + yr_sha1_ctx sha_context; + + unsigned char digest[YR_SHA1_LEN]; + char digest_ascii[YR_SHA1_LEN * 2 + 1]; + char* cached_ascii_digest; + + int past_first_block = FALSE; + + int64_t arg_offset = integer_argument(1); // offset where to start + int64_t arg_length = integer_argument(2); // length of bytes we want hash on + + int64_t offset = arg_offset; + int64_t length = arg_length; + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + yr_sha1_init(&sha_context); + + if (offset < 0 || length < 0 || offset < block->base) + return_string(UNDEFINED); + + cached_ascii_digest = get_from_cache( + module(), "sha1", arg_offset, arg_length); + + if (cached_ascii_digest != NULL) + return_string(cached_ascii_digest); + + foreach_memory_block(iterator, block) + { + // if desired block within current block + if (offset >= block->base && + offset < block->base + block->size) + { + const uint8_t* block_data = block->fetch_data(block); + + if (block_data != NULL) + { + size_t data_offset = (size_t) (offset - block->base); + size_t data_len = (size_t) yr_min( + length, (size_t) block->size - data_offset); + + offset += data_len; + length -= data_len; + + yr_sha1_update(&sha_context, block_data + data_offset, data_len); + } + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + + return_string(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block) + return_string(UNDEFINED); + + yr_sha1_final(digest, &sha_context); + + digest_to_ascii(digest, digest_ascii, YR_SHA1_LEN); + + FAIL_ON_ERROR( + add_to_cache(module(), "sha1", arg_offset, arg_length, digest_ascii)); + + return_string(digest_ascii); +} + + +define_function(data_sha256) +{ + yr_sha256_ctx sha256_context; + + unsigned char digest[YR_SHA256_LEN]; + char digest_ascii[YR_SHA256_LEN * 2 + 1]; + char* cached_ascii_digest; + + int past_first_block = FALSE; + + int64_t arg_offset = integer_argument(1); // offset where to start + int64_t arg_length = integer_argument(2); // length of bytes we want hash on + + int64_t offset = arg_offset; + int64_t length = arg_length; + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + yr_sha256_init(&sha256_context); + + if (offset < 0 || length < 0 || offset < block->base) + return_string(UNDEFINED); + + cached_ascii_digest = get_from_cache( + module(), "sha256", arg_offset, arg_length); + + if (cached_ascii_digest != NULL) + return_string(cached_ascii_digest); + + foreach_memory_block(iterator, block) + { + // if desired block within current block + if (offset >= block->base && + offset < block->base + block->size) + { + const uint8_t* block_data = block->fetch_data(block); + + if (block_data != NULL) + { + size_t data_offset = (size_t) (offset - block->base); + size_t data_len = (size_t) yr_min(length, block->size - data_offset); + + offset += data_len; + length -= data_len; + + yr_sha256_update(&sha256_context, block_data + data_offset, data_len); + } + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + + return_string(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block) + return_string(UNDEFINED); + + yr_sha256_final(digest, &sha256_context); + + digest_to_ascii(digest, digest_ascii, YR_SHA256_LEN); + + FAIL_ON_ERROR( + add_to_cache(module(), "sha256", arg_offset, arg_length, digest_ascii)); + + return_string(digest_ascii); +} + + +define_function(data_checksum32) +{ + int64_t offset = integer_argument(1); // offset where to start + int64_t length = integer_argument(2); // length of bytes we want hash on + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + uint32_t checksum = 0; + int past_first_block = FALSE; + + if (offset < 0 || length < 0 || offset < block->base) + return_integer(UNDEFINED); + + foreach_memory_block(iterator, block) + { + if (offset >= block->base && + offset < block->base + block->size) + { + const uint8_t* block_data = block->fetch_data(block); + + if (block_data != NULL) + { + size_t i; + + size_t data_offset = (size_t) (offset - block->base); + size_t data_len = (size_t) yr_min(length, block->size - data_offset); + + offset += data_len; + length -= data_len; + + for (i = 0; i < data_len; i++) + checksum += *(block_data + data_offset + i); + } + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + + return_integer(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block) + return_integer(UNDEFINED); + + return_integer(checksum); +} + + + +begin_declarations; + + declare_function("md5", "ii", "s", data_md5); + declare_function("md5", "s", "s", string_md5); + + declare_function("sha1", "ii", "s", data_sha1); + declare_function("sha1", "s", "s", string_sha1); + + declare_function("sha256", "ii", "s", data_sha256); + declare_function("sha256", "s", "s", string_sha256); + + declare_function("checksum32", "ii", "i", data_checksum32); + declare_function("checksum32", "s", "i", string_checksum32); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + YR_HASH_TABLE* hash_table; + + FAIL_ON_ERROR(yr_hash_table_create(17, &hash_table)); + + module_object->data = hash_table; + + return ERROR_SUCCESS; +} + + +int module_unload( + YR_OBJECT* module_object) +{ + YR_HASH_TABLE* hash_table = (YR_HASH_TABLE*) module_object->data; + + if (hash_table != NULL) + yr_hash_table_destroy( + hash_table, + (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_free); + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/macho.c b/yara-master/libyara/modules/macho.c new file mode 100644 index 0000000..22b4309 --- /dev/null +++ b/yara-master/libyara/modules/macho.c @@ -0,0 +1,1170 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include +#include + +#define MODULE_NAME macho + + +// Check for Mach-O binary magic constant. + +int is_macho_file_block( + const uint32_t* magic) +{ + return *magic == MH_MAGIC + || *magic == MH_CIGAM + || *magic == MH_MAGIC_64 + || *magic == MH_CIGAM_64; +} + + +// Check if file is for 32-bit architecture. + +int macho_is_32( + const uint8_t* magic) +{ + // Magic must be [CE]FAEDFE or FEEDFA[CE]. + return magic[0] == 0xce || magic[3] == 0xce; +} + + +// Check if file is for big-endian architecture. + +int macho_is_big( + const uint8_t* magic) +{ + // Magic must be [FE]EDFACE or [FE]EDFACF. + return magic[0] == 0xfe; +} + + +// Check for Mach-O fat binary magic constant. + +int is_fat_macho_file_block( + const uint32_t* magic) +{ + return *magic == FAT_MAGIC + || *magic == FAT_CIGAM + || *magic == FAT_MAGIC_64 + || *magic == FAT_CIGAM_64; +} + + +// Check if file is 32-bit fat file. + +int macho_fat_is_32( + const uint8_t* magic) +{ + // Magic must be CAFEBA[BE]. + return magic[3] == 0xbe; +} + + +// Convert virtual address to file offset. Segments have to be already loaded. + +int macho_rva_to_offset( + uint64_t address, + uint64_t* result, + YR_OBJECT* object) +{ + uint64_t segment_count = get_integer(object, "number_of_segments"); + for (uint64_t i = 0; i < segment_count; i++) + { + uint64_t start = get_integer(object, "segments[%i].vmaddr", i); + uint64_t end = start + get_integer(object, "segments[%i].vmsize", i); + + if (address >= start && address < end) + { + uint64_t fileoff = get_integer(object, "segments[%i].fileoff", i); + *result = fileoff + (address - start); + return TRUE; + } + } + return FALSE; +} + + +// Convert file offset to virtual address. Segments have to be already loaded. + +int macho_offset_to_rva( + uint64_t offset, + uint64_t* result, + YR_OBJECT* object) +{ + uint64_t segment_count = get_integer(object, "number_of_segments"); + for (uint64_t i = 0; i < segment_count; i++) + { + uint64_t start = get_integer(object, "segments[%i].fileoff", i); + uint64_t end = start + get_integer(object, "segments[%i].filesize", i); + + if (offset >= start && offset < end) + { + uint64_t vmaddr = get_integer(object, "segments[%i].vmaddr", i); + *result = vmaddr + (offset - start); + return TRUE; + } + } + return FALSE; +} + + +// Get entry point address from LC_UNIXTHREAD load command. + +#define MACHO_HANDLE_UNIXTHREAD(bo) \ +void macho_handle_unixthread_##bo( \ + void* command, \ + YR_OBJECT* object, \ + YR_SCAN_CONTEXT* context) \ +{ \ + command = (void*)((uint8_t*)command + sizeof(thread_command_t)); \ + uint64_t address = 0; \ + \ + switch (get_integer(object, "cputype")) \ + { \ + case CPU_TYPE_MC680X0: \ + { \ + m68k_thread_state_t* m68k_state = (m68k_thread_state_t*)command; \ + address = yr_##bo##32toh(m68k_state->pc); \ + break; \ + } \ + case CPU_TYPE_MC88000: \ + { \ + m88k_thread_state_t* m88k_state = (m88k_thread_state_t*)command; \ + address = yr_##bo##32toh(m88k_state->xip); \ + break; \ + } \ + case CPU_TYPE_SPARC: \ + { \ + sparc_thread_state_t* sparc_state = (sparc_thread_state_t*)command; \ + address = yr_##bo##32toh(sparc_state->pc); \ + break; \ + } \ + case CPU_TYPE_POWERPC: \ + { \ + ppc_thread_state_t* ppc_state = (ppc_thread_state_t*)command; \ + address = yr_##bo##32toh(ppc_state->srr0); \ + break; \ + } \ + case CPU_TYPE_X86: \ + { \ + x86_thread_state_t* x86_state = (x86_thread_state_t*)command; \ + address = yr_##bo##32toh(x86_state->eip); \ + break; \ + } \ + case CPU_TYPE_ARM: \ + { \ + arm_thread_state_t* arm_state = (arm_thread_state_t*)command; \ + address = yr_##bo##32toh(arm_state->pc); \ + break; \ + } \ + case CPU_TYPE_X86_64: \ + { \ + x86_thread_state64_t* x64_state = (x86_thread_state64_t*)command; \ + address = yr_##bo##64toh(x64_state->rip); \ + break; \ + } \ + case CPU_TYPE_ARM64: \ + { \ + arm_thread_state64_t* arm64_state = (arm_thread_state64_t*)command; \ + address = yr_##bo##64toh(arm64_state->pc); \ + break; \ + } \ + case CPU_TYPE_POWERPC64: \ + { \ + ppc_thread_state64_t* ppc64_state = (ppc_thread_state64_t*)command; \ + address = yr_##bo##64toh(ppc64_state->srr0); \ + break; \ + } \ + \ + default: \ + return; \ + } \ + \ + if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) \ + { \ + set_integer(address, object, "entry_point"); \ + } \ + else \ + { \ + uint64_t offset = 0; \ + if (macho_rva_to_offset(address, &offset, object)) \ + { \ + set_integer(offset, object, "entry_point"); \ + } \ + } \ +} \ + +MACHO_HANDLE_UNIXTHREAD(le) +MACHO_HANDLE_UNIXTHREAD(be) + + +// Get entry point offset and stack-size from LC_MAIN load command. + +#define MACHO_HANDLE_MAIN(bo) \ +void macho_handle_main_##bo( \ + void* command, \ + YR_OBJECT* object, \ + YR_SCAN_CONTEXT* context) \ +{ \ + entry_point_command_t* ep_command = (entry_point_command_t*)command; \ + \ + uint64_t offset = yr_##bo##64toh(ep_command->entryoff); \ + if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) \ + { \ + uint64_t address = 0; \ + if (macho_offset_to_rva(offset, &address, object)) \ + { \ + set_integer(address, object, "entry_point"); \ + } \ + } \ + else \ + { \ + set_integer(offset, object, "entry_point"); \ + } \ + set_integer(yr_##bo##64toh(ep_command->stacksize), object, "stack_size"); \ +} \ + +MACHO_HANDLE_MAIN(le) +MACHO_HANDLE_MAIN(be) + + +// Load segment and its sections. + +#define MACHO_HANDLE_SEGMENT(bits,bo) \ +void macho_handle_segment_##bits##_##bo( \ + const uint8_t* command, \ + const uint64_t i, \ + YR_OBJECT* object) \ +{ \ + segment_command_##bits##_t* sg = (segment_command_##bits##_t*)command; \ + uint64_t command_size = yr_##bo##bits##toh(sg->cmdsize); \ + \ + set_sized_string(sg->segname, strnlen(sg->segname, 16), \ + object, "segments[%i].segname", i); \ + \ + set_integer(yr_##bo##bits##toh(sg->vmaddr), \ + object, "segments[%i].vmaddr", i); \ + set_integer(yr_##bo##bits##toh(sg->vmsize), \ + object, "segments[%i].vmsize", i); \ + set_integer(yr_##bo##bits##toh(sg->fileoff), \ + object, "segments[%i].fileoff", i); \ + set_integer(yr_##bo##bits##toh(sg->filesize), \ + object, "segments[%i].fsize", i); \ + set_integer(yr_##bo##32toh(sg->maxprot), \ + object, "segments[%i].maxprot", i); \ + set_integer(yr_##bo##32toh(sg->initprot), \ + object, "segments[%i].initprot", i); \ + set_integer(yr_##bo##32toh(sg->nsects), \ + object, "segments[%i].nsects", i); \ + set_integer(yr_##bo##32toh(sg->flags), \ + object, "segments[%i].flags", i); \ + \ + uint64_t parsed_size = sizeof(segment_command_##bits##_t); \ + for (unsigned j = 0; j < yr_##bo##32toh(sg->nsects); ++j) \ + { \ + parsed_size += sizeof(section_##bits##_t); \ + if (command_size < parsed_size) \ + break; \ + \ + section_##bits##_t* sec = ((section_##bits##_t*)(sg + 1)) + j; \ + set_sized_string(sec->segname, strnlen(sec->segname, 16), \ + object, "segments[%i].sections[%i].segname", i, j); \ + set_sized_string(sec->sectname, strnlen(sec->sectname, 16), \ + object, "segments[%i].sections[%i].sectname", i, j); \ + \ + set_integer(yr_##bo##bits##toh(sec->addr), \ + object, "segments[%i].sections[%i].addr", i, j); \ + set_integer(yr_##bo##bits##toh(sec->size), \ + object, "segments[%i].sections[%i].size", i, j); \ + set_integer(yr_##bo##32toh(sec->offset), \ + object, "segments[%i].sections[%i].offset", i, j); \ + set_integer(yr_##bo##32toh(sec->align), \ + object, "segments[%i].sections[%i].align", i, j); \ + set_integer(yr_##bo##32toh(sec->reloff), \ + object, "segments[%i].sections[%i].reloff", i, j); \ + set_integer(yr_##bo##32toh(sec->nreloc), \ + object, "segments[%i].sections[%i].nreloc", i, j); \ + set_integer(yr_##bo##32toh(sec->flags), \ + object, "segments[%i].sections[%i].flags", i, j); \ + set_integer(yr_##bo##32toh(sec->reserved1), \ + object, "segments[%i].sections[%i].reserved1", i, j); \ + set_integer(yr_##bo##32toh(sec->reserved2), \ + object, "segments[%i].sections[%i].reserved2", i, j); \ + if (bits == 64) \ + { \ + section_64_t* sec_64 = (section_64_t*)sec; \ + set_integer(yr_##bo##32toh(sec_64->reserved3), \ + object, "segments[%i].sections[%i].reserved3", i, j); \ + } \ + } \ +} \ + +MACHO_HANDLE_SEGMENT(32,le) +MACHO_HANDLE_SEGMENT(64,le) +MACHO_HANDLE_SEGMENT(32,be) +MACHO_HANDLE_SEGMENT(64,be) + + +// Parse Mach-O file with specific bit-width and byte order. + +#define MACHO_PARSE_FILE(bits,bo) \ +void macho_parse_file_##bits##_##bo( \ + const uint8_t* data, \ + const uint64_t size, \ + YR_OBJECT* object, \ + YR_SCAN_CONTEXT* context) \ +{ \ + if (size < sizeof(mach_header_##bits##_t)) \ + return; \ + \ + mach_header_##bits##_t* header = (mach_header_##bits##_t*)data; \ + set_integer(yr_##bo##32toh(header->magic), object, "magic"); \ + set_integer(yr_##bo##32toh(header->cputype), object, "cputype"); \ + set_integer(yr_##bo##32toh(header->cpusubtype), object, "cpusubtype"); \ + set_integer(yr_##bo##32toh(header->filetype), object, "filetype"); \ + set_integer(yr_##bo##32toh(header->ncmds), object, "ncmds"); \ + set_integer(yr_##bo##32toh(header->sizeofcmds), object, "sizeofcmds"); \ + set_integer(yr_##bo##32toh(header->flags), object, "flags"); \ + if (bits == 64) \ + { \ + mach_header_64_t* header_64 = (mach_header_64_t*)data; \ + set_integer(yr_##bo##32toh(header_64->reserved), object, "reserved"); \ + } \ + \ + uint64_t seg_count = 0; \ + uint64_t parsed_size = sizeof(mach_header_##bits##_t); \ + \ + uint8_t *command = (uint8_t*)(header + 1); \ + for (unsigned i = 0; i < yr_##bo##32toh(header->ncmds); i++) \ + { \ + load_command_t* command_struct = (load_command_t*)command; \ + uint64_t command_size = yr_##bo##32toh(command_struct->cmdsize); \ + \ + if (size < parsed_size + command_size) \ + break; \ + \ + switch(yr_##bo##32toh(command_struct->cmd)) \ + { \ + case LC_SEGMENT: \ + case LC_SEGMENT_64: \ + { \ + macho_handle_segment_##bits##_##bo(command, seg_count++, object); \ + break; \ + } \ + case LC_UNIXTHREAD: \ + { \ + macho_handle_unixthread_##bo(command, object, context); \ + break; \ + } \ + case LC_MAIN: \ + { \ + macho_handle_main_##bo(command, object, context); \ + break; \ + } \ + } \ + \ + command += command_size; \ + parsed_size += command_size; \ + } \ + \ + set_integer(seg_count, object, "number_of_segments"); \ +} \ + +MACHO_PARSE_FILE(32,le) +MACHO_PARSE_FILE(64,le) +MACHO_PARSE_FILE(32,be) +MACHO_PARSE_FILE(64,be) + + +// Parse Mach-O file. + +void macho_parse_file( + const uint8_t* data, + const uint64_t size, + YR_OBJECT* object, + YR_SCAN_CONTEXT* context) +{ + if (macho_is_32(data)) + { + if (macho_is_big(data)) { + // 32-bit big endian + macho_parse_file_32_be(data, size, object, context); + } + else { + // 32-bit little endian + macho_parse_file_32_le(data, size, object, context); + } + } + else + { + if (macho_is_big(data)) { + // 64-bit big endian + macho_parse_file_64_be(data, size, object, context); + } + else { + // 64-bit little endian + macho_parse_file_64_le(data, size, object, context); + } + } +} + + +// Parse Mach-O fat file with specific bit-width. + +#define MACHO_PARSE_FAT_FILE(bits) \ +void macho_parse_fat_file_##bits( \ + const uint8_t* data, \ + const uint64_t size, \ + YR_OBJECT* object, \ + YR_SCAN_CONTEXT* context) \ +{ \ + if (size < sizeof(fat_header_t)) \ + return; \ + \ + /* All data in Mach-O fat binary headers are in big-endian byte order. */ \ + \ + const fat_header_t* header = (fat_header_t*)data; \ + set_integer(yr_be32toh(header->magic), object, "fat_magic"); \ + \ + uint32_t count = yr_be32toh(header->nfat_arch); \ + set_integer(count, object, "nfat_arch"); \ + \ + if (size < sizeof(fat_header_t) + count * sizeof(fat_arch_##bits##_t)) \ + return; \ + \ + fat_arch_##bits##_t* archs = (fat_arch_##bits##_t*)(header + 1); \ + for (uint32_t i = 0; i < count; i++) \ + { \ + set_integer(yr_be32toh(archs[i].cputype), \ + object, "fat_arch[%i].cputype", i); \ + set_integer(yr_be32toh(archs[i].cpusubtype), \ + object, "fat_arch[%i].cpusubtype", i); \ + \ + uint64_t offset = yr_be##bits##toh(archs[i].offset); \ + set_integer(offset, object, "fat_arch[%i].offset", i); \ + uint64_t file_size = yr_be##bits##toh(archs[i].size); \ + set_integer(file_size, object, "fat_arch[%i].size", i); \ + \ + set_integer(yr_be32toh(archs[i].align), \ + object, "fat_arch[%i].align", i); \ + \ + if (size < offset + file_size) \ + continue; \ + \ + /* Force 'file' array entry creation. */ \ + set_integer(UNDEFINED, object, "file[%i].magic", i); \ + \ + /* Get specific Mach-O file data. */ \ + macho_parse_file(data + offset, file_size, \ + get_object(object, "file[%i]", i), context); \ + } \ +} \ + +MACHO_PARSE_FAT_FILE(32) +MACHO_PARSE_FAT_FILE(64) + + +// Parse Mach-O fat file. + +void macho_parse_fat_file( + const uint8_t* data, + const uint64_t size, + YR_OBJECT* object, + YR_SCAN_CONTEXT* context) +{ + if (macho_fat_is_32(data)) { + // 32-bit fat binary + macho_parse_fat_file_32(data, size, object, context); + } + else { + // 64-bit fat binary + macho_parse_fat_file_64(data, size, object, context); + } +} + + +// Sets all necessary Mach-O constants and definitions. + +void macho_set_definitions( + YR_OBJECT* object) +{ + // Magic constants + + set_integer(MH_MAGIC, object, "MH_MAGIC"); + set_integer(MH_CIGAM, object, "MH_CIGAM"); + set_integer(MH_MAGIC_64, object, "MH_MAGIC_64"); + set_integer(MH_CIGAM_64, object, "MH_CIGAM_64"); + + // Fat magic constants + + set_integer(FAT_MAGIC, object, "FAT_MAGIC"); + set_integer(FAT_CIGAM, object, "FAT_CIGAM"); + set_integer(FAT_MAGIC_64, object, "FAT_MAGIC_64"); + set_integer(FAT_CIGAM_64, object, "FAT_CIGAM_64"); + + // 64-bit masks + + set_integer(CPU_ARCH_ABI64, object, "CPU_ARCH_ABI64"); + set_integer(CPU_SUBTYPE_LIB64, object, "CPU_SUBTYPE_LIB64"); + + // CPU types + + set_integer(CPU_TYPE_MC680X0, object, "CPU_TYPE_MC680X0"); + set_integer(CPU_TYPE_X86, object, "CPU_TYPE_X86"); + set_integer(CPU_TYPE_X86, object, "CPU_TYPE_I386"); + set_integer(CPU_TYPE_X86_64, object, "CPU_TYPE_X86_64"); + set_integer(CPU_TYPE_MIPS, object, "CPU_TYPE_MIPS"); + set_integer(CPU_TYPE_MC98000, object, "CPU_TYPE_MC98000"); + set_integer(CPU_TYPE_ARM, object, "CPU_TYPE_ARM"); + set_integer(CPU_TYPE_ARM64, object, "CPU_TYPE_ARM64"); + set_integer(CPU_TYPE_MC88000, object, "CPU_TYPE_MC88000"); + set_integer(CPU_TYPE_SPARC, object, "CPU_TYPE_SPARC"); + set_integer(CPU_TYPE_POWERPC, object, "CPU_TYPE_POWERPC"); + set_integer(CPU_TYPE_POWERPC64, object, "CPU_TYPE_POWERPC64"); + + // CPU sub-types + + set_integer(CPU_SUBTYPE_INTEL_MODEL_ALL, object, + "CPU_SUBTYPE_INTEL_MODEL_ALL"); + set_integer(CPU_SUBTYPE_386, object,"CPU_SUBTYPE_386"); + set_integer(CPU_SUBTYPE_386, object,"CPU_SUBTYPE_I386_ALL"); + set_integer(CPU_SUBTYPE_386, object,"CPU_SUBTYPE_X86_64_ALL"); + set_integer(CPU_SUBTYPE_486, object, "CPU_SUBTYPE_486"); + set_integer(CPU_SUBTYPE_486SX, object, "CPU_SUBTYPE_486SX"); + set_integer(CPU_SUBTYPE_586, object, "CPU_SUBTYPE_586"); + set_integer(CPU_SUBTYPE_PENT, object, "CPU_SUBTYPE_PENT"); + set_integer(CPU_SUBTYPE_PENTPRO, object, "CPU_SUBTYPE_PENTPRO"); + set_integer(CPU_SUBTYPE_PENTII_M3, object, "CPU_SUBTYPE_PENTII_M3"); + set_integer(CPU_SUBTYPE_PENTII_M5, object, "CPU_SUBTYPE_PENTII_M5"); + set_integer(CPU_SUBTYPE_CELERON, object, "CPU_SUBTYPE_CELERON"); + set_integer(CPU_SUBTYPE_CELERON_MOBILE, object, + "CPU_SUBTYPE_CELERON_MOBILE"); + set_integer(CPU_SUBTYPE_PENTIUM_3, object, "CPU_SUBTYPE_PENTIUM_3"); + set_integer(CPU_SUBTYPE_PENTIUM_3_M, object, "CPU_SUBTYPE_PENTIUM_3_M"); + set_integer(CPU_SUBTYPE_PENTIUM_3_XEON, object, + "CPU_SUBTYPE_PENTIUM_3_XEON"); + set_integer(CPU_SUBTYPE_PENTIUM_M, object, "CPU_SUBTYPE_PENTIUM_M"); + set_integer(CPU_SUBTYPE_PENTIUM_4, object, "CPU_SUBTYPE_PENTIUM_4"); + set_integer(CPU_SUBTYPE_PENTIUM_4_M, object, "CPU_SUBTYPE_PENTIUM_4_M"); + set_integer(CPU_SUBTYPE_ITANIUM, object, "CPU_SUBTYPE_ITANIUM"); + set_integer(CPU_SUBTYPE_ITANIUM_2, object, "CPU_SUBTYPE_ITANIUM_2"); + set_integer(CPU_SUBTYPE_XEON, object, "CPU_SUBTYPE_XEON"); + set_integer(CPU_SUBTYPE_XEON_MP, object, "CPU_SUBTYPE_XEON_MP"); + set_integer(CPU_SUBTYPE_ARM_ALL, object, "CPU_SUBTYPE_ARM_ALL"); + set_integer(CPU_SUBTYPE_ARM_V4T, object, "CPU_SUBTYPE_ARM_V4T"); + set_integer(CPU_SUBTYPE_ARM_V6, object, "CPU_SUBTYPE_ARM_V6"); + set_integer(CPU_SUBTYPE_ARM_V5, object, "CPU_SUBTYPE_ARM_V5"); + set_integer(CPU_SUBTYPE_ARM_V5TEJ, object, "CPU_SUBTYPE_ARM_V5TEJ"); + set_integer(CPU_SUBTYPE_ARM_XSCALE, object, "CPU_SUBTYPE_ARM_XSCALE"); + set_integer(CPU_SUBTYPE_ARM_V7, object, "CPU_SUBTYPE_ARM_V7"); + set_integer(CPU_SUBTYPE_ARM_V7F, object, "CPU_SUBTYPE_ARM_V7F"); + set_integer(CPU_SUBTYPE_ARM_V7S, object, "CPU_SUBTYPE_ARM_V7S"); + set_integer(CPU_SUBTYPE_ARM_V7K, object, "CPU_SUBTYPE_ARM_V7K"); + set_integer(CPU_SUBTYPE_ARM_V6M, object, "CPU_SUBTYPE_ARM_V6M"); + set_integer(CPU_SUBTYPE_ARM_V7M, object, "CPU_SUBTYPE_ARM_V7M"); + set_integer(CPU_SUBTYPE_ARM_V7EM, object, "CPU_SUBTYPE_ARM_V7EM"); + set_integer(CPU_SUBTYPE_ARM64_ALL, object, "CPU_SUBTYPE_ARM64_ALL"); + set_integer(CPU_SUBTYPE_SPARC_ALL, object, "CPU_SUBTYPE_SPARC_ALL"); + set_integer(CPU_SUBTYPE_POWERPC_ALL, object, "CPU_SUBTYPE_POWERPC_ALL"); + set_integer(CPU_SUBTYPE_MC980000_ALL, object, "CPU_SUBTYPE_MC980000_ALL"); + set_integer(CPU_SUBTYPE_POWERPC_601, object, "CPU_SUBTYPE_POWERPC_601"); + set_integer(CPU_SUBTYPE_MC98601, object, "CPU_SUBTYPE_MC98601"); + set_integer(CPU_SUBTYPE_POWERPC_602, object, "CPU_SUBTYPE_POWERPC_602"); + set_integer(CPU_SUBTYPE_POWERPC_603, object, "CPU_SUBTYPE_POWERPC_603"); + set_integer(CPU_SUBTYPE_POWERPC_603e, object, "CPU_SUBTYPE_POWERPC_603e"); + set_integer(CPU_SUBTYPE_POWERPC_603ev, object, "CPU_SUBTYPE_POWERPC_603ev"); + set_integer(CPU_SUBTYPE_POWERPC_604, object, "CPU_SUBTYPE_POWERPC_604"); + set_integer(CPU_SUBTYPE_POWERPC_604e, object, "CPU_SUBTYPE_POWERPC_604e"); + set_integer(CPU_SUBTYPE_POWERPC_620, object, "CPU_SUBTYPE_POWERPC_620"); + set_integer(CPU_SUBTYPE_POWERPC_750, object, "CPU_SUBTYPE_POWERPC_750"); + set_integer(CPU_SUBTYPE_POWERPC_7400, object, "CPU_SUBTYPE_POWERPC_7400"); + set_integer(CPU_SUBTYPE_POWERPC_7450, object, "CPU_SUBTYPE_POWERPC_7450"); + set_integer(CPU_SUBTYPE_POWERPC_970, object, "CPU_SUBTYPE_POWERPC_970"); + + // File types + + set_integer(MH_OBJECT, object, "MH_OBJECT"); + set_integer(MH_EXECUTE, object, "MH_EXECUTE"); + set_integer(MH_FVMLIB, object, "MH_FVMLIB"); + set_integer(MH_CORE, object, "MH_CORE"); + set_integer(MH_PRELOAD, object, "MH_PRELOAD"); + set_integer(MH_DYLIB, object, "MH_DYLIB"); + set_integer(MH_DYLINKER, object, "MH_DYLINKER"); + set_integer(MH_BUNDLE, object, "MH_BUNDLE"); + set_integer(MH_DYLIB_STUB, object, "MH_DYLIB_STUB"); + set_integer(MH_DSYM, object, "MH_DSYM"); + set_integer(MH_KEXT_BUNDLE, object, "MH_KEXT_BUNDLE"); + + // Header flags + + set_integer(MH_NOUNDEFS, object, "MH_NOUNDEFS"); + set_integer(MH_INCRLINK, object, "MH_INCRLINK"); + set_integer(MH_DYLDLINK, object, "MH_DYLDLINK"); + set_integer(MH_BINDATLOAD, object, "MH_BINDATLOAD"); + set_integer(MH_PREBOUND, object, "MH_PREBOUND"); + set_integer(MH_SPLIT_SEGS, object, "MH_SPLIT_SEGS"); + set_integer(MH_LAZY_INIT, object, "MH_LAZY_INIT"); + set_integer(MH_TWOLEVEL, object, "MH_TWOLEVEL"); + set_integer(MH_FORCE_FLAT, object, "MH_FORCE_FLAT"); + set_integer(MH_NOMULTIDEFS, object, "MH_NOMULTIDEFS"); + set_integer(MH_NOFIXPREBINDING, object, "MH_NOFIXPREBINDING"); + set_integer(MH_PREBINDABLE, object, "MH_PREBINDABLE"); + set_integer(MH_ALLMODSBOUND, object, "MH_ALLMODSBOUND"); + set_integer(MH_SUBSECTIONS_VIA_SYMBOLS, object, + "MH_SUBSECTIONS_VIA_SYMBOLS"); + set_integer(MH_CANONICAL, object, "MH_CANONICAL"); + set_integer(MH_WEAK_DEFINES, object, "MH_WEAK_DEFINES"); + set_integer(MH_BINDS_TO_WEAK, object, "MH_BINDS_TO_WEAK"); + set_integer(MH_ALLOW_STACK_EXECUTION, object, "MH_ALLOW_STACK_EXECUTION"); + set_integer(MH_ROOT_SAFE, object, "MH_ROOT_SAFE"); + set_integer(MH_SETUID_SAFE, object, "MH_SETUID_SAFE"); + set_integer(MH_NO_REEXPORTED_DYLIBS, object, "MH_NO_REEXPORTED_DYLIBS"); + set_integer(MH_PIE, object, "MH_PIE"); + set_integer(MH_DEAD_STRIPPABLE_DYLIB, object, "MH_DEAD_STRIPPABLE_DYLIB"); + set_integer(MH_HAS_TLV_DESCRIPTORS, object, "MH_HAS_TLV_DESCRIPTORS"); + set_integer(MH_NO_HEAP_EXECUTION, object, "MH_NO_HEAP_EXECUTION"); + set_integer(MH_APP_EXTENSION_SAFE, object, "MH_APP_EXTENSION_SAFE"); + + // Segment flags masks + + set_integer(SG_HIGHVM, object, "SG_HIGHVM"); + set_integer(SG_FVMLIB, object, "SG_FVMLIB"); + set_integer(SG_NORELOC, object, "SG_NORELOC"); + set_integer(SG_PROTECTED_VERSION_1, object, "SG_PROTECTED_VERSION_1"); + + // Section flags masks + + set_integer(SECTION_TYPE, object, "SECTION_TYPE"); + set_integer(SECTION_ATTRIBUTES, object, "SECTION_ATTRIBUTES"); + + // Section types + + set_integer(S_REGULAR, object, "S_REGULAR"); + set_integer(S_ZEROFILL, object, "S_ZEROFILL"); + set_integer(S_CSTRING_LITERALS, object, "S_CSTRING_LITERALS"); + set_integer(S_4BYTE_LITERALS, object, "S_4BYTE_LITERALS"); + set_integer(S_8BYTE_LITERALS, object, "S_8BYTE_LITERALS"); + set_integer(S_NON_LAZY_SYMBOL_POINTERS, object, + "S_NON_LAZY_SYMBOL_POINTERS"); + set_integer(S_LAZY_SYMBOL_POINTERS, object, "S_LAZY_SYMBOL_POINTERS"); + set_integer(S_LITERAL_POINTERS, object, "S_LITERAL_POINTERS"); + set_integer(S_SYMBOL_STUBS, object, "S_SYMBOL_STUBS"); + set_integer(S_MOD_INIT_FUNC_POINTERS, object, "S_MOD_INIT_FUNC_POINTERS"); + set_integer(S_MOD_TERM_FUNC_POINTERS, object, "S_MOD_TERM_FUNC_POINTERS"); + set_integer(S_COALESCED, object, "S_COALESCED"); + set_integer(S_GB_ZEROFILL, object, "S_GB_ZEROFILL"); + set_integer(S_INTERPOSING, object, "S_INTERPOSING"); + set_integer(S_16BYTE_LITERALS, object, "S_16BYTE_LITERALS"); + set_integer(S_DTRACE_DOF, object, "S_DTRACE_DOF"); + set_integer(S_LAZY_DYLIB_SYMBOL_POINTERS, object, + "S_LAZY_DYLIB_SYMBOL_POINTERS"); + set_integer(S_THREAD_LOCAL_REGULAR, object, "S_THREAD_LOCAL_REGULAR"); + set_integer(S_THREAD_LOCAL_ZEROFILL, object, "S_THREAD_LOCAL_ZEROFILL"); + set_integer(S_THREAD_LOCAL_VARIABLES, object, "S_THREAD_LOCAL_VARIABLES"); + set_integer(S_THREAD_LOCAL_VARIABLE_POINTERS, object, + "S_THREAD_LOCAL_VARIABLE_POINTERS"); + set_integer(S_THREAD_LOCAL_INIT_FUNCTION_POINTERS, object, + "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS"); + + // Section attributes + + set_integer(S_ATTR_PURE_INSTRUCTIONS, object, "S_ATTR_PURE_INSTRUCTIONS"); + set_integer(S_ATTR_NO_TOC, object, "S_ATTR_NO_TOC"); + set_integer(S_ATTR_STRIP_STATIC_SYMS, object, "S_ATTR_STRIP_STATIC_SYMS"); + set_integer(S_ATTR_NO_DEAD_STRIP, object, "S_ATTR_NO_DEAD_STRIP"); + set_integer(S_ATTR_LIVE_SUPPORT, object, "S_ATTR_LIVE_SUPPORT"); + set_integer(S_ATTR_SELF_MODIFYING_CODE, object, + "S_ATTR_SELF_MODIFYING_CODE"); + set_integer(S_ATTR_DEBUG, object, "S_ATTR_DEBUG"); + set_integer(S_ATTR_SOME_INSTRUCTIONS, object, "S_ATTR_SOME_INSTRUCTIONS"); + set_integer(S_ATTR_EXT_RELOC, object, "S_ATTR_EXT_RELOC"); + set_integer(S_ATTR_LOC_RELOC, object, "S_ATTR_LOC_RELOC"); +} + + +// Get Mach-O file index in fat file by cputype field. + +define_function(file_index_type) +{ + YR_OBJECT* module = module(); + int64_t type_arg = integer_argument(1); + + uint64_t nfat = get_integer(module, "nfat_arch"); + if (is_undefined(module, "nfat_arch")) + return_integer(UNDEFINED); + + for (uint64_t i = 0; i < nfat; i++) + { + int64_t type = get_integer(module, "file[%i].cputype", i); + if (type == type_arg) + { + return_integer(i); + } + } + return_integer(UNDEFINED); +} + + +// Get Mach-O file index in fat file by cputype and cpusubtype fields. + +define_function(file_index_subtype) +{ + YR_OBJECT* module = module(); + int64_t type_arg = integer_argument(1); + int64_t subtype_arg = integer_argument(2); + + uint64_t nfat = get_integer(module, "nfat_arch"); + if (is_undefined(module, "nfat_arch")) + return_integer(UNDEFINED); + + for (uint64_t i = 0; i < nfat; i++) + { + int64_t type = get_integer(module, "file[%i].cputype", i); + int64_t subtype = get_integer(module, "file[%i].cpusubtype", i); + + if (type == type_arg && subtype == subtype_arg) + { + return_integer(i); + } + } + return_integer(UNDEFINED); +} + + +// Get real entry point offset for specific architecture in fat Mach-O. + +define_function(ep_for_arch_type) +{ + YR_OBJECT* module = module(); + int64_t type_arg = integer_argument(1); + + uint64_t nfat = get_integer(module, "nfat_arch"); + if (is_undefined(module, "nfat_arch")) + return_integer(UNDEFINED); + + for (uint64_t i = 0; i < nfat; i++) + { + int64_t type = get_integer(module, "fat_arch[%i].cputype", i); + if (type == type_arg) + { + uint64_t file_offset = get_integer(module, "fat_arch[%i].offset", i); + uint64_t entry_point = get_integer(module, "file[%i].entry_point", i); + return_integer(file_offset + entry_point); + } + } + return_integer(UNDEFINED); +} + + +// Get real entry point offset for specific architecture in fat Mach-O. + +define_function(ep_for_arch_subtype) +{ + YR_OBJECT* module = module(); + int64_t type_arg = integer_argument(1); + int64_t subtype_arg = integer_argument(2); + + uint64_t nfat = get_integer(module, "nfat_arch"); + if (is_undefined(module, "nfat_arch")) + return_integer(UNDEFINED); + + for (uint64_t i = 0; i < nfat; i++) + { + int64_t type = get_integer(module, "fat_arch[%i].cputype", i); + int64_t subtype = get_integer(module, "fat_arch[%i].cpusubtype", i); + if (type == type_arg && subtype == subtype_arg) + { + uint64_t file_offset = get_integer(module, "fat_arch[%i].offset", i); + uint64_t entry_point = get_integer(module, "file[%i].entry_point", i); + return_integer(file_offset + entry_point); + } + } + return_integer(UNDEFINED); +} + + +begin_declarations; + + // Magic constants + + declare_integer("MH_MAGIC"); + declare_integer("MH_CIGAM"); + declare_integer("MH_MAGIC_64"); + declare_integer("MH_CIGAM_64"); + + // Fat magic constants + + declare_integer("FAT_MAGIC"); + declare_integer("FAT_CIGAM"); + declare_integer("FAT_MAGIC_64"); + declare_integer("FAT_CIGAM_64"); + + // 64-bit masks + + declare_integer("CPU_ARCH_ABI64"); + declare_integer("CPU_SUBTYPE_LIB64"); + + // CPU types + + declare_integer("CPU_TYPE_MC680X0"); + declare_integer("CPU_TYPE_X86"); + declare_integer("CPU_TYPE_I386"); + declare_integer("CPU_TYPE_X86_64"); + declare_integer("CPU_TYPE_MIPS"); + declare_integer("CPU_TYPE_MC98000"); + declare_integer("CPU_TYPE_ARM"); + declare_integer("CPU_TYPE_ARM64"); + declare_integer("CPU_TYPE_MC88000"); + declare_integer("CPU_TYPE_SPARC"); + declare_integer("CPU_TYPE_POWERPC"); + declare_integer("CPU_TYPE_POWERPC64"); + + // CPU sub-types + + declare_integer("CPU_SUBTYPE_INTEL_MODEL_ALL"); + declare_integer("CPU_SUBTYPE_386"); + declare_integer("CPU_SUBTYPE_I386_ALL"); + declare_integer("CPU_SUBTYPE_X86_64_ALL"); + declare_integer("CPU_SUBTYPE_486"); + declare_integer("CPU_SUBTYPE_486SX"); + declare_integer("CPU_SUBTYPE_586"); + declare_integer("CPU_SUBTYPE_PENT"); + declare_integer("CPU_SUBTYPE_PENTPRO"); + declare_integer("CPU_SUBTYPE_PENTII_M3"); + declare_integer("CPU_SUBTYPE_PENTII_M5"); + declare_integer("CPU_SUBTYPE_CELERON"); + declare_integer("CPU_SUBTYPE_CELERON_MOBILE"); + declare_integer("CPU_SUBTYPE_PENTIUM_3"); + declare_integer("CPU_SUBTYPE_PENTIUM_3_M"); + declare_integer("CPU_SUBTYPE_PENTIUM_3_XEON"); + declare_integer("CPU_SUBTYPE_PENTIUM_M"); + declare_integer("CPU_SUBTYPE_PENTIUM_4"); + declare_integer("CPU_SUBTYPE_PENTIUM_4_M"); + declare_integer("CPU_SUBTYPE_ITANIUM"); + declare_integer("CPU_SUBTYPE_ITANIUM_2"); + declare_integer("CPU_SUBTYPE_XEON"); + declare_integer("CPU_SUBTYPE_XEON_MP"); + declare_integer("CPU_SUBTYPE_ARM_ALL"); + declare_integer("CPU_SUBTYPE_ARM_V4T"); + declare_integer("CPU_SUBTYPE_ARM_V6"); + declare_integer("CPU_SUBTYPE_ARM_V5"); + declare_integer("CPU_SUBTYPE_ARM_V5TEJ"); + declare_integer("CPU_SUBTYPE_ARM_XSCALE"); + declare_integer("CPU_SUBTYPE_ARM_V7"); + declare_integer("CPU_SUBTYPE_ARM_V7F"); + declare_integer("CPU_SUBTYPE_ARM_V7S"); + declare_integer("CPU_SUBTYPE_ARM_V7K"); + declare_integer("CPU_SUBTYPE_ARM_V6M"); + declare_integer("CPU_SUBTYPE_ARM_V7M"); + declare_integer("CPU_SUBTYPE_ARM_V7EM"); + declare_integer("CPU_SUBTYPE_ARM64_ALL"); + declare_integer("CPU_SUBTYPE_SPARC_ALL"); + declare_integer("CPU_SUBTYPE_POWERPC_ALL"); + declare_integer("CPU_SUBTYPE_MC980000_ALL"); + declare_integer("CPU_SUBTYPE_POWERPC_601"); + declare_integer("CPU_SUBTYPE_MC98601"); + declare_integer("CPU_SUBTYPE_POWERPC_602"); + declare_integer("CPU_SUBTYPE_POWERPC_603"); + declare_integer("CPU_SUBTYPE_POWERPC_603e"); + declare_integer("CPU_SUBTYPE_POWERPC_603ev"); + declare_integer("CPU_SUBTYPE_POWERPC_604"); + declare_integer("CPU_SUBTYPE_POWERPC_604e"); + declare_integer("CPU_SUBTYPE_POWERPC_620"); + declare_integer("CPU_SUBTYPE_POWERPC_750"); + declare_integer("CPU_SUBTYPE_POWERPC_7400"); + declare_integer("CPU_SUBTYPE_POWERPC_7450"); + declare_integer("CPU_SUBTYPE_POWERPC_970"); + + // File types + + declare_integer("MH_OBJECT"); + declare_integer("MH_EXECUTE"); + declare_integer("MH_FVMLIB"); + declare_integer("MH_CORE"); + declare_integer("MH_PRELOAD"); + declare_integer("MH_DYLIB"); + declare_integer("MH_DYLINKER"); + declare_integer("MH_BUNDLE"); + declare_integer("MH_DYLIB_STUB"); + declare_integer("MH_DSYM"); + declare_integer("MH_KEXT_BUNDLE"); + + // Header flags + + declare_integer("MH_NOUNDEFS"); + declare_integer("MH_INCRLINK"); + declare_integer("MH_DYLDLINK"); + declare_integer("MH_BINDATLOAD"); + declare_integer("MH_PREBOUND"); + declare_integer("MH_SPLIT_SEGS"); + declare_integer("MH_LAZY_INIT"); + declare_integer("MH_TWOLEVEL"); + declare_integer("MH_FORCE_FLAT"); + declare_integer("MH_NOMULTIDEFS"); + declare_integer("MH_NOFIXPREBINDING"); + declare_integer("MH_PREBINDABLE"); + declare_integer("MH_ALLMODSBOUND"); + declare_integer("MH_SUBSECTIONS_VIA_SYMBOLS"); + declare_integer("MH_CANONICAL"); + declare_integer("MH_WEAK_DEFINES"); + declare_integer("MH_BINDS_TO_WEAK"); + declare_integer("MH_ALLOW_STACK_EXECUTION"); + declare_integer("MH_ROOT_SAFE"); + declare_integer("MH_SETUID_SAFE"); + declare_integer("MH_NO_REEXPORTED_DYLIBS"); + declare_integer("MH_PIE"); + declare_integer("MH_DEAD_STRIPPABLE_DYLIB"); + declare_integer("MH_HAS_TLV_DESCRIPTORS"); + declare_integer("MH_NO_HEAP_EXECUTION"); + declare_integer("MH_APP_EXTENSION_SAFE"); + + // Segment flags + + declare_integer("SG_HIGHVM"); + declare_integer("SG_FVMLIB"); + declare_integer("SG_NORELOC"); + declare_integer("SG_PROTECTED_VERSION_1"); + + // Section masks + + declare_integer("SECTION_TYPE"); + declare_integer("SECTION_ATTRIBUTES"); + + // Section types + + declare_integer("S_REGULAR"); + declare_integer("S_ZEROFILL"); + declare_integer("S_CSTRING_LITERALS"); + declare_integer("S_4BYTE_LITERALS"); + declare_integer("S_8BYTE_LITERALS"); + declare_integer("S_LITERAL_POINTERS"); + declare_integer("S_NON_LAZY_SYMBOL_POINTERS"); + declare_integer("S_LAZY_SYMBOL_POINTERS"); + declare_integer("S_SYMBOL_STUBS"); + declare_integer("S_MOD_INIT_FUNC_POINTERS"); + declare_integer("S_MOD_TERM_FUNC_POINTERS"); + declare_integer("S_COALESCED"); + declare_integer("S_GB_ZEROFILL"); + declare_integer("S_INTERPOSING"); + declare_integer("S_16BYTE_LITERALS"); + declare_integer("S_DTRACE_DOF"); + declare_integer("S_LAZY_DYLIB_SYMBOL_POINTERS"); + declare_integer("S_THREAD_LOCAL_REGULAR"); + declare_integer("S_THREAD_LOCAL_ZEROFILL"); + declare_integer("S_THREAD_LOCAL_VARIABLES"); + declare_integer("S_THREAD_LOCAL_VARIABLE_POINTERS"); + declare_integer("S_THREAD_LOCAL_INIT_FUNCTION_POINTERS"); + + // Section attributes + + declare_integer("S_ATTR_PURE_INSTRUCTIONS"); + declare_integer("S_ATTR_NO_TOC"); + declare_integer("S_ATTR_STRIP_STATIC_SYMS"); + declare_integer("S_ATTR_NO_DEAD_STRIP"); + declare_integer("S_ATTR_LIVE_SUPPORT"); + declare_integer("S_ATTR_SELF_MODIFYING_CODE"); + declare_integer("S_ATTR_DEBUG"); + declare_integer("S_ATTR_SOME_INSTRUCTIONS"); + declare_integer("S_ATTR_EXT_RELOC"); + declare_integer("S_ATTR_LOC_RELOC"); + + // Header + + declare_integer("magic"); + declare_integer("cputype"); + declare_integer("cpusubtype"); + declare_integer("filetype"); + declare_integer("ncmds"); + declare_integer("sizeofcmds"); + declare_integer("flags"); + declare_integer("reserved"); + + // Segments and nested sections + + declare_integer("number_of_segments"); + + begin_struct_array("segments"); + declare_string("segname"); + declare_integer("vmaddr"); + declare_integer("vmsize"); + declare_integer("fileoff"); + declare_integer("fsize"); + declare_integer("maxprot"); + declare_integer("initprot"); + declare_integer("nsects"); + declare_integer("flags"); + begin_struct_array("sections"); + declare_string("sectname"); + declare_string("segname"); + declare_integer("addr"); + declare_integer("size"); + declare_integer("offset"); + declare_integer("align"); + declare_integer("reloff"); + declare_integer("nreloc"); + declare_integer("flags"); + declare_integer("reserved1"); + declare_integer("reserved2"); + declare_integer("reserved3"); + end_struct_array("sections"); + end_struct_array("segments"); + + // Entry point and stack size + + declare_integer("entry_point"); + declare_integer("stack_size"); + + // Mach-O fat binary header + + declare_integer("fat_magic"); + declare_integer("nfat_arch"); + + begin_struct_array("fat_arch"); + declare_integer("cputype"); + declare_integer("cpusubtype"); + declare_integer("offset"); + declare_integer("size"); + declare_integer("align"); + end_struct_array("fat_arch"); + + // Included Mach-O files (must be same as single file structure above) + + begin_struct_array("file"); + + // Single file header + + declare_integer("magic"); + declare_integer("cputype"); + declare_integer("cpusubtype"); + declare_integer("filetype"); + declare_integer("ncmds"); + declare_integer("sizeofcmds"); + declare_integer("flags"); + declare_integer("reserved"); + + // Segments and nested sections + + declare_integer("number_of_segments"); + + begin_struct_array("segments"); + declare_string("segname"); + declare_integer("vmaddr"); + declare_integer("vmsize"); + declare_integer("fileoff"); + declare_integer("fsize"); + declare_integer("maxprot"); + declare_integer("initprot"); + declare_integer("nsects"); + declare_integer("flags"); + begin_struct_array("sections"); + declare_string("sectname"); + declare_string("segname"); + declare_integer("addr"); + declare_integer("size"); + declare_integer("offset"); + declare_integer("align"); + declare_integer("reloff"); + declare_integer("nreloc"); + declare_integer("flags"); + declare_integer("reserved1"); + declare_integer("reserved2"); + declare_integer("reserved3"); + end_struct_array("sections"); + end_struct_array("segments"); + + // Entry point and stack size + + declare_integer("entry_point"); + declare_integer("stack_size"); + + end_struct_array("file"); + + // Mach-O fat binary helper functions + + declare_function("file_index_for_arch", "i", "i", file_index_type); + declare_function("file_index_for_arch", "ii", "i", file_index_subtype); + declare_function("entry_point_for_arch", "i", "i", ep_for_arch_type); + declare_function("entry_point_for_arch", "ii", "i", ep_for_arch_subtype); + +end_declarations; + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + YR_MEMORY_BLOCK* block; + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + foreach_memory_block(iterator, block) + { + const uint8_t* block_data = block->fetch_data(block); + if (block_data == NULL || block->size < 4) + continue; + + // Parse Mach-O binary. + if (is_macho_file_block((uint32_t*)block_data)) + { + macho_parse_file(block_data, block->size, module_object, context); + break; + } + + // Parse fat Mach-O binary. + if (is_fat_macho_file_block((uint32_t*)block_data)) + { + macho_parse_fat_file(block_data, block->size, module_object, context); + break; + } + } + + macho_set_definitions(module_object); + return ERROR_SUCCESS; +} + +int module_unload( + YR_OBJECT* module_object) +{ + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/magic.c b/yara-master/libyara/modules/magic.c new file mode 100644 index 0000000..d9b8533 --- /dev/null +++ b/yara-master/libyara/modules/magic.c @@ -0,0 +1,180 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +/* + +The original idea and inspiration for this module comes from Armin Buescher. + +*/ + +#include +#include + +#define MODULE_NAME magic + +magic_t magic_cookie[MAX_THREADS]; + +const char* cached_types[MAX_THREADS]; +const char* cached_mime_types[MAX_THREADS]; + + +define_function(magic_mime_type) +{ + YR_MEMORY_BLOCK* block; + YR_SCAN_CONTEXT* context = scan_context(); + + const uint8_t* block_data; + + if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) + return_string(UNDEFINED); + + if (cached_mime_types[context->tidx] == NULL) + { + block = first_memory_block(context); + block_data = block->fetch_data(block); + + if (block_data != NULL) + { + magic_setflags(magic_cookie[context->tidx], MAGIC_MIME_TYPE); + + cached_mime_types[context->tidx] = magic_buffer( + magic_cookie[context->tidx], + block_data, + block->size); + } + } + + if (cached_mime_types[context->tidx] == NULL) + return_string(UNDEFINED); + + return_string((char*) cached_mime_types[context->tidx]); +} + + +define_function(magic_type) +{ + YR_MEMORY_BLOCK* block; + YR_SCAN_CONTEXT* context = scan_context(); + + const uint8_t* block_data; + + if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) + return_string(UNDEFINED); + + if (cached_types[context->tidx] == NULL) + { + block = first_memory_block(context); + block_data = block->fetch_data(block); + + if (block_data != NULL) + { + magic_setflags(magic_cookie[context->tidx], 0); + + cached_types[context->tidx] = magic_buffer( + magic_cookie[context->tidx], + block_data, + block->size); + } + } + + if (cached_types[context->tidx] == NULL) + return_string(UNDEFINED); + + return_string((char*) cached_types[context->tidx]); +} + +begin_declarations; + + declare_function("mime_type", "", "s", magic_mime_type); + declare_function("type", "", "s", magic_type); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + int i; + + for (i = 0; i < MAX_THREADS; i++) + magic_cookie[i] = NULL; + + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + int i; + + for (i = 0; i < MAX_THREADS; i++) + if (magic_cookie[i] != NULL) + magic_close(magic_cookie[i]); + + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + cached_types[context->tidx] = NULL; + cached_mime_types[context->tidx] = NULL; + + if (magic_cookie[context->tidx] == NULL) + { + magic_cookie[context->tidx] = magic_open(0); + + if (magic_cookie[context->tidx] != NULL) + { + if (magic_load(magic_cookie[context->tidx], NULL) != 0) + { + magic_close(magic_cookie[context->tidx]); + return ERROR_INTERNAL_FATAL_ERROR; + } + } + else + { + return ERROR_INSUFFICIENT_MEMORY; + } + } + + return ERROR_SUCCESS; +} + + +int module_unload( + YR_OBJECT* module) +{ + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/math.c b/yara-master/libyara/modules/math.c new file mode 100644 index 0000000..a23e3b7 --- /dev/null +++ b/yara-master/libyara/modules/math.c @@ -0,0 +1,641 @@ +/* +Copyright (c) 2014-2015. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#include +#include + +#define MODULE_NAME math + +#define PI 3.141592653589793 + +// log2 is not defined by math.h in VC++ + +#ifdef _MSC_VER +double log2(double n) +{ + return log(n) / log(2.0); +} +#endif + + +define_function(string_entropy) +{ + size_t i; + double entropy = 0.0; + + SIZED_STRING* s = sized_string_argument(1); + + uint32_t* data = (uint32_t*) yr_calloc(256, sizeof(uint32_t)); + + if (data == NULL) + return_float(UNDEFINED); + + for (i = 0; i < s->length; i++) + { + uint8_t c = s->c_string[i]; + data[c] += 1; + } + + for (i = 0; i < 256; i++) + { + if (data[i] != 0) + { + double x = (double) (data[i]) / s->length; + entropy -= x * log2(x); + } + } + + yr_free(data); + return_float(entropy); +} + + +define_function(data_entropy) +{ + int past_first_block = FALSE; + double entropy = 0.0; + + size_t total_len = 0; + size_t i; + + uint32_t* data; + + int64_t offset = integer_argument(1); // offset where to start + int64_t length = integer_argument(2); // length of bytes we want entropy on + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + if (offset < 0 || length < 0 || offset < block->base) + return_float(UNDEFINED); + + data = (uint32_t*) yr_calloc(256, sizeof(uint32_t)); + + if (data == NULL) + return_float(UNDEFINED); + + foreach_memory_block(iterator, block) + { + if (offset >= block->base && + offset < block->base + block->size) + { + size_t data_offset = (size_t) (offset - block->base); + size_t data_len = (size_t) yr_min( + length, (size_t) (block->size - data_offset)); + + const uint8_t* block_data = block->fetch_data(block); + + if (block_data == NULL) + { + yr_free(data); + return_float(UNDEFINED); + } + + total_len += data_len; + offset += data_len; + length -= data_len; + + for (i = 0; i < data_len; i++) + { + uint8_t c = *(block_data + data_offset + i); + data[c] += 1; + } + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + + yr_free(data); + return_float(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block) + { + yr_free(data); + return_float(UNDEFINED); + } + + for (i = 0; i < 256; i++) + { + if (data[i] != 0) + { + double x = (double) (data[i]) / total_len; + entropy -= x * log2(x); + } + } + + yr_free(data); + return_float(entropy); +} + + +define_function(string_deviation) +{ + SIZED_STRING* s = sized_string_argument(1); + + double mean = float_argument(2); + double sum = 0.0; + + size_t i; + + for (i = 0; i < s->length; i++) + sum += fabs(((double) s->c_string[i]) - mean); + + return_float(sum / s->length); +} + + +define_function(data_deviation) +{ + int past_first_block = FALSE; + + int64_t offset = integer_argument(1); + int64_t length = integer_argument(2); + + double mean = float_argument(3); + double sum = 0.0; + + size_t total_len = 0; + size_t i; + + size_t data_offset = 0; + size_t data_len = 0; + const uint8_t* block_data = NULL; + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + if (offset < 0 || length < 0 || offset < block->base) + return_float(UNDEFINED); + + foreach_memory_block(iterator, block) + { + if (offset >= block->base && + offset < block->base + block->size) + { + data_offset = (size_t)(offset - block->base); + data_len = (size_t)yr_min( + length, (size_t)(block->size - data_offset)); + block_data = block->fetch_data(block); + + if (block_data == NULL) + return_float(UNDEFINED); + + total_len += data_len; + offset += data_len; + length -= data_len; + + for (i = 0; i < data_len; i++) + sum += fabs(((double)* (block_data + data_offset + i)) - mean); + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + return_float(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block) + return_float(UNDEFINED); + + return_float(sum / total_len); +} + + +define_function(string_mean) +{ + size_t i; + double sum = 0.0; + + SIZED_STRING* s = sized_string_argument(1); + + for (i = 0; i < s->length; i++) + sum += (double) s->c_string[i]; + + return_float(sum / s->length); +} + + +define_function(data_mean) +{ + int past_first_block = FALSE; + double sum = 0.0; + + int64_t offset = integer_argument(1); + int64_t length = integer_argument(2); + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + size_t total_len = 0; + size_t i; + + if (offset < 0 || length < 0 || offset < block->base) + return_float(UNDEFINED); + + foreach_memory_block(iterator, block) + { + if (offset >= block->base && + offset < block->base + block->size) + { + size_t data_offset = (size_t) (offset - block->base); + size_t data_len = (size_t) yr_min( + length, (size_t) (block->size - data_offset)); + + const uint8_t* block_data = block->fetch_data(block); + + if (block_data == NULL) + return_float(UNDEFINED); + + total_len += data_len; + offset += data_len; + length -= data_len; + + for (i = 0; i < data_len; i++) + sum += (double)* (block_data + data_offset + i); + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + return_float(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block) + return_float(UNDEFINED); + + return_float(sum / total_len); +} + + +define_function(data_serial_correlation) +{ + int past_first_block = FALSE; + + size_t total_len = 0; + size_t i; + + int64_t offset = integer_argument(1); + int64_t length = integer_argument(2); + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + double sccun = 0; + double scclast = 0; + double scct1 = 0; + double scct2 = 0; + double scct3 = 0; + double scc = 0; + + if (offset < 0 || length < 0 || offset < block->base) + return_float(UNDEFINED); + + foreach_memory_block(iterator, block) + { + if (offset >= block->base && + offset < block->base + block->size) + { + size_t data_offset = (size_t)(offset - block->base); + size_t data_len = (size_t) yr_min( + length, (size_t) (block->size - data_offset)); + + const uint8_t* block_data = block->fetch_data(block); + + if (block_data == NULL) + return_float(UNDEFINED); + + total_len += data_len; + offset += data_len; + length -= data_len; + + for (i = 0; i < data_len; i++) + { + sccun = (double)* (block_data + data_offset + i); + scct1 += scclast * sccun; + scct2 += sccun; + scct3 += sccun * sccun; + scclast = sccun; + } + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + return_float(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block) + return_float(UNDEFINED); + + scct1 += scclast * sccun; + scct2 *= scct2; + + scc = total_len * scct3 - scct2; + + if (scc == 0) + scc = -100000; + else + scc = (total_len * scct1 - scct2) / scc; + + return_float(scc); +} + + +define_function(string_serial_correlation) +{ + SIZED_STRING* s = sized_string_argument(1); + + double sccun = 0; + double scclast = 0; + double scct1 = 0; + double scct2 = 0; + double scct3 = 0; + double scc = 0; + + size_t i; + + for (i = 0; i < s->length; i++) + { + sccun = (double) s->c_string[i]; + scct1 += scclast * sccun; + scct2 += sccun; + scct3 += sccun * sccun; + scclast = sccun; + } + + scct1 += scclast * sccun; + scct2 *= scct2; + + scc = s->length * scct3 - scct2; + + if (scc == 0) + scc = -100000; + else + scc = (s->length * scct1 - scct2) / scc; + + return_float(scc); +} + + +define_function(data_monte_carlo_pi) +{ + int past_first_block = FALSE; + int mcount = 0; + int inmont = 0; + + double INCIRC = pow(pow(256.0, 3.0) - 1, 2.0); + double mpi = 0; + + size_t i; + + int64_t offset = integer_argument(1); + int64_t length = integer_argument(2); + + YR_SCAN_CONTEXT* context = scan_context(); + YR_MEMORY_BLOCK* block = first_memory_block(context); + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + if (offset < 0 || length < 0 || offset < block->base) + return_float(UNDEFINED); + + foreach_memory_block(iterator, block) + { + if (offset >= block->base && + offset < block->base + block->size) + { + unsigned int monte[6]; + + size_t data_offset = (size_t) (offset - block->base); + size_t data_len = (size_t) yr_min( + length, (size_t) (block->size - data_offset)); + + const uint8_t* block_data = block->fetch_data(block); + + if (block_data == NULL) + return_float(UNDEFINED); + + offset += data_len; + length -= data_len; + + for (i = 0; i < data_len; i++) + { + monte[i % 6] = (unsigned int)* (block_data + data_offset + i); + + if (i % 6 == 5) + { + double mx = 0; + double my = 0; + int j; + + mcount++; + + for (j = 0; j < 3; j++) + { + mx = (mx * 256.0) + monte[j]; + my = (my * 256.0) + monte[j + 3]; + } + + if ((mx * mx + my * my) <= INCIRC) + inmont++; + } + } + + past_first_block = TRUE; + } + else if (past_first_block) + { + // If offset is not within current block and we already + // past the first block then the we are trying to compute + // the checksum over a range of non contiguous blocks. As + // range contains gaps of undefined data the checksum is + // undefined. + return_float(UNDEFINED); + } + + if (block->base + block->size > offset + length) + break; + } + + if (!past_first_block || mcount == 0) + return_float(UNDEFINED); + + mpi = 4.0 * ((double) inmont / mcount); + + return_float(fabs((mpi - PI) / PI)); +} + + +define_function(string_monte_carlo_pi) +{ + SIZED_STRING* s = sized_string_argument(1); + + double INCIRC = pow(pow(256.0, 3.0) - 1, 2.0); + double mpi = 0; + + unsigned int monte[6]; + + int mcount = 0; + int inmont = 0; + + size_t i; + + for (i = 0; i < s->length; i++) + { + monte[i % 6] = (unsigned int) s->c_string[i]; + + if (i % 6 == 5) + { + double mx = 0; + double my = 0; + + int j; + + mcount++; + + for (j = 0; j < 3; j++) + { + mx = (mx * 256.0) + monte[j]; + my = (my * 256.0) + monte[j + 3]; + } + + if ((mx * mx + my * my) <= INCIRC) + inmont++; + } + } + + if (mcount == 0) + return_float(UNDEFINED); + + mpi = 4.0 * ((double) inmont / mcount); + return_float(fabs((mpi - PI) / PI)); +} + + +define_function(in_range) +{ + double test = float_argument(1); + double lower = float_argument(2); + double upper = float_argument(3); + + return_integer((lower <= test && test <= upper) ? 1 : 0); +} + + +begin_declarations; + + declare_float("MEAN_BYTES"); + declare_function("in_range", "fff", "i", in_range); + declare_function("deviation", "iif", "f", data_deviation); + declare_function("deviation", "sf", "f", string_deviation); + declare_function("mean", "ii", "f", data_mean); + declare_function("mean", "s", "f", string_mean); + declare_function("serial_correlation", "ii", "f", data_serial_correlation); + declare_function("serial_correlation", "s", "f", string_serial_correlation); + declare_function("monte_carlo_pi", "ii", "f", data_monte_carlo_pi); + declare_function("monte_carlo_pi", "s", "f", string_monte_carlo_pi); + declare_function("entropy", "ii", "f", data_entropy); + declare_function("entropy", "s", "f", string_entropy); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + set_float(127.5, module_object, "MEAN_BYTES"); + return ERROR_SUCCESS; +} + + +int module_unload( + YR_OBJECT* module_object) +{ + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/module_list b/yara-master/libyara/modules/module_list new file mode 100644 index 0000000..264e255 --- /dev/null +++ b/yara-master/libyara/modules/module_list @@ -0,0 +1,29 @@ +MODULE(tests) +MODULE(pe) +MODULE(elf) +MODULE(math) +MODULE(time) + +#ifdef DOTNET_MODULE +MODULE(dotnet) +#endif + +#ifdef CUCKOO_MODULE +MODULE(cuckoo) +#endif + +#ifdef MAGIC_MODULE +MODULE(magic) +#endif + +#ifdef HASH_MODULE +MODULE(hash) +#endif + +#ifdef MACHO_MODULE +MODULE(macho) +#endif + +#ifdef DEX_MODULE +MODULE(dex) +#endif diff --git a/yara-master/libyara/modules/pe.c b/yara-master/libyara/modules/pe.c new file mode 100644 index 0000000..faf7f31 --- /dev/null +++ b/yara-master/libyara/modules/pe.c @@ -0,0 +1,2742 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#define _GNU_SOURCE + +#include +#include +#include + +#include "../crypto.h" +#if defined(HAVE_LIBCRYPTO) +#include +#include +#include +#include +#include +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#define X509_get_signature_nid(o) OBJ_obj2nid((o)->sig_alg->algorithm) +#endif +#endif + +#include +#include +#include +#include +#include + +#include + +#define MODULE_NAME pe + +// http://msdn.microsoft.com/en-us/library/ms648009(v=vs.85).aspx +#define RESOURCE_TYPE_CURSOR 1 +#define RESOURCE_TYPE_BITMAP 2 +#define RESOURCE_TYPE_ICON 3 +#define RESOURCE_TYPE_MENU 4 +#define RESOURCE_TYPE_DIALOG 5 +#define RESOURCE_TYPE_STRING 6 +#define RESOURCE_TYPE_FONTDIR 7 +#define RESOURCE_TYPE_FONT 8 +#define RESOURCE_TYPE_ACCELERATOR 9 +#define RESOURCE_TYPE_RCDATA 10 +#define RESOURCE_TYPE_MESSAGETABLE 11 +#define RESOURCE_TYPE_GROUP_CURSOR 12 // MAKEINTRESOURCE((ULONG_PTR)(RT_CURSOR) + 11) +#define RESOURCE_TYPE_GROUP_ICON 14 // MAKEINTRESOURCE((ULONG_PTR)(RT_ICON) + 11) +#define RESOURCE_TYPE_VERSION 16 +#define RESOURCE_TYPE_DLGINCLUDE 17 +#define RESOURCE_TYPE_PLUGPLAY 19 +#define RESOURCE_TYPE_VXD 20 +#define RESOURCE_TYPE_ANICURSOR 21 +#define RESOURCE_TYPE_ANIICON 22 +#define RESOURCE_TYPE_HTML 23 +#define RESOURCE_TYPE_MANIFEST 24 + + +#define RESOURCE_CALLBACK_CONTINUE 0 +#define RESOURCE_CALLBACK_ABORT 1 + + +#define RESOURCE_ITERATOR_FINISHED 0 +#define RESOURCE_ITERATOR_ABORTED 1 + + +#define MAX_PE_IMPORTS 16384 +#define MAX_PE_EXPORTS 65535 + + +#define IS_RESOURCE_SUBDIRECTORY(entry) \ + ((entry)->OffsetToData & 0x80000000) + + +#define RESOURCE_OFFSET(entry) \ + ((entry)->OffsetToData & 0x7FFFFFFF) + + +typedef int (*RESOURCE_CALLBACK_FUNC) ( \ + PIMAGE_RESOURCE_DATA_ENTRY rsrc_data, \ + int rsrc_type, \ + int rsrc_id, \ + int rsrc_language, \ + const uint8_t* type_string, \ + const uint8_t* name_string, \ + const uint8_t* lang_string, \ + void* cb_data); + + +static size_t available_space( + PE* pe, + void* pointer) +{ + if ((uint8_t*) pointer < pe->data) + return 0; + + if ((uint8_t*) pointer >= pe->data + pe->data_size) + return 0; + + return pe->data + pe->data_size - (uint8_t*) pointer; +} + + +int wide_string_fits_in_pe( + PE* pe, + char* data) +{ + size_t i = 0; + size_t space_left = available_space(pe, data); + + while (space_left >= 2) + { + if (data[i] == 0 && data[i + 1] == 0) + return 1; + space_left -= 2; + i += 2; + } + + return 0; +} + + +// Parse the rich signature. +// http://www.ntcore.com/files/richsign.htm + +void pe_parse_rich_signature( + PE* pe, + uint64_t base_address) +{ + PIMAGE_DOS_HEADER mz_header; + PIMAGE_NT_HEADERS32 pe_header; + PRICH_SIGNATURE rich_signature; + DWORD* rich_ptr; + + BYTE* raw_data = NULL; + BYTE* clear_data = NULL; + size_t headers_size = 0; + size_t rich_len = 0; + + if (pe->data_size < sizeof(IMAGE_DOS_HEADER)) + return; + + mz_header = (PIMAGE_DOS_HEADER) pe->data; + + if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE) + return; + + if (yr_le32toh(mz_header->e_lfanew) < 0) + return; + + headers_size = yr_le32toh(mz_header->e_lfanew) + \ + sizeof(pe_header->Signature) + \ + sizeof(IMAGE_FILE_HEADER); + + if (pe->data_size < headers_size) + return; + + // From offset 0x80 until the start of the PE header should be the Rich + // signature. The three key values must all be equal and the first dword + // XORs to "DanS". Then walk the buffer looking for "Rich" which marks the + // end. Technically the XOR key should be right after "Rich" but it's not + // important. + + rich_signature = (PRICH_SIGNATURE) (pe->data + 0x80); + + if (yr_le32toh(rich_signature->key1) != yr_le32toh(rich_signature->key2) || + yr_le32toh(rich_signature->key2) != yr_le32toh(rich_signature->key3) || + (yr_le32toh(rich_signature->dans) ^ yr_le32toh(rich_signature->key1)) != RICH_DANS) + { + return; + } + + for (rich_ptr = (DWORD*) rich_signature; + rich_ptr <= (DWORD*) (pe->data + headers_size); + rich_ptr++) + { + if (yr_le32toh(*rich_ptr) == RICH_RICH) + { + // Multiple by 4 because we are counting in DWORDs. + rich_len = (rich_ptr - (DWORD*) rich_signature) * 4; + raw_data = (BYTE*) yr_malloc(rich_len); + + if (!raw_data) + return; + + memcpy(raw_data, rich_signature, rich_len); + + set_integer( + base_address + 0x80, pe->object, "rich_signature.offset"); + + set_integer( + rich_len, pe->object, "rich_signature.length"); + + set_integer( + rich_signature->key1, pe->object, "rich_signature.key"); + + break; + } + } + + // Walk the entire block and apply the XOR key. + if (raw_data) + { + clear_data = (BYTE*) yr_malloc(rich_len); + + if (!clear_data) + { + yr_free(raw_data); + return; + } + + // Copy the entire block here to be XORed. + memcpy(clear_data, raw_data, rich_len); + + for (rich_ptr = (DWORD*) clear_data; + rich_ptr < (DWORD*) (clear_data + rich_len); + rich_ptr++) + { + *rich_ptr ^= rich_signature->key1; + } + + set_sized_string( + (char*) raw_data, rich_len, pe->object, "rich_signature.raw_data"); + + set_sized_string( + (char*) clear_data, rich_len, pe->object, "rich_signature.clear_data"); + + yr_free(raw_data); + yr_free(clear_data); + return; + } + + return; +} + + +// Return a pointer to the resource directory string or NULL. +// The callback function will parse this and call set_sized_string(). +// The pointer is guaranteed to have enough space to contain the entire string. + +const uint8_t* parse_resource_name( + PE* pe, + const uint8_t* rsrc_data, + PIMAGE_RESOURCE_DIRECTORY_ENTRY entry) +{ + + // If high bit is set it is an offset relative to rsrc_data, which contains + // a resource directory string. + + if (yr_le32toh(entry->Name) & 0x80000000) + { + DWORD length; + + const uint8_t* rsrc_str_ptr = rsrc_data + \ + (yr_le32toh(entry->Name) & 0x7FFFFFFF); + + // A resource directory string is 2 bytes for a string and then a variable + // length Unicode string. Make sure we at least have two bytes. + + if (!fits_in_pe(pe, rsrc_str_ptr, 2)) + return NULL; + + length = *rsrc_str_ptr; + + // Move past the length and make sure we have enough bytes for the string. + if (!fits_in_pe(pe, rsrc_str_ptr + 2, length * 2)) + return NULL; + + return rsrc_str_ptr; + } + + return NULL; +} + + +int _pe_iterate_resources( + PE* pe, + PIMAGE_RESOURCE_DIRECTORY resource_dir, + const uint8_t* rsrc_data, + int rsrc_tree_level, + int* type, + int* id, + int* language, + const uint8_t* type_string, + const uint8_t* name_string, + const uint8_t* lang_string, + RESOURCE_CALLBACK_FUNC callback, + void* callback_data) +{ + int i, result = RESOURCE_ITERATOR_FINISHED; + int total_entries; + + PIMAGE_RESOURCE_DIRECTORY_ENTRY entry; + + // A few sanity checks to avoid corrupt files + + if (yr_le32toh(resource_dir->Characteristics) != 0 || + yr_le16toh(resource_dir->NumberOfNamedEntries) > 32768 || + yr_le16toh(resource_dir->NumberOfIdEntries) > 32768) + { + return result; + } + + total_entries = yr_le16toh(resource_dir->NumberOfNamedEntries) + + yr_le16toh(resource_dir->NumberOfIdEntries); + + // The first directory entry is just after the resource directory, + // by incrementing resource_dir we skip sizeof(resource_dir) bytes + // and get a pointer to the end of the resource directory. + + entry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (resource_dir + 1); + + for (i = 0; i < total_entries; i++) + { + if (!struct_fits_in_pe(pe, entry, IMAGE_RESOURCE_DIRECTORY_ENTRY)) + { + result = RESOURCE_ITERATOR_ABORTED; + break; + } + + switch(rsrc_tree_level) + { + case 0: + *type = yr_le32toh(entry->Name); + type_string = parse_resource_name(pe, rsrc_data, entry); + break; + case 1: + *id = yr_le32toh(entry->Name); + name_string = parse_resource_name(pe, rsrc_data, entry); + break; + case 2: + *language = yr_le32toh(entry->Name); + lang_string = parse_resource_name(pe, rsrc_data, entry); + break; + } + + if (IS_RESOURCE_SUBDIRECTORY(entry) && rsrc_tree_level < 2) + { + PIMAGE_RESOURCE_DIRECTORY directory = (PIMAGE_RESOURCE_DIRECTORY) \ + (rsrc_data + RESOURCE_OFFSET(entry)); + + if (struct_fits_in_pe(pe, directory, IMAGE_RESOURCE_DIRECTORY)) + { + result = _pe_iterate_resources( + pe, + directory, + rsrc_data, + rsrc_tree_level + 1, + type, + id, + language, + type_string, + name_string, + lang_string, + callback, + callback_data); + } + else + { + result = RESOURCE_ITERATOR_ABORTED; + } + } + else + { + PIMAGE_RESOURCE_DATA_ENTRY data_entry = (PIMAGE_RESOURCE_DATA_ENTRY) \ + (rsrc_data + RESOURCE_OFFSET(entry)); + + if (struct_fits_in_pe(pe, data_entry, IMAGE_RESOURCE_DATA_ENTRY)) + { + if (callback( + data_entry, + *type, + *id, + *language, + type_string, + name_string, + lang_string, + callback_data) == RESOURCE_CALLBACK_ABORT) + { + result = RESOURCE_ITERATOR_ABORTED; + } + } + else + { + result = RESOURCE_ITERATOR_ABORTED; + } + } + + if (result == RESOURCE_ITERATOR_ABORTED) + break; + + entry++; + } + + return result; +} + + +int pe_iterate_resources( + PE* pe, + RESOURCE_CALLBACK_FUNC callback, + void* callback_data) +{ + int64_t offset; + + int type = -1; + int id = -1; + int language = -1; + + uint8_t* type_string = NULL; + uint8_t* name_string = NULL; + uint8_t* lang_string = NULL; + + PIMAGE_DATA_DIRECTORY directory = pe_get_directory_entry( + pe, IMAGE_DIRECTORY_ENTRY_RESOURCE); + + if (directory == NULL) + return 0; + + if (yr_le32toh(directory->VirtualAddress) != 0) + { + PIMAGE_RESOURCE_DIRECTORY rsrc_dir; + + offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); + + if (offset < 0) + return 0; + + rsrc_dir = (PIMAGE_RESOURCE_DIRECTORY) (pe->data + offset); + + if (struct_fits_in_pe(pe, rsrc_dir, IMAGE_RESOURCE_DIRECTORY)) + { + set_integer(yr_le32toh(rsrc_dir->TimeDateStamp), + pe->object, + "resource_timestamp"); + + set_integer(yr_le16toh(rsrc_dir->MajorVersion), + pe->object, + "resource_version.major"); + set_integer(yr_le16toh(rsrc_dir->MinorVersion), + pe->object, + "resource_version.minor"); + + _pe_iterate_resources( + pe, + rsrc_dir, + pe->data + offset, + 0, + &type, + &id, + &language, + type_string, + name_string, + lang_string, + callback, + callback_data); + + return 1; + } + } + + return 0; +} + + +// Align offset to a 32-bit boundary and add it to a pointer + +#define ADD_OFFSET(ptr, offset) \ + (PVERSION_INFO) ((uint8_t*) (ptr) + ((offset + 3) & ~3)) + + +void pe_parse_version_info( + PIMAGE_RESOURCE_DATA_ENTRY rsrc_data, + PE* pe) +{ + PVERSION_INFO version_info; + + int64_t version_info_offset = pe_rva_to_offset( + pe, yr_le32toh(rsrc_data->OffsetToData)); + + if (version_info_offset < 0) + return; + + version_info = (PVERSION_INFO) (pe->data + version_info_offset); + + if (!struct_fits_in_pe(pe, version_info, VERSION_INFO)) + return; + + if (!fits_in_pe(pe, version_info->Key, sizeof("VS_VERSION_INFO") * 2)) + return; + + if (strcmp_w(version_info->Key, "VS_VERSION_INFO") != 0) + return; + + version_info = ADD_OFFSET( + version_info, sizeof(VERSION_INFO) + 86); + + while(fits_in_pe(pe, version_info->Key, sizeof("VarFileInfo") * 2) && + strcmp_w(version_info->Key, "VarFileInfo") == 0 && + yr_le16toh(version_info->Length) != 0) + { + version_info = ADD_OFFSET( + version_info, + yr_le16toh(version_info->Length)); + } + + while(fits_in_pe(pe, version_info->Key, sizeof("StringFileInfo") * 2) && + strcmp_w(version_info->Key, "StringFileInfo") == 0 && + yr_le16toh(version_info->Length) != 0) + { + PVERSION_INFO string_table = ADD_OFFSET( + version_info, + sizeof(VERSION_INFO) + 30); + + version_info = ADD_OFFSET( + version_info, + yr_le16toh(version_info->Length)); + + while (struct_fits_in_pe(pe, string_table, VERSION_INFO) && + wide_string_fits_in_pe(pe, string_table->Key) && + yr_le16toh(string_table->Length) != 0 && + string_table < version_info) + { + PVERSION_INFO string = ADD_OFFSET( + string_table, + sizeof(VERSION_INFO) + 2 * (strnlen_w(string_table->Key) + 1)); + + string_table = ADD_OFFSET( + string_table, + yr_le16toh(string_table->Length)); + + while (struct_fits_in_pe(pe, string, VERSION_INFO) && + wide_string_fits_in_pe(pe, string->Key) && + yr_le16toh(string->Length) != 0 && + string < string_table) + { + if (yr_le16toh(string->ValueLength) > 0) + { + char* string_value = (char*) ADD_OFFSET(string, + sizeof(VERSION_INFO) + 2 * (strnlen_w(string->Key) + 1)); + + if (wide_string_fits_in_pe(pe, string_value)) + { + char key[64]; + char value[256]; + + strlcpy_w(key, string->Key, sizeof(key)); + strlcpy_w(value, string_value, sizeof(value)); + + set_string(value, pe->object, "version_info[%s]", key); + } + } + + string = ADD_OFFSET(string, yr_le16toh(string->Length)); + } + } + } +} + + +int pe_collect_resources( + PIMAGE_RESOURCE_DATA_ENTRY rsrc_data, + int rsrc_type, + int rsrc_id, + int rsrc_language, + uint8_t* type_string, + uint8_t* name_string, + uint8_t* lang_string, + PE* pe) +{ + DWORD length; + + int64_t offset = pe_rva_to_offset(pe, yr_le32toh(rsrc_data->OffsetToData)); + + if (offset < 0) + return RESOURCE_CALLBACK_CONTINUE; + + if (!fits_in_pe(pe, pe->data + offset, yr_le32toh(rsrc_data->Size))) + return RESOURCE_CALLBACK_CONTINUE; + + set_integer( + offset, + pe->object, + "resources[%i].offset", + pe->resources); + + set_integer( + yr_le32toh(rsrc_data->Size), + pe->object, + "resources[%i].length", + pe->resources); + + if (type_string) + { + // Multiply by 2 because it is a Unicode string. + length = ((DWORD) *type_string) * 2; + type_string += 2; + + set_sized_string( + (char*) type_string, length, pe->object, + "resources[%i].type_string", pe->resources); + } + else + { + set_integer( + rsrc_type, + pe->object, + "resources[%i].type", + pe->resources); + } + + if (name_string) + { + // Multiply by 2 because it is a Unicode string. + length = ((DWORD) *name_string) * 2; + name_string += 2; + set_sized_string( + (char*) name_string, length, pe->object, + "resources[%i].name_string", pe->resources); + } + else + { + set_integer( + rsrc_id, + pe->object, + "resources[%i].id", + pe->resources); + } + + if (lang_string) + { + // Multiply by 2 because it is a Unicode string. + length = ((DWORD) *lang_string) * 2; + lang_string += 2; + set_sized_string( + (char*) lang_string, length, pe->object, + "resources[%i].language_string", pe->resources); + } + else + { + set_integer( + rsrc_language, + pe->object, + "resources[%i].language", + pe->resources); + } + + // Resources we do extra parsing on + if (rsrc_type == RESOURCE_TYPE_VERSION) + pe_parse_version_info(rsrc_data, pe); + + pe->resources += 1; + return RESOURCE_CALLBACK_CONTINUE; +} + + +IMPORT_EXPORT_FUNCTION* pe_parse_import_descriptor( + PE* pe, + PIMAGE_IMPORT_DESCRIPTOR import_descriptor, + char* dll_name) +{ + IMPORT_EXPORT_FUNCTION* head = NULL; + IMPORT_EXPORT_FUNCTION* tail = NULL; + + int num_functions = 0; + + int64_t offset = pe_rva_to_offset( + pe, yr_le32toh(import_descriptor->OriginalFirstThunk)); + + // I've seen binaries where OriginalFirstThunk is zero. In this case + // use FirstThunk. + + if (offset <= 0) + offset = pe_rva_to_offset(pe, yr_le32toh(import_descriptor->FirstThunk)); + + if (offset < 0) + return NULL; + + if (IS_64BITS_PE(pe)) + { + PIMAGE_THUNK_DATA64 thunks64 = (PIMAGE_THUNK_DATA64)(pe->data + offset); + + while (struct_fits_in_pe(pe, thunks64, IMAGE_THUNK_DATA64) && + yr_le64toh(thunks64->u1.Ordinal) != 0 && + num_functions < MAX_PE_IMPORTS) + { + char* name = NULL; + uint16_t ordinal = 0; + uint8_t has_ordinal = 0; + + if (!(yr_le64toh(thunks64->u1.Ordinal) & IMAGE_ORDINAL_FLAG64)) + { + // If imported by name + offset = pe_rva_to_offset(pe, yr_le64toh(thunks64->u1.Function)); + + if (offset >= 0) + { + PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME) \ + (pe->data + offset); + + if (struct_fits_in_pe(pe, import, IMAGE_IMPORT_BY_NAME)) + { + name = (char *) yr_strndup( + (char*) import->Name, + yr_min(available_space(pe, import->Name), 512)); + } + } + } + else + { + // If imported by ordinal. Lookup the ordinal. + name = ord_lookup(dll_name, yr_le64toh(thunks64->u1.Ordinal) & 0xFFFF); + // Also store the ordinal. + ordinal = yr_le64toh(thunks64->u1.Ordinal) & 0xFFFF; + has_ordinal = 1; + } + + if (name != NULL || has_ordinal == 1) + { + IMPORT_EXPORT_FUNCTION* imported_func = (IMPORT_EXPORT_FUNCTION*) + yr_calloc(1, sizeof(IMPORT_EXPORT_FUNCTION)); + + if (imported_func == NULL) + { + yr_free(name); + continue; + } + + imported_func->name = name; + imported_func->ordinal = ordinal; + imported_func->has_ordinal = has_ordinal; + imported_func->next = NULL; + + if (head == NULL) + head = imported_func; + + if (tail != NULL) + tail->next = imported_func; + + tail = imported_func; + } + + num_functions++; + thunks64++; + } + } + else + { + PIMAGE_THUNK_DATA32 thunks32 = (PIMAGE_THUNK_DATA32)(pe->data + offset); + + while (struct_fits_in_pe(pe, thunks32, IMAGE_THUNK_DATA32) && + yr_le32toh(thunks32->u1.Ordinal) != 0 && num_functions < MAX_PE_IMPORTS) + { + char* name = NULL; + uint16_t ordinal = 0; + uint8_t has_ordinal = 0; + + if (!(yr_le32toh(thunks32->u1.Ordinal) & IMAGE_ORDINAL_FLAG32)) + { + // If imported by name + offset = pe_rva_to_offset(pe, yr_le32toh(thunks32->u1.Function)); + + if (offset >= 0) + { + PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME) \ + (pe->data + offset); + + if (struct_fits_in_pe(pe, import, IMAGE_IMPORT_BY_NAME)) + { + name = (char *) yr_strndup( + (char*) import->Name, + yr_min(available_space(pe, import->Name), 512)); + } + } + } + else + { + // If imported by ordinal. Lookup the ordinal. + name = ord_lookup(dll_name, yr_le32toh(thunks32->u1.Ordinal) & 0xFFFF); + // Also store the ordinal. + ordinal = yr_le32toh(thunks32->u1.Ordinal) & 0xFFFF; + has_ordinal = 1; + } + + if (name != NULL || has_ordinal == 1) + { + IMPORT_EXPORT_FUNCTION* imported_func = (IMPORT_EXPORT_FUNCTION*) + yr_calloc(1, sizeof(IMPORT_EXPORT_FUNCTION)); + + if (imported_func == NULL) + { + yr_free(name); + continue; + } + + imported_func->name = name; + imported_func->ordinal = ordinal; + imported_func->has_ordinal = has_ordinal; + imported_func->next = NULL; + + if (head == NULL) + head = imported_func; + + if (tail != NULL) + tail->next = imported_func; + + tail = imported_func; + } + + num_functions++; + thunks32++; + } + } + + return head; +} + + +int pe_valid_dll_name( + const char* dll_name, size_t n) +{ + const char* c = dll_name; + size_t l = 0; + + while (l < n && *c != '\0') + { + if ((*c >= 'a' && *c <= 'z') || + (*c >= 'A' && *c <= 'Z') || + (*c >= '0' && *c <= '9') || + (*c == '_' || *c == '.' || *c == '-')) + { + c++; + l++; + } + else + { + return FALSE; + } + } + + return (l > 0 && l < n); +} + + +// +// Walk the imports and collect relevant information. It is used in the +// "imports" function for comparison and in the "imphash" function for +// calculation. +// + +IMPORTED_DLL* pe_parse_imports( + PE* pe) +{ + int64_t offset; + int num_imports = 0; + + IMPORTED_DLL* head = NULL; + IMPORTED_DLL* tail = NULL; + + PIMAGE_IMPORT_DESCRIPTOR imports; + + PIMAGE_DATA_DIRECTORY directory = pe_get_directory_entry( + pe, IMAGE_DIRECTORY_ENTRY_IMPORT); + + if (directory == NULL) + return NULL; + + if (yr_le32toh(directory->VirtualAddress) == 0) + return NULL; + + offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); + + if (offset < 0) + return NULL; + + imports = (PIMAGE_IMPORT_DESCRIPTOR) \ + (pe->data + offset); + + while (struct_fits_in_pe(pe, imports, IMAGE_IMPORT_DESCRIPTOR) && + yr_le32toh(imports->Name) != 0 && num_imports < MAX_PE_IMPORTS) + { + int64_t offset = pe_rva_to_offset(pe, yr_le32toh(imports->Name)); + + if (offset >= 0) + { + IMPORTED_DLL* imported_dll; + + char* dll_name = (char *) (pe->data + offset); + + if (!pe_valid_dll_name(dll_name, pe->data_size - (size_t) offset)) + break; + + imported_dll = (IMPORTED_DLL*) yr_calloc(1, sizeof(IMPORTED_DLL)); + + if (imported_dll != NULL) + { + IMPORT_EXPORT_FUNCTION* functions = pe_parse_import_descriptor( + pe, imports, dll_name); + + if (functions != NULL) + { + imported_dll->name = yr_strdup(dll_name);; + imported_dll->functions = functions; + imported_dll->next = NULL; + + if (head == NULL) + head = imported_dll; + + if (tail != NULL) + tail->next = imported_dll; + + tail = imported_dll; + } + else + { + yr_free(imported_dll); + } + } + } + + num_imports++; + imports++; + } + + set_integer(num_imports, pe->object, "number_of_imports"); + return head; +} + +// +// Walk the exports and collect relevant information. It is used in the +// "exports" function for comparison. +// + +IMPORT_EXPORT_FUNCTION* pe_parse_exports( + PE* pe) +{ + IMPORT_EXPORT_FUNCTION* head = NULL; + IMPORT_EXPORT_FUNCTION* tail = NULL; + + PIMAGE_DATA_DIRECTORY directory; + PIMAGE_EXPORT_DIRECTORY exports; + + DWORD* names; + WORD* ordinals; + + int64_t offset; + uint32_t i; + size_t remaining; + + int num_exports = 0; + + // If not a PE file, return UNDEFINED + + if (pe == NULL) + return NULL; + + directory = pe_get_directory_entry( + pe, IMAGE_DIRECTORY_ENTRY_EXPORT); + + if (directory == NULL) + return NULL; + + if (yr_le32toh(directory->VirtualAddress) == 0) + return NULL; + + offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); + + if (offset < 0) + return NULL; + + exports = (PIMAGE_EXPORT_DIRECTORY) (pe->data + offset); + + if (!struct_fits_in_pe(pe, exports, IMAGE_EXPORT_DIRECTORY)) + return NULL; + + offset = pe_rva_to_offset(pe, yr_le32toh(exports->AddressOfNames)); + + if (offset < 0) + return NULL; + + if (yr_le32toh(exports->NumberOfFunctions) > MAX_PE_EXPORTS || + yr_le32toh(exports->NumberOfFunctions) * sizeof(DWORD) > pe->data_size - offset) + return NULL; + + names = (DWORD*)(pe->data + offset); + + offset = pe_rva_to_offset(pe, yr_le32toh(exports->AddressOfNameOrdinals)); + + if (offset < 0) + return NULL; + + ordinals = (WORD*)(pe->data + offset); + + // Walk the number of functions, not the number of names as each exported + // symbol has an ordinal value, but names are optional. + + for (i = 0; i < yr_le32toh(exports->NumberOfFunctions); i++) + { + IMPORT_EXPORT_FUNCTION* exported_func; + uint16_t ordinal = 0; + char* name; + + if (available_space(pe, names + i) < sizeof(DWORD) || + available_space(pe, ordinals + i) < sizeof(WORD)) + { + break; + } + + offset = pe_rva_to_offset(pe, names[i]); + + if (offset < 0) + continue; + + remaining = pe->data_size - (size_t) offset; + name = yr_strndup((char*) (pe->data + offset), remaining); + + // Get the corresponding ordinal. Note that we are not subtracting the + // ordinal base here as we don't intend to index into the export address + // table. + ordinal = yr_le16toh(ordinals[i]); + + // Now add it to the list... + exported_func = (IMPORT_EXPORT_FUNCTION*) + yr_calloc(1, sizeof(IMPORT_EXPORT_FUNCTION)); + + if (exported_func == NULL) + { + yr_free(name); + continue; + } + + exported_func->name = name; + exported_func->ordinal = ordinal; + exported_func->next = NULL; + + if (head == NULL) + head = exported_func; + + if (tail != NULL) + tail->next = exported_func; + + tail = exported_func; + num_exports++; + } + + set_integer(num_exports, pe->object, "number_of_exports"); + return head; +} + + +#if defined(HAVE_LIBCRYPTO) + +void pe_parse_certificates( + PE* pe) +{ + int i, counter = 0; + + const uint8_t* eod; + uintptr_t end; + + PWIN_CERTIFICATE win_cert; + + PIMAGE_DATA_DIRECTORY directory = pe_get_directory_entry( + pe, IMAGE_DIRECTORY_ENTRY_SECURITY); + + if (directory == NULL) + return; + + // Default to 0 signatures until we know otherwise. + set_integer(0, pe->object, "number_of_signatures"); + + // directory->VirtualAddress is a file offset. Don't call pe_rva_to_offset(). + if (yr_le32toh(directory->VirtualAddress) == 0 || + yr_le32toh(directory->VirtualAddress) > pe->data_size || + yr_le32toh(directory->Size) > pe->data_size || + yr_le32toh(directory->VirtualAddress) + yr_le32toh(directory->Size) > pe->data_size) + { + return; + } + + // Store the end of directory, making comparisons easier. + eod = pe->data + \ + yr_le32toh(directory->VirtualAddress) + \ + yr_le32toh(directory->Size); + + win_cert = (PWIN_CERTIFICATE) \ + (pe->data + yr_le32toh(directory->VirtualAddress)); + + // + // Walk the directory, pulling out certificates. + // + // Make sure WIN_CERTIFICATE fits within the directory. + // Make sure the Length specified fits within directory too. + // + // The docs say that the length is only for the Certificate, but the next + // paragraph contradicts that. All the binaries I've seen have the Length + // being the entire structure (Certificate included). + // + + while (struct_fits_in_pe(pe, win_cert, WIN_CERTIFICATE) && + yr_le32toh(win_cert->Length) > sizeof(WIN_CERTIFICATE) && + fits_in_pe(pe, win_cert, yr_le32toh(win_cert->Length)) && + (uint8_t*) win_cert + sizeof(WIN_CERTIFICATE) < eod && + (uint8_t*) win_cert + yr_le32toh(win_cert->Length) <= eod) + { + BIO* cert_bio; + PKCS7* pkcs7; + STACK_OF(X509)* certs; + + // Some sanity checks + + if (yr_le32toh(win_cert->Length) == 0 || + (yr_le16toh(win_cert->Revision) != WIN_CERT_REVISION_1_0 && + yr_le16toh(win_cert->Revision) != WIN_CERT_REVISION_2_0)) + { + break; + } + + // Don't support legacy revision for now. + // Make sure type is PKCS#7 too. + + if (yr_le16toh(win_cert->Revision) != WIN_CERT_REVISION_2_0 || + yr_le16toh(win_cert->CertificateType) != WIN_CERT_TYPE_PKCS_SIGNED_DATA) + { + uintptr_t end = (uintptr_t) + ((uint8_t *) win_cert) + yr_le32toh(win_cert->Length); + + win_cert = (PWIN_CERTIFICATE) (end + (end % 8)); + continue; + } + + cert_bio = BIO_new_mem_buf( + win_cert->Certificate, yr_le32toh(win_cert->Length) - WIN_CERTIFICATE_HEADER_SIZE); + + if (!cert_bio) + break; + + pkcs7 = d2i_PKCS7_bio(cert_bio, NULL); + certs = PKCS7_get0_signers(pkcs7, NULL, 0); + + if (!certs) + { + BIO_free(cert_bio); + PKCS7_free(pkcs7); + break; + } + + for (i = 0; i < sk_X509_num(certs); i++) + { + time_t date_time; + const char* sig_alg; + char buffer[256]; + int bytes; + + ASN1_INTEGER* serial; + + X509* cert = sk_X509_value(certs, i); + + X509_NAME_oneline( + X509_get_issuer_name(cert), buffer, sizeof(buffer)); + + set_string(buffer, pe->object, "signatures[%i].issuer", counter); + + X509_NAME_oneline( + X509_get_subject_name(cert), buffer, sizeof(buffer)); + + set_string(buffer, pe->object, "signatures[%i].subject", counter); + + set_integer( + X509_get_version(cert) + 1, // Versions are zero based, so add one. + pe->object, + "signatures[%i].version", counter); + + sig_alg = OBJ_nid2ln(X509_get_signature_nid(cert)); + + set_string(sig_alg, pe->object, "signatures[%i].algorithm", counter); + + serial = X509_get_serialNumber(cert); + + if (serial) + { + // ASN1_INTEGER can be negative (serial->type & V_ASN1_NEG_INTEGER), + // in which case the serial number will be stored in 2's complement. + // + // Handle negative serial numbers, which are technically not allowed + // by RFC5280, but do exist. An example binary which has a negative + // serial number is: 4bfe05f182aa273e113db6ed7dae4bb8. + // + // Negative serial numbers are handled by calling i2d_ASN1_INTEGER() + // with a NULL second parameter. This will return the size of the + // buffer necessary to store the proper serial number. + // + // Do this even for positive serial numbers because it makes the code + // cleaner and easier to read. + + bytes = i2d_ASN1_INTEGER(serial, NULL); + + // According to X.509 specification the maximum length for the + // serial number is 20 octets. Add two bytes to account for + // DER type and length information. + + if (bytes > 2 && bytes <= 22) + { + // Now that we know the size of the serial number allocate enough + // space to hold it, and use i2d_ASN1_INTEGER() one last time to + // hold it in the allocated buffer. + + unsigned char* serial_der = (unsigned char*) yr_malloc(bytes); + + if (serial_der != NULL) + { + unsigned char* serial_bytes; + char *serial_ascii; + + bytes = i2d_ASN1_INTEGER(serial, &serial_der); + + // i2d_ASN1_INTEGER() moves the pointer as it writes into + // serial_bytes. Move it back. + + serial_der -= bytes; + + // Skip over DER type, length information + serial_bytes = serial_der + 2; + bytes -= 2; + + // Also allocate space to hold the "common" string format: + // 00:01:02:03:04... + // + // For each byte in the serial to convert to hexlified format we + // need three bytes, two for the byte itself and one for colon. + // The last one doesn't have the colon, but the extra byte is used + // for the NULL terminator. + + serial_ascii = (char*) yr_malloc(bytes * 3); + + if (serial_ascii) + { + int j; + + for (j = 0; j < bytes; j++) + { + // Don't put the colon on the last one. + if (j < bytes - 1) + snprintf( + serial_ascii + 3 * j, 4, "%02x:", serial_bytes[j]); + else + snprintf( + serial_ascii + 3 * j, 3, "%02x", serial_bytes[j]); + } + + set_string( + serial_ascii, + pe->object, + "signatures[%i].serial", + counter); + + yr_free(serial_ascii); + } + + yr_free(serial_der); + } + } + } + + date_time = ASN1_get_time_t(X509_get_notBefore(cert)); + set_integer(date_time, pe->object, "signatures[%i].not_before", counter); + + date_time = ASN1_get_time_t(X509_get_notAfter(cert)); + set_integer(date_time, pe->object, "signatures[%i].not_after", counter); + + counter++; + } + + end = (uintptr_t)((uint8_t *) win_cert) + yr_le32toh(win_cert->Length); + win_cert = (PWIN_CERTIFICATE)(end + (end % 8)); + + BIO_free(cert_bio); + PKCS7_free(pkcs7); + sk_X509_free(certs); + } + + set_integer(counter, pe->object, "number_of_signatures"); +} + +#endif // defined(HAVE_LIBCRYPTO) + + +void pe_parse_header( + PE* pe, + uint64_t base_address, + int flags) +{ + PIMAGE_SECTION_HEADER section; + + char section_name[IMAGE_SIZEOF_SHORT_NAME + 1]; + int i, scount; + uint64_t highest_sec_siz = 0; + uint64_t highest_sec_ofs = 0; + uint64_t last_section_end; + + set_integer( + yr_le16toh(pe->header->FileHeader.Machine), + pe->object, "machine"); + + set_integer( + yr_le16toh(pe->header->FileHeader.NumberOfSections), + pe->object, "number_of_sections"); + + set_integer( + yr_le32toh(pe->header->FileHeader.TimeDateStamp), + pe->object, "timestamp"); + + set_integer( + yr_le16toh(pe->header->FileHeader.Characteristics), + pe->object, "characteristics"); + + set_integer( + flags & SCAN_FLAGS_PROCESS_MEMORY ? + base_address + yr_le32toh(OptionalHeader(pe, AddressOfEntryPoint)) : + pe_rva_to_offset(pe, yr_le32toh(OptionalHeader(pe, AddressOfEntryPoint))), + pe->object, "entry_point"); + + set_integer( + IS_64BITS_PE(pe) ? + yr_le64toh(OptionalHeader(pe, ImageBase)) : + yr_le32toh(OptionalHeader(pe, ImageBase)), + pe->object, "image_base"); + + set_integer( + IS_64BITS_PE(pe) ? + yr_le64toh(OptionalHeader(pe, NumberOfRvaAndSizes)) : + yr_le32toh(OptionalHeader(pe, NumberOfRvaAndSizes)), + pe->object, "number_of_rva_and_sizes"); + + set_integer( + OptionalHeader(pe, MajorLinkerVersion), + pe->object, "linker_version.major"); + + set_integer( + OptionalHeader(pe, MinorLinkerVersion), + pe->object, "linker_version.minor"); + + set_integer( + yr_le16toh(OptionalHeader(pe, MajorOperatingSystemVersion)), + pe->object, "os_version.major"); + + set_integer( + yr_le16toh(OptionalHeader(pe, MinorOperatingSystemVersion)), + pe->object, "os_version.minor"); + + set_integer( + yr_le16toh(OptionalHeader(pe, MajorImageVersion)), + pe->object, "image_version.major"); + + set_integer( + yr_le16toh(OptionalHeader(pe, MinorImageVersion)), + pe->object, "image_version.minor"); + + set_integer( + yr_le16toh(OptionalHeader(pe, MajorSubsystemVersion)), + pe->object, "subsystem_version.major"); + + set_integer( + yr_le16toh(OptionalHeader(pe, MinorSubsystemVersion)), + pe->object, "subsystem_version.minor"); + + set_integer( + yr_le32toh(OptionalHeader(pe, CheckSum)), + pe->object, "checksum"); + + set_integer( + yr_le16toh(OptionalHeader(pe, Subsystem)), + pe->object, "subsystem"); + + set_integer( + OptionalHeader(pe, DllCharacteristics), + pe->object, "dll_characteristics"); + + pe_iterate_resources( + pe, + (RESOURCE_CALLBACK_FUNC) pe_collect_resources, + (void*) pe); + + set_integer(pe->resources, pe->object, "number_of_resources"); + + section = IMAGE_FIRST_SECTION(pe->header); + + scount = yr_min( + yr_le16toh(pe->header->FileHeader.NumberOfSections), MAX_PE_SECTIONS); + + for (i = 0; i < scount; i++) + { + if (!struct_fits_in_pe(pe, section, IMAGE_SECTION_HEADER)) + break; + + strncpy(section_name, (char*) section->Name, IMAGE_SIZEOF_SHORT_NAME); + section_name[IMAGE_SIZEOF_SHORT_NAME] = '\0'; + + set_string( + section_name, + pe->object, "sections[%i].name", i); + + set_integer( + yr_le32toh(section->Characteristics), + pe->object, "sections[%i].characteristics", i); + + set_integer( + yr_le32toh(section->SizeOfRawData), + pe->object, "sections[%i].raw_data_size", i); + + set_integer( + yr_le32toh(section->PointerToRawData), + pe->object, "sections[%i].raw_data_offset", i); + + set_integer( + yr_le32toh(section->VirtualAddress), + pe->object, "sections[%i].virtual_address", i); + + set_integer( + yr_le32toh(section->Misc.VirtualSize), + pe->object, "sections[%i].virtual_size", i); + + // This will catch the section with the highest raw offset to help checking + // if overlay data is present + if (yr_le32toh(section->PointerToRawData) > highest_sec_ofs) + { + highest_sec_ofs = yr_le32toh(section->PointerToRawData); + highest_sec_siz = yr_le32toh(section->SizeOfRawData); + } + + section++; + } + + // An overlay is data appended to a PE file. Its location is at + // RawData + RawOffset of the last section on the physical file + last_section_end = highest_sec_siz + highest_sec_ofs; + + // "overlay.offset" is set to UNDEFINED for files that do not have an overlay + if (last_section_end && (pe->data_size > last_section_end)) + set_integer(last_section_end, pe->object, "overlay.offset"); + + // "overlay.size" is zero for well formed PE files that don not have an + // overlay and UNDEFINED for malformed PE files or non-PE files. + if (last_section_end && (pe->data_size >= last_section_end)) + set_integer(pe->data_size - last_section_end, pe->object, "overlay.size"); +} + +// +// Given a posix timestamp argument, make sure not_before <= arg <= not_after +// + +define_function(valid_on) +{ + int64_t timestamp; + int64_t not_before; + int64_t not_after; + + if (is_undefined(parent(), "not_before") || + is_undefined(parent(), "not_after")) + { + return_integer(UNDEFINED); + } + + timestamp = integer_argument(1); + + not_before = get_integer(parent(), "not_before"); + not_after = get_integer(parent(), "not_after"); + + return_integer(timestamp >= not_before && timestamp <= not_after); +} + + +define_function(section_index_addr) +{ + YR_OBJECT* module = module(); + YR_SCAN_CONTEXT* context = scan_context(); + + int64_t i; + int64_t offset; + int64_t size; + + int64_t addr = integer_argument(1); + int64_t n = get_integer(module, "number_of_sections"); + + if (is_undefined(module, "number_of_sections")) + return_integer(UNDEFINED); + + for (i = 0; i < yr_min(n, MAX_PE_SECTIONS); i++) + { + if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) + { + offset = get_integer(module, "sections[%i].virtual_address", i); + size = get_integer(module, "sections[%i].virtual_size", i); + } + else + { + offset = get_integer(module, "sections[%i].raw_data_offset", i); + size = get_integer(module, "sections[%i].raw_data_size", i); + } + + if (addr >= offset && addr < offset + size) + return_integer(i); + } + + return_integer(UNDEFINED); +} + + +define_function(section_index_name) +{ + YR_OBJECT* module = module(); + + char* name = string_argument(1); + + int64_t n = get_integer(module, "number_of_sections"); + int64_t i; + + if (is_undefined(module, "number_of_sections")) + return_integer(UNDEFINED); + + for (i = 0; i < yr_min(n, MAX_PE_SECTIONS); i++) + { + SIZED_STRING* sect = get_string(module, "sections[%i].name", i); + + if (sect != NULL && strcmp(name, sect->c_string) == 0) + return_integer(i); + } + + return_integer(UNDEFINED); +} + + +define_function(exports) +{ + SIZED_STRING* function_name = sized_string_argument(1); + + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + IMPORT_EXPORT_FUNCTION* exported_func; + + // If not a PE, return UNDEFINED. + + if (pe == NULL) + return_integer(UNDEFINED); + + exported_func = pe->exported_functions; + + while (exported_func != NULL) + { + if (strcasecmp(exported_func->name, function_name->c_string) == 0) + return_integer(1); + + exported_func = exported_func->next; + } + + return_integer(0); +} + + +define_function(exports_regexp) +{ + RE* regex = regexp_argument(1); + + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + IMPORT_EXPORT_FUNCTION* exported_func; + + if (!pe) + return_integer(UNDEFINED); + + exported_func = pe->exported_functions; + + while (exported_func != NULL) + { + if (yr_re_match(scan_context(), regex, exported_func->name) != -1) + return_integer(1); + + exported_func = exported_func->next; + } + + return_integer(0); +} + + +define_function(exports_ordinal) +{ + uint64_t ordinal = integer_argument(1); + + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + IMPORT_EXPORT_FUNCTION* exported_func; + + if (!pe) + return_integer(UNDEFINED); + + exported_func = pe->exported_functions; + + while (exported_func != NULL) + { + if (exported_func->ordinal == ordinal) + return_integer(1); + + exported_func = exported_func->next; + } + + return_integer(0); +} + +#if defined(HAVE_LIBCRYPTO) || \ + defined(HAVE_WINCRYPT_H) || \ + defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) + +// +// Generate an import hash: +// https://www.mandiant.com/blog/tracking-malware-import-hashing/ +// It is important to make duplicates of the strings as we don't want +// to alter the contents of the parsed import structures. +// + +define_function(imphash) +{ + YR_OBJECT* module = module(); + + IMPORTED_DLL* dll; + yr_md5_ctx ctx; + + unsigned char digest[YR_MD5_LEN]; + char digest_ascii[YR_MD5_LEN * 2 + 1]; + size_t i; + int first = TRUE; + + PE* pe = (PE*) module->data; + + // If not a PE, return UNDEFINED. + + if (!pe) + return_string(UNDEFINED); + + yr_md5_init(&ctx); + + dll = pe->imported_dlls; + + while (dll) + { + IMPORT_EXPORT_FUNCTION* func; + + size_t dll_name_len; + char* dll_name; + + // If extension is 'ocx', 'sys' or 'dll', chop it. + + char* ext = strstr(dll->name, "."); + + if (ext && (strncasecmp(ext, ".ocx", 4) == 0 || + strncasecmp(ext, ".sys", 4) == 0 || + strncasecmp(ext, ".dll", 4) == 0)) + { + dll_name_len = (ext - dll->name); + } + else + { + dll_name_len = strlen(dll->name); + } + + // Allocate a new string to hold the dll name. + + dll_name = (char *) yr_malloc(dll_name_len + 1); + + if (!dll_name) + return ERROR_INSUFFICIENT_MEMORY; + + strlcpy(dll_name, dll->name, dll_name_len + 1); + + func = dll->functions; + + while (func) + { + char* final_name; + size_t final_name_len = dll_name_len + strlen(func->name) + 1; + + if (!first) + final_name_len++; // Additional byte to accommodate the extra comma + + final_name = (char*) yr_malloc(final_name_len + 1); + + if (final_name == NULL) + break; + + sprintf(final_name, first ? "%s.%s": ",%s.%s", dll_name, func->name); + + // Lowercase the whole thing. + + for (i = 0; i < final_name_len; i++) + final_name[i] = tolower(final_name[i]); + + yr_md5_update(&ctx, final_name, final_name_len); + + yr_free(final_name); + + func = func->next; + first = FALSE; + } + + yr_free(dll_name); + + dll = dll->next; + } + + yr_md5_final(digest, &ctx); + + // Transform the binary digest to ascii + + for (i = 0; i < YR_MD5_LEN; i++) + { + sprintf(digest_ascii + (i * 2), "%02x", digest[i]); + } + + digest_ascii[YR_MD5_LEN * 2] = '\0'; + + return_string(digest_ascii); +} + +#endif // defined(HAVE_LIBCRYPTO) || defined(HAVE_WINCRYPT_H) + + +define_function(imports) +{ + char* dll_name = string_argument(1); + char* function_name = string_argument(2); + + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + IMPORTED_DLL* imported_dll; + + if (!pe) + return_integer(UNDEFINED); + + imported_dll = pe->imported_dlls; + + while (imported_dll != NULL) + { + if (strcasecmp(imported_dll->name, dll_name) == 0) + { + IMPORT_EXPORT_FUNCTION* imported_func = imported_dll->functions; + + while (imported_func != NULL) + { + if (imported_func->name && + strcasecmp(imported_func->name, function_name) == 0) + return_integer(1); + + imported_func = imported_func->next; + } + } + + imported_dll = imported_dll->next; + } + + return_integer(0); +} + +define_function(imports_ordinal) +{ + char* dll_name = string_argument(1); + uint64_t ordinal = integer_argument(2); + + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + IMPORTED_DLL* imported_dll; + + if (!pe) + return_integer(UNDEFINED); + + imported_dll = pe->imported_dlls; + + while (imported_dll != NULL) + { + if (strcasecmp(imported_dll->name, dll_name) == 0) + { + IMPORT_EXPORT_FUNCTION* imported_func = imported_dll->functions; + + while (imported_func != NULL) + { + if (imported_func->has_ordinal && imported_func->ordinal == ordinal) + return_integer(1); + + imported_func = imported_func->next; + } + } + + imported_dll = imported_dll->next; + } + + return_integer(0); +} + +define_function(imports_dll) +{ + char* dll_name = string_argument(1); + + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + IMPORTED_DLL* imported_dll; + + if (!pe) + return_integer(UNDEFINED); + + imported_dll = pe->imported_dlls; + + while (imported_dll != NULL) + { + if (strcasecmp(imported_dll->name, dll_name) == 0) + { + return_integer(1); + } + + imported_dll = imported_dll->next; + } + + return_integer(0); +} + +define_function(locale) +{ + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + uint64_t locale = integer_argument(1); + int64_t n, i; + + if (is_undefined(module, "number_of_resources")) + return_integer(UNDEFINED); + + // If not a PE file, return UNDEFINED + + if (pe == NULL) + return_integer(UNDEFINED); + + n = get_integer(module, "number_of_resources"); + + for (i = 0; i < n; i++) + { + uint64_t rsrc_language = get_integer(module, "resources[%i].language", i); + + if ((rsrc_language & 0xFFFF) == locale) + return_integer(1); + } + + return_integer(0); +} + + +define_function(language) +{ + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + uint64_t language = integer_argument(1); + int64_t n, i; + + if (is_undefined(module, "number_of_resources")) + return_integer(UNDEFINED); + + // If not a PE file, return UNDEFINED + + if (pe == NULL) + return_integer(UNDEFINED); + + n = get_integer(module, "number_of_resources"); + + for (i = 0; i < n; i++) + { + uint64_t rsrc_language = get_integer(module, "resources[%i].language", i); + + if ((rsrc_language & 0xFF) == language) + return_integer(1); + } + + return_integer(0); +} + + +define_function(is_dll) +{ + int64_t characteristics; + YR_OBJECT* module = module(); + + if (is_undefined(module, "characteristics")) + return_integer(UNDEFINED); + + characteristics = get_integer(module, "characteristics"); + return_integer(characteristics & IMAGE_FILE_DLL); +} + + +define_function(is_32bit) +{ + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + if (pe == NULL) + return_integer(UNDEFINED); + + return_integer(IS_64BITS_PE(pe) ? 0 : 1); +} + + +define_function(is_64bit) +{ + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + if (pe == NULL) + return_integer(UNDEFINED); + + return_integer(IS_64BITS_PE(pe) ? 1 : 0); +} + + +static uint64_t rich_internal( + YR_OBJECT* module, + uint64_t version, + uint64_t toolid) +{ + int64_t rich_length; + int64_t rich_count; + int64_t i; + + PRICH_SIGNATURE clear_rich_signature; + SIZED_STRING* rich_string; + + // Check if the required fields are set + if (is_undefined(module, "rich_signature.length")) + return UNDEFINED; + + rich_length = get_integer(module, "rich_signature.length"); + rich_string = get_string(module, "rich_signature.clear_data"); + + // If the clear_data was not set, return UNDEFINED + if (rich_string == NULL) + return UNDEFINED; + + if (version == UNDEFINED && toolid == UNDEFINED) + return FALSE; + + clear_rich_signature = (PRICH_SIGNATURE) rich_string->c_string; + + // Loop over the versions in the rich signature + + rich_count = \ + (rich_length - sizeof(RICH_SIGNATURE)) / sizeof(RICH_VERSION_INFO); + + for (i = 0; i < rich_count; i++) + { + DWORD id_version = yr_le32toh(clear_rich_signature->versions[i].id_version); + + int match_version = (version == RICH_VERSION_VERSION(id_version)); + int match_toolid = (toolid == RICH_VERSION_ID(id_version)); + + if (version != UNDEFINED && toolid != UNDEFINED) + { + // check version and toolid + if (match_version && match_toolid) + return TRUE; + } + else if (version != UNDEFINED) + { + // check only version + if (match_version) + return TRUE; + } + else if (toolid != UNDEFINED) + { + // check only toolid + if (match_toolid) + return TRUE; + } + } + + return FALSE; +} + + +define_function(rich_version) +{ + return_integer( + rich_internal(module(), integer_argument(1), UNDEFINED)); +} + + +define_function(rich_version_toolid) +{ + return_integer( + rich_internal(module(), integer_argument(1), integer_argument(2))); +} + + +define_function(rich_toolid) +{ + return_integer( + rich_internal(module(), UNDEFINED, integer_argument(1))); +} + + +define_function(rich_toolid_version) +{ + return_integer( + rich_internal(module(), integer_argument(2), integer_argument(1))); +} + + +define_function(calculate_checksum) +{ + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + uint64_t csum = 0; + size_t csum_offset; + size_t i, j; + + if (pe == NULL) + return_integer(UNDEFINED); + + csum_offset = ((uint8_t*) &(pe->header->OptionalHeader) + + offsetof(IMAGE_OPTIONAL_HEADER32, CheckSum)) - pe->data; + + for (i = 0; i <= pe->data_size / 4; i++) + { + // Treat the CheckSum field as 0 -- the offset is the same for + // PE32 and PE64. + + if (4 * i == csum_offset) + continue; + + if (4 * i + 4 <= pe->data_size) + { + csum += ((uint64_t) pe->data[4 * i] + + ((uint64_t) pe->data[4 * i + 1] << 8) + + ((uint64_t) pe->data[4 * i + 2] << 16) + + ((uint64_t) pe->data[4 * i + 3] << 24)); + } + else + { + for (j = 0; j < pe->data_size % 4; j++) + csum += (uint64_t) pe->data[4 * i + j] << (8 * j); + } + + if (csum > 0xffffffff) + csum = (csum & 0xffffffff) + (csum >> 32); + } + + csum = (csum & 0xffff) + (csum >> 16); + csum += (csum >> 16); + csum &= 0xffff; + csum += pe->data_size; + + return_integer(csum); +} + + +define_function(rva_to_offset) +{ + YR_OBJECT* module = module(); + PE* pe = (PE*) module->data; + + uint64_t rva, offset; + + if (pe == NULL) + return_integer(UNDEFINED); + + rva = integer_argument(1); + offset = pe_rva_to_offset(pe, rva); + if (offset == -1) + return_integer(UNDEFINED); + + return_integer(offset); +} + + +begin_declarations; + + declare_integer("MACHINE_UNKNOWN"); + declare_integer("MACHINE_AM33"); + declare_integer("MACHINE_AMD64"); + declare_integer("MACHINE_ARM"); + declare_integer("MACHINE_ARMNT"); + declare_integer("MACHINE_ARM64"); + declare_integer("MACHINE_EBC"); + declare_integer("MACHINE_I386"); + declare_integer("MACHINE_IA64"); + declare_integer("MACHINE_M32R"); + declare_integer("MACHINE_MIPS16"); + declare_integer("MACHINE_MIPSFPU"); + declare_integer("MACHINE_MIPSFPU16"); + declare_integer("MACHINE_POWERPC"); + declare_integer("MACHINE_POWERPCFP"); + declare_integer("MACHINE_R4000"); + declare_integer("MACHINE_SH3"); + declare_integer("MACHINE_SH3DSP"); + declare_integer("MACHINE_SH4"); + declare_integer("MACHINE_SH5"); + declare_integer("MACHINE_THUMB"); + declare_integer("MACHINE_WCEMIPSV2"); + + declare_integer("SUBSYSTEM_UNKNOWN"); + declare_integer("SUBSYSTEM_NATIVE"); + declare_integer("SUBSYSTEM_WINDOWS_GUI"); + declare_integer("SUBSYSTEM_WINDOWS_CUI"); + declare_integer("SUBSYSTEM_OS2_CUI"); + declare_integer("SUBSYSTEM_POSIX_CUI"); + declare_integer("SUBSYSTEM_NATIVE_WINDOWS"); + declare_integer("SUBSYSTEM_WINDOWS_CE_GUI"); + declare_integer("SUBSYSTEM_EFI_APPLICATION"); + declare_integer("SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER"); + declare_integer("SUBSYSTEM_EFI_RUNTIME_DRIVER"); + declare_integer("SUBSYSTEM_XBOX"); + declare_integer("SUBSYSTEM_WINDOWS_BOOT_APPLICATION"); + + declare_integer("DYNAMIC_BASE"); + declare_integer("FORCE_INTEGRITY"); + declare_integer("NX_COMPAT"); + declare_integer("NO_ISOLATION"); + declare_integer("NO_SEH"); + declare_integer("NO_BIND"); + declare_integer("WDM_DRIVER"); + declare_integer("TERMINAL_SERVER_AWARE"); + + declare_integer("RELOCS_STRIPPED"); + declare_integer("EXECUTABLE_IMAGE"); + declare_integer("LINE_NUMS_STRIPPED"); + declare_integer("LOCAL_SYMS_STRIPPED"); + declare_integer("AGGRESIVE_WS_TRIM"); + declare_integer("LARGE_ADDRESS_AWARE"); + declare_integer("BYTES_REVERSED_LO"); + declare_integer("MACHINE_32BIT"); + declare_integer("DEBUG_STRIPPED"); + declare_integer("REMOVABLE_RUN_FROM_SWAP"); + declare_integer("NET_RUN_FROM_SWAP"); + declare_integer("SYSTEM"); + declare_integer("DLL"); + declare_integer("UP_SYSTEM_ONLY"); + declare_integer("BYTES_REVERSED_HI"); + + declare_integer("SECTION_CNT_CODE"); + declare_integer("SECTION_CNT_INITIALIZED_DATA"); + declare_integer("SECTION_CNT_UNINITIALIZED_DATA"); + declare_integer("SECTION_GPREL"); + declare_integer("SECTION_MEM_16BIT"); + declare_integer("SECTION_LNK_NRELOC_OVFL"); + declare_integer("SECTION_MEM_DISCARDABLE"); + declare_integer("SECTION_MEM_NOT_CACHED"); + declare_integer("SECTION_MEM_NOT_PAGED"); + declare_integer("SECTION_MEM_SHARED"); + declare_integer("SECTION_MEM_EXECUTE"); + declare_integer("SECTION_MEM_READ"); + declare_integer("SECTION_MEM_WRITE"); + + declare_integer("RESOURCE_TYPE_CURSOR"); + declare_integer("RESOURCE_TYPE_BITMAP"); + declare_integer("RESOURCE_TYPE_ICON"); + declare_integer("RESOURCE_TYPE_MENU"); + declare_integer("RESOURCE_TYPE_DIALOG"); + declare_integer("RESOURCE_TYPE_STRING"); + declare_integer("RESOURCE_TYPE_FONTDIR"); + declare_integer("RESOURCE_TYPE_FONT"); + declare_integer("RESOURCE_TYPE_ACCELERATOR"); + declare_integer("RESOURCE_TYPE_RCDATA"); + declare_integer("RESOURCE_TYPE_MESSAGETABLE"); + declare_integer("RESOURCE_TYPE_GROUP_CURSOR"); + declare_integer("RESOURCE_TYPE_GROUP_ICON"); + declare_integer("RESOURCE_TYPE_VERSION"); + declare_integer("RESOURCE_TYPE_DLGINCLUDE"); + declare_integer("RESOURCE_TYPE_PLUGPLAY"); + declare_integer("RESOURCE_TYPE_VXD"); + declare_integer("RESOURCE_TYPE_ANICURSOR"); + declare_integer("RESOURCE_TYPE_ANIICON"); + declare_integer("RESOURCE_TYPE_HTML"); + declare_integer("RESOURCE_TYPE_MANIFEST"); + + declare_integer("machine"); + declare_integer("number_of_sections"); + declare_integer("timestamp"); + declare_integer("characteristics"); + + declare_integer("entry_point"); + declare_integer("image_base"); + declare_integer("number_of_rva_and_sizes"); + + declare_string_dictionary("version_info"); + + begin_struct("linker_version"); + declare_integer("major"); + declare_integer("minor"); + end_struct("linker_version"); + + begin_struct("os_version"); + declare_integer("major"); + declare_integer("minor"); + end_struct("os_version"); + + begin_struct("image_version"); + declare_integer("major"); + declare_integer("minor"); + end_struct("image_version"); + + begin_struct("subsystem_version"); + declare_integer("major"); + declare_integer("minor"); + end_struct("subsystem_version"); + + declare_integer("checksum"); + declare_function("calculate_checksum", "", "i", calculate_checksum); + declare_integer("subsystem"); + + declare_integer("dll_characteristics"); + + begin_struct_array("sections"); + declare_string("name"); + declare_integer("characteristics"); + declare_integer("virtual_address"); + declare_integer("virtual_size"); + declare_integer("raw_data_offset"); + declare_integer("raw_data_size"); + end_struct_array("sections"); + + begin_struct("overlay"); + declare_integer("offset"); + declare_integer("size"); + end_struct("overlay"); + + begin_struct("rich_signature"); + declare_integer("offset"); + declare_integer("length"); + declare_integer("key"); + declare_string("raw_data"); + declare_string("clear_data"); + declare_function("version", "i", "i", rich_version); + declare_function("version", "ii", "i", rich_version_toolid); + declare_function("toolid", "i", "i", rich_toolid); + declare_function("toolid", "ii", "i", rich_toolid_version); + end_struct("rich_signature"); + + #if defined(HAVE_LIBCRYPTO) || \ + defined(HAVE_WINCRYPT_H) || \ + defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) + declare_function("imphash", "", "s", imphash); + #endif + + declare_function("section_index", "s", "i", section_index_name); + declare_function("section_index", "i", "i", section_index_addr); + declare_function("exports", "s", "i", exports); + declare_function("exports", "r", "i", exports_regexp); + declare_function("exports", "i", "i", exports_ordinal); + declare_function("imports", "ss", "i", imports); + declare_function("imports", "si", "i", imports_ordinal); + declare_function("imports", "s", "i", imports_dll); + declare_function("locale", "i", "i", locale); + declare_function("language", "i", "i", language); + declare_function("is_dll", "", "i", is_dll); + declare_function("is_32bit", "", "i", is_32bit); + declare_function("is_64bit", "", "i", is_64bit); + + declare_integer("number_of_imports"); + declare_integer("number_of_exports"); + + declare_integer("resource_timestamp"); + + begin_struct("resource_version"); + declare_integer("major"); + declare_integer("minor"); + end_struct("resource_version"); + + begin_struct_array("resources"); + declare_integer("offset"); + declare_integer("length"); + declare_integer("type"); + declare_integer("id"); + declare_integer("language"); + declare_string("type_string"); + declare_string("name_string"); + declare_string("language_string"); + end_struct_array("resources"); + + declare_integer("number_of_resources"); + + #if defined(HAVE_LIBCRYPTO) + begin_struct_array("signatures"); + declare_string("issuer"); + declare_string("subject"); + declare_integer("version"); + declare_string("algorithm"); + declare_string("serial"); + declare_integer("not_before"); + declare_integer("not_after"); + declare_function("valid_on", "i", "i", valid_on); + end_struct_array("signatures"); + + declare_integer("number_of_signatures"); + #endif + + declare_function("rva_to_offset", "i", "i", rva_to_offset); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + YR_MEMORY_BLOCK* block; + YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; + + PIMAGE_NT_HEADERS32 pe_header; + const uint8_t* block_data = NULL; + PE* pe = NULL; + + set_integer( + IMAGE_FILE_MACHINE_UNKNOWN, module_object, + "MACHINE_UNKNOWN"); + set_integer( + IMAGE_FILE_MACHINE_AM33, module_object, + "MACHINE_AM33"); + set_integer( + IMAGE_FILE_MACHINE_AMD64, module_object, + "MACHINE_AMD64"); + set_integer( + IMAGE_FILE_MACHINE_ARM, module_object, + "MACHINE_ARM"); + set_integer( + IMAGE_FILE_MACHINE_ARMNT, module_object, + "MACHINE_ARMNT"); + set_integer( + IMAGE_FILE_MACHINE_ARM64, module_object, + "MACHINE_ARM64"); + set_integer( + IMAGE_FILE_MACHINE_EBC, module_object, + "MACHINE_EBC"); + set_integer( + IMAGE_FILE_MACHINE_I386, module_object, + "MACHINE_I386"); + set_integer( + IMAGE_FILE_MACHINE_IA64, module_object, + "MACHINE_IA64"); + set_integer( + IMAGE_FILE_MACHINE_M32R, module_object, + "MACHINE_M32R"); + set_integer( + IMAGE_FILE_MACHINE_MIPS16, module_object, + "MACHINE_MIPS16"); + set_integer( + IMAGE_FILE_MACHINE_MIPSFPU, module_object, + "MACHINE_MIPSFPU"); + set_integer( + IMAGE_FILE_MACHINE_MIPSFPU16, module_object, + "MACHINE_MIPSFPU16"); + set_integer( + IMAGE_FILE_MACHINE_POWERPC, module_object, + "MACHINE_POWERPC"); + set_integer( + IMAGE_FILE_MACHINE_POWERPCFP, module_object, + "MACHINE_POWERPCFP"); + set_integer( + IMAGE_FILE_MACHINE_R4000, module_object, + "MACHINE_R4000"); + set_integer( + IMAGE_FILE_MACHINE_SH3, module_object, + "MACHINE_SH3"); + set_integer( + IMAGE_FILE_MACHINE_SH3DSP, module_object, + "MACHINE_SH3DSP"); + set_integer( + IMAGE_FILE_MACHINE_SH4, module_object, + "MACHINE_SH4"); + set_integer( + IMAGE_FILE_MACHINE_SH5, module_object, + "MACHINE_SH5"); + set_integer( + IMAGE_FILE_MACHINE_THUMB, module_object, + "MACHINE_THUMB"); + set_integer( + IMAGE_FILE_MACHINE_WCEMIPSV2, module_object, + "MACHINE_WCEMIPSV2"); + + set_integer( + IMAGE_SUBSYSTEM_UNKNOWN, module_object, + "SUBSYSTEM_UNKNOWN"); + set_integer( + IMAGE_SUBSYSTEM_NATIVE, module_object, + "SUBSYSTEM_NATIVE"); + set_integer( + IMAGE_SUBSYSTEM_WINDOWS_GUI, module_object, + "SUBSYSTEM_WINDOWS_GUI"); + set_integer( + IMAGE_SUBSYSTEM_WINDOWS_CUI, module_object, + "SUBSYSTEM_WINDOWS_CUI"); + set_integer( + IMAGE_SUBSYSTEM_OS2_CUI, module_object, + "SUBSYSTEM_OS2_CUI"); + set_integer( + IMAGE_SUBSYSTEM_POSIX_CUI, module_object, + "SUBSYSTEM_POSIX_CUI"); + set_integer( + IMAGE_SUBSYSTEM_NATIVE_WINDOWS, module_object, + "SUBSYSTEM_NATIVE_WINDOWS"); + set_integer( + IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, module_object, + "SUBSYSTEM_WINDOWS_CE_GUI"); + set_integer( + IMAGE_SUBSYSTEM_EFI_APPLICATION, module_object, + "SUBSYSTEM_EFI_APPLICATION"); + set_integer( + IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, module_object, + "SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER"); + set_integer( + IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, module_object, + "SUBSYSTEM_EFI_RUNTIME_DRIVER"); + set_integer( + IMAGE_SUBSYSTEM_XBOX, module_object, + "SUBSYSTEM_XBOX"); + set_integer( + IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION, module_object, + "SUBSYSTEM_WINDOWS_BOOT_APPLICATION"); + + set_integer( + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, module_object, + "DYNAMIC_BASE"); + set_integer( + IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY, module_object, + "FORCE_INTEGRITY"); + set_integer( + IMAGE_DLLCHARACTERISTICS_NX_COMPAT, module_object, + "NX_COMPAT"); + set_integer( + IMAGE_DLLCHARACTERISTICS_NO_ISOLATION, module_object, + "NO_ISOLATION"); + set_integer( + IMAGE_DLLCHARACTERISTICS_NO_SEH, module_object, + "NO_SEH"); + set_integer( + IMAGE_DLLCHARACTERISTICS_NO_BIND, module_object, + "NO_BIND"); + set_integer( + IMAGE_DLLCHARACTERISTICS_WDM_DRIVER, module_object, + "WDM_DRIVER"); + set_integer( + IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, module_object, + "TERMINAL_SERVER_AWARE"); + + set_integer( + IMAGE_FILE_RELOCS_STRIPPED, module_object, + "RELOCS_STRIPPED"); + set_integer( + IMAGE_FILE_EXECUTABLE_IMAGE, module_object, + "EXECUTABLE_IMAGE"); + set_integer( + IMAGE_FILE_LINE_NUMS_STRIPPED, module_object, + "LINE_NUMS_STRIPPED"); + set_integer( + IMAGE_FILE_LOCAL_SYMS_STRIPPED, module_object, + "LOCAL_SYMS_STRIPPED"); + set_integer( + IMAGE_FILE_AGGRESIVE_WS_TRIM, module_object, + "AGGRESIVE_WS_TRIM"); + set_integer( + IMAGE_FILE_LARGE_ADDRESS_AWARE, module_object, + "LARGE_ADDRESS_AWARE"); + set_integer( + IMAGE_FILE_BYTES_REVERSED_LO, module_object, + "BYTES_REVERSED_LO"); + set_integer( + IMAGE_FILE_32BIT_MACHINE, module_object, + "MACHINE_32BIT"); + set_integer( + IMAGE_FILE_DEBUG_STRIPPED, module_object, + "DEBUG_STRIPPED"); + set_integer( + IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, module_object, + "REMOVABLE_RUN_FROM_SWAP"); + set_integer( + IMAGE_FILE_NET_RUN_FROM_SWAP, module_object, + "NET_RUN_FROM_SWAP"); + set_integer( + IMAGE_FILE_SYSTEM, module_object, + "SYSTEM"); + set_integer( + IMAGE_FILE_DLL, module_object, + "DLL"); + set_integer( + IMAGE_FILE_UP_SYSTEM_ONLY, module_object, + "UP_SYSTEM_ONLY"); + set_integer( + IMAGE_FILE_BYTES_REVERSED_HI, module_object, + "BYTES_REVERSED_HI"); + + set_integer( + IMAGE_SCN_CNT_CODE, module_object, + "SECTION_CNT_CODE"); + set_integer( + IMAGE_SCN_CNT_INITIALIZED_DATA, module_object, + "SECTION_CNT_INITIALIZED_DATA"); + set_integer( + IMAGE_SCN_CNT_UNINITIALIZED_DATA, module_object, + "SECTION_CNT_UNINITIALIZED_DATA"); + set_integer( + IMAGE_SCN_GPREL, module_object, + "SECTION_GPREL"); + set_integer( + IMAGE_SCN_MEM_16BIT, module_object, + "SECTION_MEM_16BIT"); + set_integer( + IMAGE_SCN_LNK_NRELOC_OVFL, module_object, + "SECTION_LNK_NRELOC_OVFL"); + set_integer( + IMAGE_SCN_MEM_DISCARDABLE, module_object, + "SECTION_MEM_DISCARDABLE"); + set_integer( + IMAGE_SCN_MEM_NOT_CACHED, module_object, + "SECTION_MEM_NOT_CACHED"); + set_integer( + IMAGE_SCN_MEM_NOT_PAGED, module_object, + "SECTION_MEM_NOT_PAGED"); + set_integer( + IMAGE_SCN_MEM_SHARED, module_object, + "SECTION_MEM_SHARED"); + set_integer( + IMAGE_SCN_MEM_EXECUTE, module_object, + "SECTION_MEM_EXECUTE"); + set_integer( + IMAGE_SCN_MEM_READ, module_object, + "SECTION_MEM_READ"); + set_integer( + IMAGE_SCN_MEM_WRITE, module_object, + "SECTION_MEM_WRITE"); + + set_integer( + RESOURCE_TYPE_CURSOR, module_object, + "RESOURCE_TYPE_CURSOR"); + set_integer( + RESOURCE_TYPE_BITMAP, module_object, + "RESOURCE_TYPE_BITMAP"); + set_integer( + RESOURCE_TYPE_ICON, module_object, + "RESOURCE_TYPE_ICON"); + set_integer( + RESOURCE_TYPE_MENU, module_object, + "RESOURCE_TYPE_MENU"); + set_integer( + RESOURCE_TYPE_DIALOG, module_object, + "RESOURCE_TYPE_DIALOG"); + set_integer( + RESOURCE_TYPE_STRING, module_object, + "RESOURCE_TYPE_STRING"); + set_integer( + RESOURCE_TYPE_FONTDIR, module_object, + "RESOURCE_TYPE_FONTDIR"); + set_integer( + RESOURCE_TYPE_FONT, module_object, + "RESOURCE_TYPE_FONT"); + set_integer( + RESOURCE_TYPE_ACCELERATOR, module_object, + "RESOURCE_TYPE_ACCELERATOR"); + set_integer( + RESOURCE_TYPE_RCDATA, module_object, + "RESOURCE_TYPE_RCDATA"); + set_integer( + RESOURCE_TYPE_MESSAGETABLE, module_object, + "RESOURCE_TYPE_MESSAGETABLE"); + set_integer( + RESOURCE_TYPE_GROUP_CURSOR, module_object, + "RESOURCE_TYPE_GROUP_CURSOR"); + set_integer( + RESOURCE_TYPE_GROUP_ICON, module_object, + "RESOURCE_TYPE_GROUP_ICON"); + set_integer( + RESOURCE_TYPE_VERSION, module_object, + "RESOURCE_TYPE_VERSION"); + set_integer( + RESOURCE_TYPE_DLGINCLUDE, module_object, + "RESOURCE_TYPE_DLGINCLUDE"); + set_integer( + RESOURCE_TYPE_PLUGPLAY, module_object, + "RESOURCE_TYPE_PLUGPLAY"); + set_integer( + RESOURCE_TYPE_VXD, module_object, + "RESOURCE_TYPE_VXD"); + set_integer( + RESOURCE_TYPE_ANICURSOR, module_object, + "RESOURCE_TYPE_ANICURSOR"); + set_integer( + RESOURCE_TYPE_ANIICON, module_object, + "RESOURCE_TYPE_ANIICON"); + set_integer( + RESOURCE_TYPE_HTML, module_object, + "RESOURCE_TYPE_HTML"); + set_integer( + RESOURCE_TYPE_MANIFEST, module_object, + "RESOURCE_TYPE_MANIFEST"); + + foreach_memory_block(iterator, block) + { + block_data = block->fetch_data(block); + + if (block_data == NULL) + continue; + + pe_header = pe_get_header(block_data, block->size); + + if (pe_header != NULL) + { + // Ignore DLLs while scanning a process + + if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || + !(yr_le16toh(pe_header->FileHeader.Characteristics) & IMAGE_FILE_DLL)) + { + pe = (PE*) yr_malloc(sizeof(PE)); + + if (pe == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + pe->data = block_data; + pe->data_size = block->size; + pe->header = pe_header; + pe->object = module_object; + pe->resources = 0; + + module_object->data = pe; + + pe_parse_header(pe, block->base, context->flags); + pe_parse_rich_signature(pe, block->base); + + #if defined(HAVE_LIBCRYPTO) + pe_parse_certificates(pe); + #endif + + pe->imported_dlls = pe_parse_imports(pe); + pe->exported_functions = pe_parse_exports(pe); + + break; + } + } + } + + return ERROR_SUCCESS; +} + + +int module_unload( + YR_OBJECT* module_object) +{ + IMPORTED_DLL* dll = NULL; + IMPORTED_DLL* next_dll = NULL; + IMPORT_EXPORT_FUNCTION* func = NULL; + IMPORT_EXPORT_FUNCTION* next_func = NULL; + + PE* pe = (PE *) module_object->data; + + if (pe == NULL) + return ERROR_SUCCESS; + + dll = pe->imported_dlls; + + while (dll) + { + if (dll->name) + yr_free(dll->name); + + func = dll->functions; + + while (func) + { + if (func->name) + yr_free(func->name); + + next_func = func->next; + yr_free(func); + func = next_func; + } + + next_dll = dll->next; + yr_free(dll); + dll = next_dll; + } + + func = pe->exported_functions; + + while (func) + { + yr_free(func->name); + next_func = func->next; + yr_free(func); + func = next_func; + } + + yr_free(pe); + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/pe_utils.c b/yara-master/libyara/modules/pe_utils.c new file mode 100644 index 0000000..18a7dca --- /dev/null +++ b/yara-master/libyara/modules/pe_utils.c @@ -0,0 +1,1929 @@ +/* +Copyright (c) 2014-2015. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_LIBCRYPTO +#include +#endif + +PIMAGE_NT_HEADERS32 pe_get_header( + const uint8_t* data, + size_t data_size) +{ + PIMAGE_DOS_HEADER mz_header; + PIMAGE_NT_HEADERS32 pe_header; + + size_t headers_size = 0; + + if (data_size < sizeof(IMAGE_DOS_HEADER)) + return NULL; + + mz_header = (PIMAGE_DOS_HEADER) data; + + if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE) + return NULL; + + if (yr_le32toh(mz_header->e_lfanew) < 0) + return NULL; + + headers_size = yr_le32toh(mz_header->e_lfanew) + \ + sizeof(pe_header->Signature) + \ + sizeof(IMAGE_FILE_HEADER); + + if (data_size < headers_size) + return NULL; + + pe_header = (PIMAGE_NT_HEADERS32) (data + yr_le32toh(mz_header->e_lfanew)); + + if (yr_le32toh(pe_header->Signature) != IMAGE_NT_SIGNATURE) + return NULL; + + if (data_size < headers_size + sizeof(IMAGE_OPTIONAL_HEADER32)) + return NULL; + + if (pe_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + headers_size += sizeof(IMAGE_OPTIONAL_HEADER64); + else + headers_size += sizeof(IMAGE_OPTIONAL_HEADER32); + + if (data_size < headers_size) + return NULL; + + if (yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_UNKNOWN && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_AM33 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_AMD64 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_ARM && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_ARMNT && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_ARM64 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_EBC && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_I386 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_IA64 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_M32R && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_MIPS16 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_MIPSFPU && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_MIPSFPU16 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_POWERPC && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_POWERPCFP && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_R4000 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_SH3 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_SH3DSP && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_SH4 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_SH5 && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_THUMB && + yr_le16toh(pe_header->FileHeader.Machine) != IMAGE_FILE_MACHINE_WCEMIPSV2) + { + return NULL; + } + + return pe_header; +} + + +PIMAGE_DATA_DIRECTORY pe_get_directory_entry( + PE* pe, + int entry) +{ + PIMAGE_DATA_DIRECTORY directory_start; + uint8_t* optional_header_start; + uint16_t optional_header_size; + + // We are specifically NOT checking NumberOfRvaAndSizes here because it can + // lie. 7ff1bf680c80fd73c0b35084904848b3705480ddeb6d0eff62180bd14cd18570 has + // NumberOfRvaAndSizes set to 11 when in fact there is a valid + // IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR entry (which is more than 11). If we + // are overly strict here and only parse entries which are less than + // NumberOfRvaAndSizes we run the risk of missing otherwise perfectly valid + // files. Instead of being strict we check to make sure the entry is within + // the OptionalHeader, since SizeOfOptionalHeader includes the DataDirectory + // array. + + // In case someone requests an entry which is, by definition, invalid. + if (entry >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) + return NULL; + + if (IS_64BITS_PE(pe)) + { + optional_header_start = (uint8_t*) &pe->header64->OptionalHeader; + optional_header_size = pe->header64->FileHeader.SizeOfOptionalHeader; + directory_start = pe->header64->OptionalHeader.DataDirectory; + } + else + { + optional_header_start = (uint8_t*) &pe->header->OptionalHeader; + optional_header_size = pe->header->FileHeader.SizeOfOptionalHeader; + directory_start = pe->header->OptionalHeader.DataDirectory; + } + + // Make sure the entry doesn't point outside of the OptionalHeader. + if ((uint8_t*) (directory_start + entry) <= optional_header_start + optional_header_size) + { + if (IS_64BITS_PE(pe)) + return &pe->header64->OptionalHeader.DataDirectory[entry]; + else + return &pe->header->OptionalHeader.DataDirectory[entry]; + } + + return NULL; +} + + +int64_t pe_rva_to_offset( + PE* pe, + uint64_t rva) +{ + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pe->header); + + DWORD lowest_section_rva = 0xffffffff; + DWORD section_rva = 0; + DWORD section_offset = 0; + DWORD section_raw_size = 0; + + int64_t result; + + int i = 0; + + int alignment = 0; + int rest = 0; + + while(i < yr_min(yr_le16toh(pe->header->FileHeader.NumberOfSections), MAX_PE_SECTIONS)) + { + if (struct_fits_in_pe(pe, section, IMAGE_SECTION_HEADER)) + { + if (lowest_section_rva > yr_le32toh(section->VirtualAddress)) + { + lowest_section_rva = yr_le32toh(section->VirtualAddress); + } + + if (rva >= yr_le32toh(section->VirtualAddress) && + section_rva <= yr_le32toh(section->VirtualAddress)) + { + // Round section_offset + // + // Rounding everything less than 0x200 to 0 as discussed in + // https://code.google.com/archive/p/corkami/wikis/PE.wiki#PointerToRawData + // does not work for PE32_FILE from the test suite and for + // some tinype samples where File Alignment = 4 + // (http://www.phreedom.org/research/tinype/). + // + // If FileAlignment is >= 0x200, it is apparently ignored (see + // Ero Carreras's pefile.py, PE.adjust_FileAlignment). + + alignment = yr_min(yr_le32toh(OptionalHeader(pe, FileAlignment)), 0x200); + + section_rva = yr_le32toh(section->VirtualAddress); + section_offset = yr_le32toh(section->PointerToRawData); + section_raw_size = yr_le32toh(section->SizeOfRawData); + + if (alignment) + { + rest = section_offset % alignment; + + if (rest) + section_offset -= rest; + } + } + + section++; + i++; + } + else + { + return -1; + } + } + + // Everything before the first section seems to get mapped straight + // relative to ImageBase. + + if (rva < lowest_section_rva) + { + section_rva = 0; + section_offset = 0; + section_raw_size = (DWORD) pe->data_size; + } + + // Many sections, have a raw (on disk) size smaller than their in-memory size. + // Check for rva's that map to this sparse space, and therefore have no valid + // associated file offset. + + if ((rva - section_rva) >= section_raw_size) + return -1; + + result = section_offset + (rva - section_rva); + + // Check that the offset fits within the file. + if (result >= pe->data_size) + return -1; + + return result; +} + + +#if !HAVE_TIMEGM +#if HAVE__MKGMTIME +#define timegm _mkgmtime +#else + +#include + +static int is_leap( + unsigned int year) +{ + year += 1900; + return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); +} + + +time_t timegm( + struct tm *tm) +{ + static const unsigned ndays[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + + time_t res = 0; + int i; + + for (i = 70; i < tm->tm_year; ++i) + res += is_leap(i) ? 366 : 365; + + for (i = 0; i < tm->tm_mon; ++i) + res += ndays[is_leap(tm->tm_year)][i]; + + res += tm->tm_mday - 1; + res *= 24; + res += tm->tm_hour; + res *= 60; + res += tm->tm_min; + res *= 60; + res += tm->tm_sec; + + return res; +} + +#endif // HAVE__MKGMTIME +#endif // !HAVE_TIMEGM + +#if HAVE_LIBCRYPTO + +// Taken from http://stackoverflow.com/questions/10975542/asn1-time-conversion +// and cleaned up. Also uses timegm(3) instead of mktime(3). + +time_t ASN1_get_time_t( + ASN1_TIME* time) +{ + struct tm t; + const char* str = (const char*) time->data; + size_t i = 0; + + memset(&t, 0, sizeof(t)); + + if (time->type == V_ASN1_UTCTIME) /* two digit year */ + { + t.tm_year = (str[i++] - '0') * 10; + t.tm_year += (str[i++] - '0'); + + if (t.tm_year < 70) + t.tm_year += 100; + } + else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */ + { + t.tm_year = (str[i++] - '0') * 1000; + t.tm_year += (str[i++] - '0') * 100; + t.tm_year += (str[i++] - '0') * 10; + t.tm_year += (str[i++] - '0'); + t.tm_year -= 1900; + } + + t.tm_mon = (str[i++] - '0') * 10; + t.tm_mon += (str[i++] - '0') - 1; // -1 since January is 0 not 1. + t.tm_mday = (str[i++] - '0') * 10; + t.tm_mday += (str[i++] - '0'); + t.tm_hour = (str[i++] - '0') * 10; + t.tm_hour += (str[i++] - '0'); + t.tm_min = (str[i++] - '0') * 10; + t.tm_min += (str[i++] - '0'); + t.tm_sec = (str[i++] - '0') * 10; + t.tm_sec += (str[i++] - '0'); + + /* Note: we did not adjust the time based on time zone information */ + return timegm(&t); +} + +#endif + + +// These ordinals are taken from pefile. If a lookup fails attempt to return +// "ordN" and if that fails, return NULL. The caller is responsible for freeing +// the returned string. + +char *ord_lookup( + char *dll, + uint16_t ord) +{ + char name[64]; + name[0] = '\0'; + + if (strncasecmp(dll, "WS2_32.dll", 10) == 0 || + strncasecmp(dll, "wsock32.dll", 11) == 0) + { + switch(ord) { + case 1: + sprintf(name, "accept"); + break; + case 2: + sprintf(name, "bind"); + break; + case 3: + sprintf(name, "closesocket"); + break; + case 4: + sprintf(name, "connect"); + break; + case 5: + sprintf(name, "getpeername"); + break; + case 6: + sprintf(name, "getsockname"); + break; + case 7: + sprintf(name, "getsockopt"); + break; + case 8: + sprintf(name, "htonl"); + break; + case 9: + sprintf(name, "htons"); + break; + case 10: + sprintf(name, "ioctlsocket"); + break; + case 11: + sprintf(name, "inet_addr"); + break; + case 12: + sprintf(name, "inet_ntoa"); + break; + case 13: + sprintf(name, "listen"); + break; + case 14: + sprintf(name, "ntohl"); + break; + case 15: + sprintf(name, "ntohs"); + break; + case 16: + sprintf(name, "recv"); + break; + case 17: + sprintf(name, "recvfrom"); + break; + case 18: + sprintf(name, "select"); + break; + case 19: + sprintf(name, "send"); + break; + case 20: + sprintf(name, "sendto"); + break; + case 21: + sprintf(name, "setsockopt"); + break; + case 22: + sprintf(name, "shutdown"); + break; + case 23: + sprintf(name, "socket"); + break; + case 24: + sprintf(name, "GetAddrInfoW"); + break; + case 25: + sprintf(name, "GetNameInfoW"); + break; + case 26: + sprintf(name, "WSApSetPostRoutine"); + break; + case 27: + sprintf(name, "FreeAddrInfoW"); + break; + case 28: + sprintf(name, "WPUCompleteOverlappedRequest"); + break; + case 29: + sprintf(name, "WSAAccept"); + break; + case 30: + sprintf(name, "WSAAddressToStringA"); + break; + case 31: + sprintf(name, "WSAAddressToStringW"); + break; + case 32: + sprintf(name, "WSACloseEvent"); + break; + case 33: + sprintf(name, "WSAConnect"); + break; + case 34: + sprintf(name, "WSACreateEvent"); + break; + case 35: + sprintf(name, "WSADuplicateSocketA"); + break; + case 36: + sprintf(name, "WSADuplicateSocketW"); + break; + case 37: + sprintf(name, "WSAEnumNameSpaceProvidersA"); + break; + case 38: + sprintf(name, "WSAEnumNameSpaceProvidersW"); + break; + case 39: + sprintf(name, "WSAEnumNetworkEvents"); + break; + case 40: + sprintf(name, "WSAEnumProtocolsA"); + break; + case 41: + sprintf(name, "WSAEnumProtocolsW"); + break; + case 42: + sprintf(name, "WSAEventSelect"); + break; + case 43: + sprintf(name, "WSAGetOverlappedResult"); + break; + case 44: + sprintf(name, "WSAGetQOSByName"); + break; + case 45: + sprintf(name, "WSAGetServiceClassInfoA"); + break; + case 46: + sprintf(name, "WSAGetServiceClassInfoW"); + break; + case 47: + sprintf(name, "WSAGetServiceClassNameByClassIdA"); + break; + case 48: + sprintf(name, "WSAGetServiceClassNameByClassIdW"); + break; + case 49: + sprintf(name, "WSAHtonl"); + break; + case 50: + sprintf(name, "WSAHtons"); + break; + case 51: + sprintf(name, "gethostbyaddr"); + break; + case 52: + sprintf(name, "gethostbyname"); + break; + case 53: + sprintf(name, "getprotobyname"); + break; + case 54: + sprintf(name, "getprotobynumber"); + break; + case 55: + sprintf(name, "getservbyname"); + break; + case 56: + sprintf(name, "getservbyport"); + break; + case 57: + sprintf(name, "gethostname"); + break; + case 58: + sprintf(name, "WSAInstallServiceClassA"); + break; + case 59: + sprintf(name, "WSAInstallServiceClassW"); + break; + case 60: + sprintf(name, "WSAIoctl"); + break; + case 61: + sprintf(name, "WSAJoinLeaf"); + break; + case 62: + sprintf(name, "WSALookupServiceBeginA"); + break; + case 63: + sprintf(name, "WSALookupServiceBeginW"); + break; + case 64: + sprintf(name, "WSALookupServiceEnd"); + break; + case 65: + sprintf(name, "WSALookupServiceNextA"); + break; + case 66: + sprintf(name, "WSALookupServiceNextW"); + break; + case 67: + sprintf(name, "WSANSPIoctl"); + break; + case 68: + sprintf(name, "WSANtohl"); + break; + case 69: + sprintf(name, "WSANtohs"); + break; + case 70: + sprintf(name, "WSAProviderConfigChange"); + break; + case 71: + sprintf(name, "WSARecv"); + break; + case 72: + sprintf(name, "WSARecvDisconnect"); + break; + case 73: + sprintf(name, "WSARecvFrom"); + break; + case 74: + sprintf(name, "WSARemoveServiceClass"); + break; + case 75: + sprintf(name, "WSAResetEvent"); + break; + case 76: + sprintf(name, "WSASend"); + break; + case 77: + sprintf(name, "WSASendDisconnect"); + break; + case 78: + sprintf(name, "WSASendTo"); + break; + case 79: + sprintf(name, "WSASetEvent"); + break; + case 80: + sprintf(name, "WSASetServiceA"); + break; + case 81: + sprintf(name, "WSASetServiceW"); + break; + case 82: + sprintf(name, "WSASocketA"); + break; + case 83: + sprintf(name, "WSASocketW"); + break; + case 84: + sprintf(name, "WSAStringToAddressA"); + break; + case 85: + sprintf(name, "WSAStringToAddressW"); + break; + case 86: + sprintf(name, "WSAWaitForMultipleEvents"); + break; + case 87: + sprintf(name, "WSCDeinstallProvider"); + break; + case 88: + sprintf(name, "WSCEnableNSProvider"); + break; + case 89: + sprintf(name, "WSCEnumProtocols"); + break; + case 90: + sprintf(name, "WSCGetProviderPath"); + break; + case 91: + sprintf(name, "WSCInstallNameSpace"); + break; + case 92: + sprintf(name, "WSCInstallProvider"); + break; + case 93: + sprintf(name, "WSCUnInstallNameSpace"); + break; + case 94: + sprintf(name, "WSCUpdateProvider"); + break; + case 95: + sprintf(name, "WSCWriteNameSpaceOrder"); + break; + case 96: + sprintf(name, "WSCWriteProviderOrder"); + break; + case 97: + sprintf(name, "freeaddrinfo"); + break; + case 98: + sprintf(name, "getaddrinfo"); + break; + case 99: + sprintf(name, "getnameinfo"); + break; + case 101: + sprintf(name, "WSAAsyncSelect"); + break; + case 102: + sprintf(name, "WSAAsyncGetHostByAddr"); + break; + case 103: + sprintf(name, "WSAAsyncGetHostByName"); + break; + case 104: + sprintf(name, "WSAAsyncGetProtoByNumber"); + break; + case 105: + sprintf(name, "WSAAsyncGetProtoByName"); + break; + case 106: + sprintf(name, "WSAAsyncGetServByPort"); + break; + case 107: + sprintf(name, "WSAAsyncGetServByName"); + break; + case 108: + sprintf(name, "WSACancelAsyncRequest"); + break; + case 109: + sprintf(name, "WSASetBlockingHook"); + break; + case 110: + sprintf(name, "WSAUnhookBlockingHook"); + break; + case 111: + sprintf(name, "WSAGetLastError"); + break; + case 112: + sprintf(name, "WSASetLastError"); + break; + case 113: + sprintf(name, "WSACancelBlockingCall"); + break; + case 114: + sprintf(name, "WSAIsBlocking"); + break; + case 115: + sprintf(name, "WSAStartup"); + break; + case 116: + sprintf(name, "WSACleanup"); + break; + case 151: + sprintf(name, "__WSAFDIsSet"); + break; + case 500: + sprintf(name, "WEP"); + break; + default: + break; + } + } + else if (strncasecmp(dll, "oleaut32.dll", 12) == 0) + { + switch (ord) { + case 2: + sprintf(name, "SysAllocString"); + break; + case 3: + sprintf(name, "SysReAllocString"); + break; + case 4: + sprintf(name, "SysAllocStringLen"); + break; + case 5: + sprintf(name, "SysReAllocStringLen"); + break; + case 6: + sprintf(name, "SysFreeString"); + break; + case 7: + sprintf(name, "SysStringLen"); + break; + case 8: + sprintf(name, "VariantInit"); + break; + case 9: + sprintf(name, "VariantClear"); + break; + case 10: + sprintf(name, "VariantCopy"); + break; + case 11: + sprintf(name, "VariantCopyInd"); + break; + case 12: + sprintf(name, "VariantChangeType"); + break; + case 13: + sprintf(name, "VariantTimeToDosDateTime"); + break; + case 14: + sprintf(name, "DosDateTimeToVariantTime"); + break; + case 15: + sprintf(name, "SafeArrayCreate"); + break; + case 16: + sprintf(name, "SafeArrayDestroy"); + break; + case 17: + sprintf(name, "SafeArrayGetDim"); + break; + case 18: + sprintf(name, "SafeArrayGetElemsize"); + break; + case 19: + sprintf(name, "SafeArrayGetUBound"); + break; + case 20: + sprintf(name, "SafeArrayGetLBound"); + break; + case 21: + sprintf(name, "SafeArrayLock"); + break; + case 22: + sprintf(name, "SafeArrayUnlock"); + break; + case 23: + sprintf(name, "SafeArrayAccessData"); + break; + case 24: + sprintf(name, "SafeArrayUnaccessData"); + break; + case 25: + sprintf(name, "SafeArrayGetElement"); + break; + case 26: + sprintf(name, "SafeArrayPutElement"); + break; + case 27: + sprintf(name, "SafeArrayCopy"); + break; + case 28: + sprintf(name, "DispGetParam"); + break; + case 29: + sprintf(name, "DispGetIDsOfNames"); + break; + case 30: + sprintf(name, "DispInvoke"); + break; + case 31: + sprintf(name, "CreateDispTypeInfo"); + break; + case 32: + sprintf(name, "CreateStdDispatch"); + break; + case 33: + sprintf(name, "RegisterActiveObject"); + break; + case 34: + sprintf(name, "RevokeActiveObject"); + break; + case 35: + sprintf(name, "GetActiveObject"); + break; + case 36: + sprintf(name, "SafeArrayAllocDescriptor"); + break; + case 37: + sprintf(name, "SafeArrayAllocData"); + break; + case 38: + sprintf(name, "SafeArrayDestroyDescriptor"); + break; + case 39: + sprintf(name, "SafeArrayDestroyData"); + break; + case 40: + sprintf(name, "SafeArrayRedim"); + break; + case 41: + sprintf(name, "SafeArrayAllocDescriptorEx"); + break; + case 42: + sprintf(name, "SafeArrayCreateEx"); + break; + case 43: + sprintf(name, "SafeArrayCreateVectorEx"); + break; + case 44: + sprintf(name, "SafeArraySetRecordInfo"); + break; + case 45: + sprintf(name, "SafeArrayGetRecordInfo"); + break; + case 46: + sprintf(name, "VarParseNumFromStr"); + break; + case 47: + sprintf(name, "VarNumFromParseNum"); + break; + case 48: + sprintf(name, "VarI2FromUI1"); + break; + case 49: + sprintf(name, "VarI2FromI4"); + break; + case 50: + sprintf(name, "VarI2FromR4"); + break; + case 51: + sprintf(name, "VarI2FromR8"); + break; + case 52: + sprintf(name, "VarI2FromCy"); + break; + case 53: + sprintf(name, "VarI2FromDate"); + break; + case 54: + sprintf(name, "VarI2FromStr"); + break; + case 55: + sprintf(name, "VarI2FromDisp"); + break; + case 56: + sprintf(name, "VarI2FromBool"); + break; + case 57: + sprintf(name, "SafeArraySetIID"); + break; + case 58: + sprintf(name, "VarI4FromUI1"); + break; + case 59: + sprintf(name, "VarI4FromI2"); + break; + case 60: + sprintf(name, "VarI4FromR4"); + break; + case 61: + sprintf(name, "VarI4FromR8"); + break; + case 62: + sprintf(name, "VarI4FromCy"); + break; + case 63: + sprintf(name, "VarI4FromDate"); + break; + case 64: + sprintf(name, "VarI4FromStr"); + break; + case 65: + sprintf(name, "VarI4FromDisp"); + break; + case 66: + sprintf(name, "VarI4FromBool"); + break; + case 67: + sprintf(name, "SafeArrayGetIID"); + break; + case 68: + sprintf(name, "VarR4FromUI1"); + break; + case 69: + sprintf(name, "VarR4FromI2"); + break; + case 70: + sprintf(name, "VarR4FromI4"); + break; + case 71: + sprintf(name, "VarR4FromR8"); + break; + case 72: + sprintf(name, "VarR4FromCy"); + break; + case 73: + sprintf(name, "VarR4FromDate"); + break; + case 74: + sprintf(name, "VarR4FromStr"); + break; + case 75: + sprintf(name, "VarR4FromDisp"); + break; + case 76: + sprintf(name, "VarR4FromBool"); + break; + case 77: + sprintf(name, "SafeArrayGetVartype"); + break; + case 78: + sprintf(name, "VarR8FromUI1"); + break; + case 79: + sprintf(name, "VarR8FromI2"); + break; + case 80: + sprintf(name, "VarR8FromI4"); + break; + case 81: + sprintf(name, "VarR8FromR4"); + break; + case 82: + sprintf(name, "VarR8FromCy"); + break; + case 83: + sprintf(name, "VarR8FromDate"); + break; + case 84: + sprintf(name, "VarR8FromStr"); + break; + case 85: + sprintf(name, "VarR8FromDisp"); + break; + case 86: + sprintf(name, "VarR8FromBool"); + break; + case 87: + sprintf(name, "VarFormat"); + break; + case 88: + sprintf(name, "VarDateFromUI1"); + break; + case 89: + sprintf(name, "VarDateFromI2"); + break; + case 90: + sprintf(name, "VarDateFromI4"); + break; + case 91: + sprintf(name, "VarDateFromR4"); + break; + case 92: + sprintf(name, "VarDateFromR8"); + break; + case 93: + sprintf(name, "VarDateFromCy"); + break; + case 94: + sprintf(name, "VarDateFromStr"); + break; + case 95: + sprintf(name, "VarDateFromDisp"); + break; + case 96: + sprintf(name, "VarDateFromBool"); + break; + case 97: + sprintf(name, "VarFormatDateTime"); + break; + case 98: + sprintf(name, "VarCyFromUI1"); + break; + case 99: + sprintf(name, "VarCyFromI2"); + break; + case 100: + sprintf(name, "VarCyFromI4"); + break; + case 101: + sprintf(name, "VarCyFromR4"); + break; + case 102: + sprintf(name, "VarCyFromR8"); + break; + case 103: + sprintf(name, "VarCyFromDate"); + break; + case 104: + sprintf(name, "VarCyFromStr"); + break; + case 105: + sprintf(name, "VarCyFromDisp"); + break; + case 106: + sprintf(name, "VarCyFromBool"); + break; + case 107: + sprintf(name, "VarFormatNumber"); + break; + case 108: + sprintf(name, "VarBstrFromUI1"); + break; + case 109: + sprintf(name, "VarBstrFromI2"); + break; + case 110: + sprintf(name, "VarBstrFromI4"); + break; + case 111: + sprintf(name, "VarBstrFromR4"); + break; + case 112: + sprintf(name, "VarBstrFromR8"); + break; + case 113: + sprintf(name, "VarBstrFromCy"); + break; + case 114: + sprintf(name, "VarBstrFromDate"); + break; + case 115: + sprintf(name, "VarBstrFromDisp"); + break; + case 116: + sprintf(name, "VarBstrFromBool"); + break; + case 117: + sprintf(name, "VarFormatPercent"); + break; + case 118: + sprintf(name, "VarBoolFromUI1"); + break; + case 119: + sprintf(name, "VarBoolFromI2"); + break; + case 120: + sprintf(name, "VarBoolFromI4"); + break; + case 121: + sprintf(name, "VarBoolFromR4"); + break; + case 122: + sprintf(name, "VarBoolFromR8"); + break; + case 123: + sprintf(name, "VarBoolFromDate"); + break; + case 124: + sprintf(name, "VarBoolFromCy"); + break; + case 125: + sprintf(name, "VarBoolFromStr"); + break; + case 126: + sprintf(name, "VarBoolFromDisp"); + break; + case 127: + sprintf(name, "VarFormatCurrency"); + break; + case 128: + sprintf(name, "VarWeekdayName"); + break; + case 129: + sprintf(name, "VarMonthName"); + break; + case 130: + sprintf(name, "VarUI1FromI2"); + break; + case 131: + sprintf(name, "VarUI1FromI4"); + break; + case 132: + sprintf(name, "VarUI1FromR4"); + break; + case 133: + sprintf(name, "VarUI1FromR8"); + break; + case 134: + sprintf(name, "VarUI1FromCy"); + break; + case 135: + sprintf(name, "VarUI1FromDate"); + break; + case 136: + sprintf(name, "VarUI1FromStr"); + break; + case 137: + sprintf(name, "VarUI1FromDisp"); + break; + case 138: + sprintf(name, "VarUI1FromBool"); + break; + case 139: + sprintf(name, "VarFormatFromTokens"); + break; + case 140: + sprintf(name, "VarTokenizeFormatString"); + break; + case 141: + sprintf(name, "VarAdd"); + break; + case 142: + sprintf(name, "VarAnd"); + break; + case 143: + sprintf(name, "VarDiv"); + break; + case 144: + sprintf(name, "DllCanUnloadNow"); + break; + case 145: + sprintf(name, "DllGetClassObject"); + break; + case 146: + sprintf(name, "DispCallFunc"); + break; + case 147: + sprintf(name, "VariantChangeTypeEx"); + break; + case 148: + sprintf(name, "SafeArrayPtrOfIndex"); + break; + case 149: + sprintf(name, "SysStringByteLen"); + break; + case 150: + sprintf(name, "SysAllocStringByteLen"); + break; + case 151: + sprintf(name, "DllRegisterServer"); + break; + case 152: + sprintf(name, "VarEqv"); + break; + case 153: + sprintf(name, "VarIdiv"); + break; + case 154: + sprintf(name, "VarImp"); + break; + case 155: + sprintf(name, "VarMod"); + break; + case 156: + sprintf(name, "VarMul"); + break; + case 157: + sprintf(name, "VarOr"); + break; + case 158: + sprintf(name, "VarPow"); + break; + case 159: + sprintf(name, "VarSub"); + break; + case 160: + sprintf(name, "CreateTypeLib"); + break; + case 161: + sprintf(name, "LoadTypeLib"); + break; + case 162: + sprintf(name, "LoadRegTypeLib"); + break; + case 163: + sprintf(name, "RegisterTypeLib"); + break; + case 164: + sprintf(name, "QueryPathOfRegTypeLib"); + break; + case 165: + sprintf(name, "LHashValOfNameSys"); + break; + case 166: + sprintf(name, "LHashValOfNameSysA"); + break; + case 167: + sprintf(name, "VarXor"); + break; + case 168: + sprintf(name, "VarAbs"); + break; + case 169: + sprintf(name, "VarFix"); + break; + case 170: + sprintf(name, "OaBuildVersion"); + break; + case 171: + sprintf(name, "ClearCustData"); + break; + case 172: + sprintf(name, "VarInt"); + break; + case 173: + sprintf(name, "VarNeg"); + break; + case 174: + sprintf(name, "VarNot"); + break; + case 175: + sprintf(name, "VarRound"); + break; + case 176: + sprintf(name, "VarCmp"); + break; + case 177: + sprintf(name, "VarDecAdd"); + break; + case 178: + sprintf(name, "VarDecDiv"); + break; + case 179: + sprintf(name, "VarDecMul"); + break; + case 180: + sprintf(name, "CreateTypeLib2"); + break; + case 181: + sprintf(name, "VarDecSub"); + break; + case 182: + sprintf(name, "VarDecAbs"); + break; + case 183: + sprintf(name, "LoadTypeLibEx"); + break; + case 184: + sprintf(name, "SystemTimeToVariantTime"); + break; + case 185: + sprintf(name, "VariantTimeToSystemTime"); + break; + case 186: + sprintf(name, "UnRegisterTypeLib"); + break; + case 187: + sprintf(name, "VarDecFix"); + break; + case 188: + sprintf(name, "VarDecInt"); + break; + case 189: + sprintf(name, "VarDecNeg"); + break; + case 190: + sprintf(name, "VarDecFromUI1"); + break; + case 191: + sprintf(name, "VarDecFromI2"); + break; + case 192: + sprintf(name, "VarDecFromI4"); + break; + case 193: + sprintf(name, "VarDecFromR4"); + break; + case 194: + sprintf(name, "VarDecFromR8"); + break; + case 195: + sprintf(name, "VarDecFromDate"); + break; + case 196: + sprintf(name, "VarDecFromCy"); + break; + case 197: + sprintf(name, "VarDecFromStr"); + break; + case 198: + sprintf(name, "VarDecFromDisp"); + break; + case 199: + sprintf(name, "VarDecFromBool"); + break; + case 200: + sprintf(name, "GetErrorInfo"); + break; + case 201: + sprintf(name, "SetErrorInfo"); + break; + case 202: + sprintf(name, "CreateErrorInfo"); + break; + case 203: + sprintf(name, "VarDecRound"); + break; + case 204: + sprintf(name, "VarDecCmp"); + break; + case 205: + sprintf(name, "VarI2FromI1"); + break; + case 206: + sprintf(name, "VarI2FromUI2"); + break; + case 207: + sprintf(name, "VarI2FromUI4"); + break; + case 208: + sprintf(name, "VarI2FromDec"); + break; + case 209: + sprintf(name, "VarI4FromI1"); + break; + case 210: + sprintf(name, "VarI4FromUI2"); + break; + case 211: + sprintf(name, "VarI4FromUI4"); + break; + case 212: + sprintf(name, "VarI4FromDec"); + break; + case 213: + sprintf(name, "VarR4FromI1"); + break; + case 214: + sprintf(name, "VarR4FromUI2"); + break; + case 215: + sprintf(name, "VarR4FromUI4"); + break; + case 216: + sprintf(name, "VarR4FromDec"); + break; + case 217: + sprintf(name, "VarR8FromI1"); + break; + case 218: + sprintf(name, "VarR8FromUI2"); + break; + case 219: + sprintf(name, "VarR8FromUI4"); + break; + case 220: + sprintf(name, "VarR8FromDec"); + break; + case 221: + sprintf(name, "VarDateFromI1"); + break; + case 222: + sprintf(name, "VarDateFromUI2"); + break; + case 223: + sprintf(name, "VarDateFromUI4"); + break; + case 224: + sprintf(name, "VarDateFromDec"); + break; + case 225: + sprintf(name, "VarCyFromI1"); + break; + case 226: + sprintf(name, "VarCyFromUI2"); + break; + case 227: + sprintf(name, "VarCyFromUI4"); + break; + case 228: + sprintf(name, "VarCyFromDec"); + break; + case 229: + sprintf(name, "VarBstrFromI1"); + break; + case 230: + sprintf(name, "VarBstrFromUI2"); + break; + case 231: + sprintf(name, "VarBstrFromUI4"); + break; + case 232: + sprintf(name, "VarBstrFromDec"); + break; + case 233: + sprintf(name, "VarBoolFromI1"); + break; + case 234: + sprintf(name, "VarBoolFromUI2"); + break; + case 235: + sprintf(name, "VarBoolFromUI4"); + break; + case 236: + sprintf(name, "VarBoolFromDec"); + break; + case 237: + sprintf(name, "VarUI1FromI1"); + break; + case 238: + sprintf(name, "VarUI1FromUI2"); + break; + case 239: + sprintf(name, "VarUI1FromUI4"); + break; + case 240: + sprintf(name, "VarUI1FromDec"); + break; + case 241: + sprintf(name, "VarDecFromI1"); + break; + case 242: + sprintf(name, "VarDecFromUI2"); + break; + case 243: + sprintf(name, "VarDecFromUI4"); + break; + case 244: + sprintf(name, "VarI1FromUI1"); + break; + case 245: + sprintf(name, "VarI1FromI2"); + break; + case 246: + sprintf(name, "VarI1FromI4"); + break; + case 247: + sprintf(name, "VarI1FromR4"); + break; + case 248: + sprintf(name, "VarI1FromR8"); + break; + case 249: + sprintf(name, "VarI1FromDate"); + break; + case 250: + sprintf(name, "VarI1FromCy"); + break; + case 251: + sprintf(name, "VarI1FromStr"); + break; + case 252: + sprintf(name, "VarI1FromDisp"); + break; + case 253: + sprintf(name, "VarI1FromBool"); + break; + case 254: + sprintf(name, "VarI1FromUI2"); + break; + case 255: + sprintf(name, "VarI1FromUI4"); + break; + case 256: + sprintf(name, "VarI1FromDec"); + break; + case 257: + sprintf(name, "VarUI2FromUI1"); + break; + case 258: + sprintf(name, "VarUI2FromI2"); + break; + case 259: + sprintf(name, "VarUI2FromI4"); + break; + case 260: + sprintf(name, "VarUI2FromR4"); + break; + case 261: + sprintf(name, "VarUI2FromR8"); + break; + case 262: + sprintf(name, "VarUI2FromDate"); + break; + case 263: + sprintf(name, "VarUI2FromCy"); + break; + case 264: + sprintf(name, "VarUI2FromStr"); + break; + case 265: + sprintf(name, "VarUI2FromDisp"); + break; + case 266: + sprintf(name, "VarUI2FromBool"); + break; + case 267: + sprintf(name, "VarUI2FromI1"); + break; + case 268: + sprintf(name, "VarUI2FromUI4"); + break; + case 269: + sprintf(name, "VarUI2FromDec"); + break; + case 270: + sprintf(name, "VarUI4FromUI1"); + break; + case 271: + sprintf(name, "VarUI4FromI2"); + break; + case 272: + sprintf(name, "VarUI4FromI4"); + break; + case 273: + sprintf(name, "VarUI4FromR4"); + break; + case 274: + sprintf(name, "VarUI4FromR8"); + break; + case 275: + sprintf(name, "VarUI4FromDate"); + break; + case 276: + sprintf(name, "VarUI4FromCy"); + break; + case 277: + sprintf(name, "VarUI4FromStr"); + break; + case 278: + sprintf(name, "VarUI4FromDisp"); + break; + case 279: + sprintf(name, "VarUI4FromBool"); + break; + case 280: + sprintf(name, "VarUI4FromI1"); + break; + case 281: + sprintf(name, "VarUI4FromUI2"); + break; + case 282: + sprintf(name, "VarUI4FromDec"); + break; + case 283: + sprintf(name, "BSTR_UserSize"); + break; + case 284: + sprintf(name, "BSTR_UserMarshal"); + break; + case 285: + sprintf(name, "BSTR_UserUnmarshal"); + break; + case 286: + sprintf(name, "BSTR_UserFree"); + break; + case 287: + sprintf(name, "VARIANT_UserSize"); + break; + case 288: + sprintf(name, "VARIANT_UserMarshal"); + break; + case 289: + sprintf(name, "VARIANT_UserUnmarshal"); + break; + case 290: + sprintf(name, "VARIANT_UserFree"); + break; + case 291: + sprintf(name, "LPSAFEARRAY_UserSize"); + break; + case 292: + sprintf(name, "LPSAFEARRAY_UserMarshal"); + break; + case 293: + sprintf(name, "LPSAFEARRAY_UserUnmarshal"); + break; + case 294: + sprintf(name, "LPSAFEARRAY_UserFree"); + break; + case 295: + sprintf(name, "LPSAFEARRAY_Size"); + break; + case 296: + sprintf(name, "LPSAFEARRAY_Marshal"); + break; + case 297: + sprintf(name, "LPSAFEARRAY_Unmarshal"); + break; + case 298: + sprintf(name, "VarDecCmpR8"); + break; + case 299: + sprintf(name, "VarCyAdd"); + break; + case 300: + sprintf(name, "DllUnregisterServer"); + break; + case 301: + sprintf(name, "OACreateTypeLib2"); + break; + case 303: + sprintf(name, "VarCyMul"); + break; + case 304: + sprintf(name, "VarCyMulI4"); + break; + case 305: + sprintf(name, "VarCySub"); + break; + case 306: + sprintf(name, "VarCyAbs"); + break; + case 307: + sprintf(name, "VarCyFix"); + break; + case 308: + sprintf(name, "VarCyInt"); + break; + case 309: + sprintf(name, "VarCyNeg"); + break; + case 310: + sprintf(name, "VarCyRound"); + break; + case 311: + sprintf(name, "VarCyCmp"); + break; + case 312: + sprintf(name, "VarCyCmpR8"); + break; + case 313: + sprintf(name, "VarBstrCat"); + break; + case 314: + sprintf(name, "VarBstrCmp"); + break; + case 315: + sprintf(name, "VarR8Pow"); + break; + case 316: + sprintf(name, "VarR4CmpR8"); + break; + case 317: + sprintf(name, "VarR8Round"); + break; + case 318: + sprintf(name, "VarCat"); + break; + case 319: + sprintf(name, "VarDateFromUdateEx"); + break; + case 322: + sprintf(name, "GetRecordInfoFromGuids"); + break; + case 323: + sprintf(name, "GetRecordInfoFromTypeInfo"); + break; + case 325: + sprintf(name, "SetVarConversionLocaleSetting"); + break; + case 326: + sprintf(name, "GetVarConversionLocaleSetting"); + break; + case 327: + sprintf(name, "SetOaNoCache"); + break; + case 329: + sprintf(name, "VarCyMulI8"); + break; + case 330: + sprintf(name, "VarDateFromUdate"); + break; + case 331: + sprintf(name, "VarUdateFromDate"); + break; + case 332: + sprintf(name, "GetAltMonthNames"); + break; + case 333: + sprintf(name, "VarI8FromUI1"); + break; + case 334: + sprintf(name, "VarI8FromI2"); + break; + case 335: + sprintf(name, "VarI8FromR4"); + break; + case 336: + sprintf(name, "VarI8FromR8"); + break; + case 337: + sprintf(name, "VarI8FromCy"); + break; + case 338: + sprintf(name, "VarI8FromDate"); + break; + case 339: + sprintf(name, "VarI8FromStr"); + break; + case 340: + sprintf(name, "VarI8FromDisp"); + break; + case 341: + sprintf(name, "VarI8FromBool"); + break; + case 342: + sprintf(name, "VarI8FromI1"); + break; + case 343: + sprintf(name, "VarI8FromUI2"); + break; + case 344: + sprintf(name, "VarI8FromUI4"); + break; + case 345: + sprintf(name, "VarI8FromDec"); + break; + case 346: + sprintf(name, "VarI2FromI8"); + break; + case 347: + sprintf(name, "VarI2FromUI8"); + break; + case 348: + sprintf(name, "VarI4FromI8"); + break; + case 349: + sprintf(name, "VarI4FromUI8"); + break; + case 360: + sprintf(name, "VarR4FromI8"); + break; + case 361: + sprintf(name, "VarR4FromUI8"); + break; + case 362: + sprintf(name, "VarR8FromI8"); + break; + case 363: + sprintf(name, "VarR8FromUI8"); + break; + case 364: + sprintf(name, "VarDateFromI8"); + break; + case 365: + sprintf(name, "VarDateFromUI8"); + break; + case 366: + sprintf(name, "VarCyFromI8"); + break; + case 367: + sprintf(name, "VarCyFromUI8"); + break; + case 368: + sprintf(name, "VarBstrFromI8"); + break; + case 369: + sprintf(name, "VarBstrFromUI8"); + break; + case 370: + sprintf(name, "VarBoolFromI8"); + break; + case 371: + sprintf(name, "VarBoolFromUI8"); + break; + case 372: + sprintf(name, "VarUI1FromI8"); + break; + case 373: + sprintf(name, "VarUI1FromUI8"); + break; + case 374: + sprintf(name, "VarDecFromI8"); + break; + case 375: + sprintf(name, "VarDecFromUI8"); + break; + case 376: + sprintf(name, "VarI1FromI8"); + break; + case 377: + sprintf(name, "VarI1FromUI8"); + break; + case 378: + sprintf(name, "VarUI2FromI8"); + break; + case 379: + sprintf(name, "VarUI2FromUI8"); + break; + case 401: + sprintf(name, "OleLoadPictureEx"); + break; + case 402: + sprintf(name, "OleLoadPictureFileEx"); + break; + case 411: + sprintf(name, "SafeArrayCreateVector"); + break; + case 412: + sprintf(name, "SafeArrayCopyData"); + break; + case 413: + sprintf(name, "VectorFromBstr"); + break; + case 414: + sprintf(name, "BstrFromVector"); + break; + case 415: + sprintf(name, "OleIconToCursor"); + break; + case 416: + sprintf(name, "OleCreatePropertyFrameIndirect"); + break; + case 417: + sprintf(name, "OleCreatePropertyFrame"); + break; + case 418: + sprintf(name, "OleLoadPicture"); + break; + case 419: + sprintf(name, "OleCreatePictureIndirect"); + break; + case 420: + sprintf(name, "OleCreateFontIndirect"); + break; + case 421: + sprintf(name, "OleTranslateColor"); + break; + case 422: + sprintf(name, "OleLoadPictureFile"); + break; + case 423: + sprintf(name, "OleSavePictureFile"); + break; + case 424: + sprintf(name, "OleLoadPicturePath"); + break; + case 425: + sprintf(name, "VarUI4FromI8"); + break; + case 426: + sprintf(name, "VarUI4FromUI8"); + break; + case 427: + sprintf(name, "VarI8FromUI8"); + break; + case 428: + sprintf(name, "VarUI8FromI8"); + break; + case 429: + sprintf(name, "VarUI8FromUI1"); + break; + case 430: + sprintf(name, "VarUI8FromI2"); + break; + case 431: + sprintf(name, "VarUI8FromR4"); + break; + case 432: + sprintf(name, "VarUI8FromR8"); + break; + case 433: + sprintf(name, "VarUI8FromCy"); + break; + case 434: + sprintf(name, "VarUI8FromDate"); + break; + case 435: + sprintf(name, "VarUI8FromStr"); + break; + case 436: + sprintf(name, "VarUI8FromDisp"); + break; + case 437: + sprintf(name, "VarUI8FromBool"); + break; + case 438: + sprintf(name, "VarUI8FromI1"); + break; + case 439: + sprintf(name, "VarUI8FromUI2"); + break; + case 440: + sprintf(name, "VarUI8FromUI4"); + break; + case 441: + sprintf(name, "VarUI8FromDec"); + break; + case 442: + sprintf(name, "RegisterTypeLibForUser"); + break; + case 443: + sprintf(name, "UnRegisterTypeLibForUser"); + break; + default: + break; + } + } + + if (name[0] == '\0') + sprintf(name, "ord%u", ord); + + return yr_strdup(name); +} diff --git a/yara-master/libyara/modules/tests.c b/yara-master/libyara/modules/tests.c new file mode 100644 index 0000000..4ef3169 --- /dev/null +++ b/yara-master/libyara/modules/tests.c @@ -0,0 +1,220 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#define MODULE_NAME tests + + +define_function(fsum_2) +{ + double a = float_argument(1); + double b = float_argument(2); + + return_float(a + b); +} + +define_function(fsum_3) +{ + double a = float_argument(1); + double b = float_argument(2); + double c = float_argument(3); + + return_float(a + b + c); +} + +define_function(isum_2) +{ + int64_t a = integer_argument(1); + int64_t b = integer_argument(2); + + return_integer(a + b); +} + + +define_function(isum_3) +{ + int64_t a = integer_argument(1); + int64_t b = integer_argument(2); + int64_t c = integer_argument(3); + + return_integer(a + b + c); +} + + +define_function(length) +{ + char* s = string_argument(1); + + return_integer(strlen(s)); +} + + +define_function(empty) +{ + return_string(""); +} + + +define_function(match) +{ + return_integer( + yr_re_match( + scan_context(), + regexp_argument(1), + string_argument(2))); +} + + +define_function(foobar) +{ + int64_t arg = integer_argument(1); + + switch (arg) + { + case 1: + return_string("foo"); + break; + case 2: + return_string("bar"); + break; + } + + return_string("oops") +} + +begin_declarations; + + begin_struct("constants"); + declare_integer("one"); + declare_integer("two"); + declare_string("foo"); + declare_string("empty"); + end_struct("constants"); + + begin_struct("undefined"); + declare_integer("i"); + declare_float("f"); + end_struct("undefined"); + + declare_string("module_data") + + declare_integer_array("integer_array"); + declare_string_array("string_array"); + + declare_integer_dictionary("integer_dict"); + declare_string_dictionary("string_dict"); + + begin_struct_array("struct_array"); + declare_integer("i"); + declare_string("s"); + end_struct_array("struct_array"); + + begin_struct_dictionary("struct_dict"); + declare_integer("i"); + declare_string("s"); + end_struct_dictionary("struct_dict"); + + declare_function("match", "rs", "i", match); + declare_function("isum", "ii", "i", isum_2); + declare_function("isum", "iii", "i", isum_3); + declare_function("fsum", "ff", "f", fsum_2); + declare_function("fsum", "fff", "f", fsum_3); + declare_function("length", "s", "i", length); + declare_function("empty", "", "s", empty); + declare_function("foobar", "i", "s", foobar); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + set_integer(1, module_object, "constants.one"); + set_integer(2, module_object, "constants.two"); + set_string("foo", module_object, "constants.foo"); + set_string("", module_object, "constants.empty"); + + set_integer(1, module_object, "struct_array[1].i"); + + set_integer(0, module_object, "integer_array[%i]", 0); + set_integer(1, module_object, "integer_array[%i]", 1); + set_integer(2, module_object, "integer_array[%i]", 2); + set_integer(256, module_object, "integer_array[%i]", 256); + + set_string("foo", module_object, "string_array[%i]", 0); + set_string("bar", module_object, "string_array[%i]", 1); + set_string("baz", module_object, "string_array[%i]", 2); + + set_sized_string("foo\0bar", 7, module_object, "string_array[%i]", 3); + + set_string("foo", module_object, "string_dict[%s]", "foo"); + set_string("bar", module_object, "string_dict[\"bar\"]"); + + set_string("foo", module_object, "struct_dict[%s].s", "foo"); + set_integer(1, module_object, "struct_dict[%s].i", "foo"); + + if (module_data_size > 0 && module_data != NULL) { + set_sized_string( + (const char*) module_data, + module_data_size, + module_object, + "module_data"); + } + + return ERROR_SUCCESS; +} + + +int module_unload( + YR_OBJECT* module_object) +{ + // Fail if module_unload is called twice with the same module_object + if (module_object->data == (void*) 0xFABADA) + assert(FALSE); + + module_object->data = (void*) 0xFABADA; + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/modules/time.c b/yara-master/libyara/modules/time.c new file mode 100644 index 0000000..f1a1f6a --- /dev/null +++ b/yara-master/libyara/modules/time.c @@ -0,0 +1,80 @@ +/* +Copyright (c) 2014-2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#define MODULE_NAME time + + +define_function(now) +{ + time_t now = time(NULL); + if (now == -1) + return_integer(UNDEFINED); + return_integer((long) now); +} + + +begin_declarations; + + declare_function("now", "", "i", now); + +end_declarations; + + +int module_initialize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_finalize( + YR_MODULE* module) +{ + return ERROR_SUCCESS; +} + + +int module_load( + YR_SCAN_CONTEXT* context, + YR_OBJECT* module_object, + void* module_data, + size_t module_data_size) +{ + return ERROR_SUCCESS; +} + + +int module_unload( + YR_OBJECT* module_object) +{ + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/object.c b/yara-master/libyara/object.c new file mode 100644 index 0000000..027ea84 --- /dev/null +++ b/yara-master/libyara/object.c @@ -0,0 +1,1216 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + + +int yr_object_create( + int8_t type, + const char* identifier, + YR_OBJECT* parent, + YR_OBJECT** object) +{ + YR_OBJECT* obj; + int i; + size_t object_size = 0; + + assert(parent != NULL || object != NULL); + + switch (type) + { + case OBJECT_TYPE_STRUCTURE: + object_size = sizeof(YR_OBJECT_STRUCTURE); + break; + case OBJECT_TYPE_ARRAY: + object_size = sizeof(YR_OBJECT_ARRAY); + break; + case OBJECT_TYPE_DICTIONARY: + object_size = sizeof(YR_OBJECT_DICTIONARY); + break; + case OBJECT_TYPE_INTEGER: + object_size = sizeof(YR_OBJECT); + break; + case OBJECT_TYPE_FLOAT: + object_size = sizeof(YR_OBJECT); + break; + case OBJECT_TYPE_STRING: + object_size = sizeof(YR_OBJECT); + break; + case OBJECT_TYPE_FUNCTION: + object_size = sizeof(YR_OBJECT_FUNCTION); + break; + default: + assert(FALSE); + } + + obj = (YR_OBJECT*) yr_malloc(object_size); + + if (obj == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + obj->type = type; + obj->identifier = yr_strdup(identifier); + obj->parent = parent; + obj->data = NULL; + + switch(type) + { + case OBJECT_TYPE_INTEGER: + obj->value.i = UNDEFINED; + break; + case OBJECT_TYPE_FLOAT: + obj->value.d = NAN; + break; + case OBJECT_TYPE_STRING: + obj->value.ss = NULL; + break; + case OBJECT_TYPE_STRUCTURE: + object_as_structure(obj)->members = NULL; + break; + case OBJECT_TYPE_ARRAY: + object_as_array(obj)->items = NULL; + object_as_array(obj)->prototype_item = NULL; + break; + case OBJECT_TYPE_DICTIONARY: + object_as_dictionary(obj)->items = NULL; + object_as_dictionary(obj)->prototype_item = NULL; + break; + case OBJECT_TYPE_FUNCTION: + object_as_function(obj)->return_obj = NULL; + for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++) + { + object_as_function(obj)->prototypes[i].arguments_fmt = NULL; + object_as_function(obj)->prototypes[i].code = NULL; + } + break; + } + + if (obj->identifier == NULL) + { + yr_free(obj); + return ERROR_INSUFFICIENT_MEMORY; + } + + if (parent != NULL) + { + assert(parent->type == OBJECT_TYPE_STRUCTURE || + parent->type == OBJECT_TYPE_ARRAY || + parent->type == OBJECT_TYPE_DICTIONARY || + parent->type == OBJECT_TYPE_FUNCTION); + + switch(parent->type) + { + case OBJECT_TYPE_STRUCTURE: + FAIL_ON_ERROR_WITH_CLEANUP( + yr_object_structure_set_member(parent, obj), + { + yr_free((void*) obj->identifier); + yr_free(obj); + }); + break; + + case OBJECT_TYPE_ARRAY: + object_as_array(parent)->prototype_item = obj; + break; + + case OBJECT_TYPE_DICTIONARY: + object_as_dictionary(parent)->prototype_item = obj; + break; + + case OBJECT_TYPE_FUNCTION: + object_as_function(parent)->return_obj = obj; + break; + } + } + + if (object != NULL) + *object = obj; + + return ERROR_SUCCESS; +} + + +int yr_object_function_create( + const char* identifier, + const char* arguments_fmt, + const char* return_fmt, + YR_MODULE_FUNC code, + YR_OBJECT* parent, + YR_OBJECT** function) +{ + YR_OBJECT* return_obj; + YR_OBJECT* o = NULL; + YR_OBJECT_FUNCTION* f = NULL; + + int8_t return_type; + int i; + + switch (*return_fmt) + { + case 'i': + return_type = OBJECT_TYPE_INTEGER; + break; + case 's': + return_type = OBJECT_TYPE_STRING; + break; + case 'f': + return_type = OBJECT_TYPE_FLOAT; + break; + default: + return ERROR_INVALID_FORMAT; + } + + if (parent != NULL) + { + // The parent of a function must be a structure. + + assert(parent->type == OBJECT_TYPE_STRUCTURE); + + // Try to find if the structure already has a function + // with that name. In that case this is a function overload. + + f = object_as_function(yr_object_lookup_field(parent, identifier)); + + // Overloaded functions must have the same return type. + + if (f != NULL && return_type != f->return_obj->type) + return ERROR_WRONG_RETURN_TYPE; + } + + if (f == NULL) // Function doesn't exist yet + { + FAIL_ON_ERROR( + yr_object_create( + OBJECT_TYPE_FUNCTION, + identifier, + parent, + &o)); + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_object_create( + return_type, + "result", + o, + &return_obj), + yr_object_destroy(o)); + + f = object_as_function(o); + } + + for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++) + { + if (f->prototypes[i].arguments_fmt == NULL) + { + f->prototypes[i].arguments_fmt = arguments_fmt; + f->prototypes[i].code = code; + + break; + } + } + + if (function != NULL) + *function = (YR_OBJECT*) f; + + return ERROR_SUCCESS; +} + + +int yr_object_from_external_variable( + YR_EXTERNAL_VARIABLE* external, + YR_OBJECT** object) +{ + YR_OBJECT* obj; + int result; + uint8_t obj_type = 0; + + switch(external->type) + { + case EXTERNAL_VARIABLE_TYPE_INTEGER: + case EXTERNAL_VARIABLE_TYPE_BOOLEAN: + obj_type = OBJECT_TYPE_INTEGER; + break; + + case EXTERNAL_VARIABLE_TYPE_FLOAT: + obj_type = OBJECT_TYPE_FLOAT; + break; + + case EXTERNAL_VARIABLE_TYPE_STRING: + case EXTERNAL_VARIABLE_TYPE_MALLOC_STRING: + obj_type = OBJECT_TYPE_STRING; + break; + + default: + assert(FALSE); + } + + result = yr_object_create( + obj_type, + external->identifier, + NULL, + &obj); + + if (result == ERROR_SUCCESS) + { + switch(external->type) + { + case EXTERNAL_VARIABLE_TYPE_INTEGER: + case EXTERNAL_VARIABLE_TYPE_BOOLEAN: + result = yr_object_set_integer(external->value.i, obj, NULL); + break; + + case EXTERNAL_VARIABLE_TYPE_FLOAT: + result = yr_object_set_float(external->value.f, obj, NULL); + break; + + case EXTERNAL_VARIABLE_TYPE_STRING: + case EXTERNAL_VARIABLE_TYPE_MALLOC_STRING: + result = yr_object_set_string( + external->value.s, strlen(external->value.s), obj, NULL); + break; + } + + *object = obj; + } + + return result; +} + + +void yr_object_destroy( + YR_OBJECT* object) +{ + YR_STRUCTURE_MEMBER* member; + YR_STRUCTURE_MEMBER* next_member; + YR_ARRAY_ITEMS* array_items; + YR_DICTIONARY_ITEMS* dict_items; + + int i; + + if (object == NULL) + return; + + switch(object->type) + { + case OBJECT_TYPE_STRUCTURE: + member = object_as_structure(object)->members; + + while (member != NULL) + { + next_member = member->next; + yr_object_destroy(member->object); + yr_free(member); + member = next_member; + } + break; + + case OBJECT_TYPE_STRING: + if (object->value.ss != NULL) + yr_free(object->value.ss); + break; + + case OBJECT_TYPE_ARRAY: + if (object_as_array(object)->prototype_item != NULL) + yr_object_destroy(object_as_array(object)->prototype_item); + + array_items = object_as_array(object)->items; + + if (array_items != NULL) + { + for (i = 0; i < array_items->count; i++) + if (array_items->objects[i] != NULL) + yr_object_destroy(array_items->objects[i]); + } + + yr_free(array_items); + break; + + case OBJECT_TYPE_DICTIONARY: + if (object_as_dictionary(object)->prototype_item != NULL) + yr_object_destroy(object_as_dictionary(object)->prototype_item); + + dict_items = object_as_dictionary(object)->items; + + if (dict_items != NULL) + { + for (i = 0; i < dict_items->used; i++) + { + if (dict_items->objects[i].key != NULL) + yr_free(dict_items->objects[i].key); + + if (dict_items->objects[i].obj != NULL) + yr_object_destroy(dict_items->objects[i].obj); + } + } + + yr_free(dict_items); + break; + + case OBJECT_TYPE_FUNCTION: + yr_object_destroy(object_as_function(object)->return_obj); + break; + } + + yr_free((void*) object->identifier); + yr_free(object); +} + + +YR_OBJECT* yr_object_lookup_field( + YR_OBJECT* object, + const char* field_name) +{ + YR_STRUCTURE_MEMBER* member; + + assert(object != NULL); + assert(object->type == OBJECT_TYPE_STRUCTURE); + + member = object_as_structure(object)->members; + + while (member != NULL) + { + if (strcmp(member->object->identifier, field_name) == 0) + return member->object; + + member = member->next; + } + + return NULL; +} + + +static YR_OBJECT* _yr_object_lookup( + YR_OBJECT* object, + int flags, + const char* pattern, + va_list args) +{ + YR_OBJECT* obj = object; + + const char* p = pattern; + const char* key = NULL; + + char str[256]; + + int i; + int index = -1; + + while (obj != NULL) + { + i = 0; + + while (*p != '\0' && *p != '.' && *p != '[' && i < sizeof(str) - 1) + { + str[i++] = *p++; + } + + str[i] = '\0'; + + if (obj->type != OBJECT_TYPE_STRUCTURE) + return NULL; + + obj = yr_object_lookup_field(obj, str); + + if (obj == NULL) + return NULL; + + if (*p == '[') + { + p++; + + if (*p == '%') + { + p++; + + switch(*p++) + { + case 'i': + index = va_arg(args, int); + break; + case 's': + key = va_arg(args, const char*); + break; + + default: + return NULL; + } + } + else if (*p >= '0' && *p <= '9') + { + index = (int) strtol(p, (char**) &p, 10); + } + else if (*p == '"') + { + i = 0; + p++; // skip the opening quotation mark + + while (*p != '"' && *p != '\0' && i < sizeof(str) - 1) + str[i++] = *p++; + + str[i] = '\0'; + p++; // skip the closing quotation mark + key = str; + } + else + { + return NULL; + } + + assert(*p == ']'); + p++; + assert(*p == '.' || *p == '\0'); + + switch(obj->type) + { + case OBJECT_TYPE_ARRAY: + assert(index != -1); + obj = yr_object_array_get_item(obj, flags, index); + break; + + case OBJECT_TYPE_DICTIONARY: + assert(key != NULL); + obj = yr_object_dict_get_item(obj, flags, key); + break; + } + } + + if (*p == '\0') + break; + + p++; + } + + return obj; +} + + +YR_OBJECT* yr_object_lookup( + YR_OBJECT* object, + int flags, + const char* pattern, + ...) +{ + YR_OBJECT* result; + + va_list args; + va_start(args, pattern); + + result = _yr_object_lookup(object, flags, pattern, args); + + va_end(args); + + return result; + +} + + +int yr_object_copy( + YR_OBJECT* object, + YR_OBJECT** object_copy) +{ + YR_OBJECT* copy; + YR_OBJECT* o; + + YR_STRUCTURE_MEMBER* structure_member; + + int i; + + *object_copy = NULL; + + FAIL_ON_ERROR(yr_object_create( + object->type, + object->identifier, + NULL, + ©)); + + switch(object->type) + { + case OBJECT_TYPE_INTEGER: + copy->value.i = object->value.i; + break; + + case OBJECT_TYPE_FLOAT: + copy->value.d = object->value.d; + break; + + case OBJECT_TYPE_STRING: + + if (object->value.ss != NULL) + copy->value.ss = sized_string_dup(object->value.ss); + else + copy->value.ss = NULL; + + break; + + case OBJECT_TYPE_FUNCTION: + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_object_copy( + object_as_function(object)->return_obj, + &object_as_function(copy)->return_obj), + yr_object_destroy(copy)); + + for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++) + object_as_function(copy)->prototypes[i] = \ + object_as_function(object)->prototypes[i]; + + break; + + case OBJECT_TYPE_STRUCTURE: + + structure_member = object_as_structure(object)->members; + + while (structure_member != NULL) + { + FAIL_ON_ERROR_WITH_CLEANUP( + yr_object_copy(structure_member->object, &o), + yr_object_destroy(copy)); + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_object_structure_set_member(copy, o), + yr_free(o); + yr_object_destroy(copy)); + + structure_member = structure_member->next; + } + + break; + + case OBJECT_TYPE_ARRAY: + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_object_copy(object_as_array(object)->prototype_item, &o), + yr_object_destroy(copy)); + + object_as_array(copy)->prototype_item = o; + + break; + + case OBJECT_TYPE_DICTIONARY: + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_object_copy(object_as_dictionary(object)->prototype_item, &o), + yr_object_destroy(copy)); + + object_as_dictionary(copy)->prototype_item = o; + + break; + + default: + assert(FALSE); + + } + + *object_copy = copy; + + return ERROR_SUCCESS; +} + + +int yr_object_structure_set_member( + YR_OBJECT* object, + YR_OBJECT* member) +{ + YR_STRUCTURE_MEMBER* sm; + + assert(object->type == OBJECT_TYPE_STRUCTURE); + + // Check if the object already have a member with the same identifier + + if (yr_object_lookup_field(object, member->identifier) != NULL) + return ERROR_DUPLICATED_STRUCTURE_MEMBER; + + sm = (YR_STRUCTURE_MEMBER*) yr_malloc(sizeof(YR_STRUCTURE_MEMBER)); + + if (sm == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + member->parent = object; + sm->object = member; + sm->next = object_as_structure(object)->members; + + object_as_structure(object)->members = sm; + + return ERROR_SUCCESS; +} + + +YR_OBJECT* yr_object_array_get_item( + YR_OBJECT* object, + int flags, + int index) +{ + YR_OBJECT* result = NULL; + YR_OBJECT_ARRAY* array; + + assert(object->type == OBJECT_TYPE_ARRAY); + + if (index < 0) + return NULL; + + array = object_as_array(object); + + if (array->items != NULL && array->items->count > index) + result = array->items->objects[index]; + + if (result == NULL && flags & OBJECT_CREATE) + { + yr_object_copy(array->prototype_item, &result); + + if (result != NULL) + yr_object_array_set_item(object, result, index); + } + + return result; +} + + +int yr_object_array_set_item( + YR_OBJECT* object, + YR_OBJECT* item, + int index) +{ + YR_OBJECT_ARRAY* array; + + int i; + int count; + + assert(index >= 0); + assert(object->type == OBJECT_TYPE_ARRAY); + + array = object_as_array(object); + + if (array->items == NULL) + { + count = 64; + + while (count <= index) + count *= 2; + + array->items = (YR_ARRAY_ITEMS*) yr_malloc( + sizeof(YR_ARRAY_ITEMS) + count * sizeof(YR_OBJECT*)); + + if (array->items == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + memset(array->items->objects, 0, count * sizeof(YR_OBJECT*)); + + array->items->count = count; + } + else if (index >= array->items->count) + { + count = array->items->count * 2; + + while (count <= index) + count *= 2; + + array->items = (YR_ARRAY_ITEMS*) yr_realloc( + array->items, + sizeof(YR_ARRAY_ITEMS) + count * sizeof(YR_OBJECT*)); + + if (array->items == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + for (i = array->items->count; i < count; i++) + array->items->objects[i] = NULL; + + array->items->count = count; + } + + item->parent = object; + array->items->objects[index] = item; + + return ERROR_SUCCESS; +} + + +YR_OBJECT* yr_object_dict_get_item( + YR_OBJECT* object, + int flags, + const char* key) +{ + int i; + + YR_OBJECT* result = NULL; + YR_OBJECT_DICTIONARY* dict; + + assert(object->type == OBJECT_TYPE_DICTIONARY); + + dict = object_as_dictionary(object); + + if (dict->items != NULL) + { + for (i = 0; i < dict->items->used; i++) + { + if (strcmp(dict->items->objects[i].key, key) == 0) + result = dict->items->objects[i].obj; + } + } + + if (result == NULL && flags & OBJECT_CREATE) + { + yr_object_copy(dict->prototype_item, &result); + + if (result != NULL) + yr_object_dict_set_item(object, result, key); + } + + return result; +} + + +int yr_object_dict_set_item( + YR_OBJECT* object, + YR_OBJECT* item, + const char* key) +{ + YR_OBJECT_DICTIONARY* dict; + + int i; + int count; + + assert(object->type == OBJECT_TYPE_DICTIONARY); + + dict = object_as_dictionary(object); + + if (dict->items == NULL) + { + count = 64; + + dict->items = (YR_DICTIONARY_ITEMS*) yr_malloc( + sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0])); + + if (dict->items == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + memset(dict->items->objects, 0, count * sizeof(dict->items->objects[0])); + + dict->items->free = count; + dict->items->used = 0; + } + else if (dict->items->free == 0) + { + count = dict->items->used * 2; + dict->items = (YR_DICTIONARY_ITEMS*) yr_realloc( + dict->items, + sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0])); + + if (dict->items == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + for (i = dict->items->used; i < count; i++) + { + dict->items->objects[i].key = NULL; + dict->items->objects[i].obj = NULL; + } + + dict->items->free = dict->items->used; + } + + item->parent = object; + + dict->items->objects[dict->items->used].key = yr_strdup(key); + dict->items->objects[dict->items->used].obj = item; + + dict->items->used++; + dict->items->free--; + + return ERROR_SUCCESS; +} + + +int yr_object_has_undefined_value( + YR_OBJECT* object, + const char* field, + ...) +{ + YR_OBJECT* field_obj; + + va_list args; + va_start(args, field); + + if (field != NULL) + field_obj = _yr_object_lookup(object, 0, field, args); + else + field_obj = object; + + va_end(args); + + if (field_obj == NULL) + return TRUE; + + switch(field_obj->type) + { + case OBJECT_TYPE_FLOAT: + return isnan(field_obj->value.d); + case OBJECT_TYPE_STRING: + return field_obj->value.ss == NULL; + case OBJECT_TYPE_INTEGER: + return field_obj->value.i == UNDEFINED; + } + + return FALSE; +} + + +int64_t yr_object_get_integer( + YR_OBJECT* object, + const char* field, + ...) +{ + YR_OBJECT* integer_obj; + + va_list args; + va_start(args, field); + + if (field != NULL) + integer_obj = _yr_object_lookup(object, 0, field, args); + else + integer_obj = object; + + va_end(args); + + if (integer_obj == NULL) + return UNDEFINED; + + assertf(integer_obj->type == OBJECT_TYPE_INTEGER, + "type of \"%s\" is not integer\n", field); + + return integer_obj->value.i; +} + + +double yr_object_get_float( + YR_OBJECT* object, + const char* field, + ...) +{ + YR_OBJECT* double_obj; + + va_list args; + va_start(args, field); + + if (field != NULL) + double_obj = _yr_object_lookup(object, 0, field, args); + else + double_obj = object; + + va_end(args); + + if (double_obj == NULL) + return NAN; + + assertf(double_obj->type == OBJECT_TYPE_FLOAT, + "type of \"%s\" is not double\n", field); + + return double_obj->value.d; +} + + +SIZED_STRING* yr_object_get_string( + YR_OBJECT* object, + const char* field, + ...) +{ + YR_OBJECT* string_obj; + + va_list args; + va_start(args, field); + + if (field != NULL) + string_obj = _yr_object_lookup(object, 0, field, args); + else + string_obj = object; + + va_end(args); + + if (string_obj == NULL) + return NULL; + + assertf(string_obj->type == OBJECT_TYPE_STRING, + "type of \"%s\" is not string\n", field); + + return string_obj->value.ss; +} + + +int yr_object_set_integer( + int64_t value, + YR_OBJECT* object, + const char* field, + ...) +{ + YR_OBJECT* integer_obj; + + va_list args; + va_start(args, field); + + if (field != NULL) + integer_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); + else + integer_obj = object; + + va_end(args); + + if (integer_obj == NULL) + { + if (field != NULL) + return ERROR_INSUFFICIENT_MEMORY; + else + return ERROR_INVALID_ARGUMENT; + } + + assert(integer_obj->type == OBJECT_TYPE_INTEGER); + + integer_obj->value.i = value; + + return ERROR_SUCCESS; +} + + +int yr_object_set_float( + double value, + YR_OBJECT* object, + const char* field, + ...) +{ + YR_OBJECT* double_obj; + + va_list args; + va_start(args, field); + + if (field != NULL) + double_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); + else + double_obj = object; + + va_end(args); + + if (double_obj == NULL) + { + if (field != NULL) + return ERROR_INSUFFICIENT_MEMORY; + else + return ERROR_INVALID_ARGUMENT; + } + + assert(double_obj->type == OBJECT_TYPE_FLOAT); + + double_obj->value.d = value; + + return ERROR_SUCCESS; +} + + +int yr_object_set_string( + const char* value, + size_t len, + YR_OBJECT* object, + const char* field, + ...) +{ + YR_OBJECT* string_obj; + + va_list args; + va_start(args, field); + + if (field != NULL) + string_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); + else + string_obj = object; + + va_end(args); + + if (string_obj == NULL) + { + if (field != NULL) + return ERROR_INSUFFICIENT_MEMORY; + else + return ERROR_INVALID_ARGUMENT; + } + + assert(string_obj->type == OBJECT_TYPE_STRING); + + if (string_obj->value.ss != NULL) + yr_free(string_obj->value.ss); + + if (value != NULL) + { + string_obj->value.ss = (SIZED_STRING*) yr_malloc( + len + sizeof(SIZED_STRING)); + + if (string_obj->value.ss == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + string_obj->value.ss->length = (uint32_t) len; + string_obj->value.ss->flags = 0; + + memcpy(string_obj->value.ss->c_string, value, len); + string_obj->value.ss->c_string[len] = '\0'; + } + else + { + string_obj->value.ss = NULL; + } + + return ERROR_SUCCESS; +} + + +YR_OBJECT* yr_object_get_root( + YR_OBJECT* object) +{ + YR_OBJECT* o = object; + + while (o->parent != NULL) + o = o->parent; + + return o; +} + +YR_API void yr_object_print_data( + YR_OBJECT* object, + int indent, + int print_identifier) +{ + YR_DICTIONARY_ITEMS* dict_items; + YR_ARRAY_ITEMS* array_items; + YR_STRUCTURE_MEMBER* member; + + char indent_spaces[32]; + int i; + + indent = yr_min(indent, sizeof(indent_spaces) - 1); + + memset(indent_spaces, '\t', indent); + indent_spaces[indent] = '\0'; + + if (print_identifier && object->type != OBJECT_TYPE_FUNCTION) + printf("%s%s", indent_spaces, object->identifier); + + switch(object->type) + { + case OBJECT_TYPE_INTEGER: + + if (object->value.i != UNDEFINED) + printf(" = %" PRIu64, object->value.i); + else + printf(" = UNDEFINED"); + + break; + + case OBJECT_TYPE_STRING: + + if (object->value.ss != NULL) + { + size_t l; + printf(" = \""); + + for (l = 0; l < object->value.ss->length; l++) + { + char c = object->value.ss->c_string[l]; + + if (isprint((unsigned char) c)) + printf("%c", c); + else + printf("\\x%02x", (unsigned char) c); + } + + printf("\""); + } + else + { + printf(" = UNDEFINED"); + } + + break; + + case OBJECT_TYPE_STRUCTURE: + + member = object_as_structure(object)->members; + + while (member != NULL) + { + if (member->object->type != OBJECT_TYPE_FUNCTION) + { + printf("\n"); + yr_object_print_data(member->object, indent + 1, 1); + } + member = member->next; + } + + break; + + case OBJECT_TYPE_ARRAY: + + array_items = object_as_array(object)->items; + + if (array_items != NULL) + { + for (i = 0; i < array_items->count; i++) + { + if (array_items->objects[i] != NULL) + { + printf("\n%s\t[%d]", indent_spaces, i); + yr_object_print_data(array_items->objects[i], indent + 1, 0); + } + } + } + + break; + + case OBJECT_TYPE_DICTIONARY: + + dict_items = object_as_dictionary(object)->items; + + if (dict_items != NULL) + { + for (i = 0; i < dict_items->used; i++) + { + printf("\n%s\t%s", indent_spaces, dict_items->objects[i].key); + yr_object_print_data(dict_items->objects[i].obj, indent + 1, 0); + } + } + + break; + } +} diff --git a/yara-master/libyara/parser.c b/yara-master/libyara/parser.c new file mode 100644 index 0000000..bdfa6ad --- /dev/null +++ b/yara-master/libyara/parser.c @@ -0,0 +1,1276 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define todigit(x) ((x) >='A'&& (x) <='F')? \ + ((uint8_t) (x - 'A' + 10)) : \ + ((uint8_t) (x - '0')) + + +int yr_parser_emit( + yyscan_t yyscanner, + uint8_t instruction, + uint8_t** instruction_address) +{ + return yr_arena_write_data( + yyget_extra(yyscanner)->code_arena, + &instruction, + sizeof(int8_t), + (void**) instruction_address); +} + + +int yr_parser_emit_with_arg_double( + yyscan_t yyscanner, + uint8_t instruction, + double argument, + uint8_t** instruction_address, + double** argument_address) +{ + int result = yr_arena_write_data( + yyget_extra(yyscanner)->code_arena, + &instruction, + sizeof(uint8_t), + (void**) instruction_address); + + if (result == ERROR_SUCCESS) + result = yr_arena_write_data( + yyget_extra(yyscanner)->code_arena, + &argument, + sizeof(double), + (void**) argument_address); + + return result; +} + + +int yr_parser_emit_with_arg( + yyscan_t yyscanner, + uint8_t instruction, + int64_t argument, + uint8_t** instruction_address, + int64_t** argument_address) +{ + int result = yr_arena_write_data( + yyget_extra(yyscanner)->code_arena, + &instruction, + sizeof(uint8_t), + (void**) instruction_address); + + if (result == ERROR_SUCCESS) + result = yr_arena_write_data( + yyget_extra(yyscanner)->code_arena, + &argument, + sizeof(int64_t), + (void**) argument_address); + + return result; +} + + +int yr_parser_emit_with_arg_reloc( + yyscan_t yyscanner, + uint8_t instruction, + void* argument, + uint8_t** instruction_address, + void** argument_address) +{ + int64_t* ptr = NULL; + int result; + + DECLARE_REFERENCE(void*, ptr) arg; + + memset(&arg, 0, sizeof(arg)); + arg.ptr = argument; + + result = yr_arena_write_data( + yyget_extra(yyscanner)->code_arena, + &instruction, + sizeof(uint8_t), + (void**) instruction_address); + + if (result == ERROR_SUCCESS) + result = yr_arena_write_data( + yyget_extra(yyscanner)->code_arena, + &arg, + sizeof(arg), + (void**) &ptr); + + if (result == ERROR_SUCCESS) + result = yr_arena_make_ptr_relocatable( + yyget_extra(yyscanner)->code_arena, + ptr, + 0, + EOL); + + if (argument_address != NULL) + *argument_address = (void*) ptr; + + return result; +} + + +int yr_parser_emit_pushes_for_strings( + yyscan_t yyscanner, + const char* identifier) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + YR_STRING* string = compiler->current_rule->strings; + + const char* string_identifier; + const char* target_identifier; + + int matching = 0; + + while(!STRING_IS_NULL(string)) + { + // Don't generate pushes for strings chained to another one, we are + // only interested in non-chained strings or the head of the chain. + + if (string->chained_to == NULL) + { + string_identifier = string->identifier; + target_identifier = identifier; + + while (*target_identifier != '\0' && + *string_identifier != '\0' && + *target_identifier == *string_identifier) + { + target_identifier++; + string_identifier++; + } + + if ((*target_identifier == '\0' && *string_identifier == '\0') || + *target_identifier == '*') + { + yr_parser_emit_with_arg_reloc( + yyscanner, + OP_PUSH, + string, + NULL, + NULL); + + string->g_flags |= STRING_GFLAGS_REFERENCED; + string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; + matching++; + } + } + + string = (YR_STRING*) yr_arena_next_address( + compiler->strings_arena, + string, + sizeof(YR_STRING)); + } + + if (matching == 0) + { + yr_compiler_set_error_extra_info(compiler, identifier); + compiler->last_result = ERROR_UNDEFINED_STRING; + } + + return compiler->last_result; +} + + +int yr_parser_check_types( + YR_COMPILER* compiler, + YR_OBJECT_FUNCTION* function, + const char* actual_args_fmt) +{ + int i; + + for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++) + { + if (function->prototypes[i].arguments_fmt == NULL) + break; + + if (strcmp(function->prototypes[i].arguments_fmt, actual_args_fmt) == 0) + { + compiler->last_result = ERROR_SUCCESS; + return compiler->last_result; + } + } + + yr_compiler_set_error_extra_info(compiler, function->identifier); + compiler->last_result = ERROR_WRONG_ARGUMENTS; + + return compiler->last_result; +} + + +YR_STRING* yr_parser_lookup_string( + yyscan_t yyscanner, + const char* identifier) +{ + YR_STRING* string; + YR_COMPILER* compiler = yyget_extra(yyscanner); + + string = compiler->current_rule->strings; + + while(!STRING_IS_NULL(string)) + { + // If some string $a gets fragmented into multiple chained + // strings, all those fragments have the same $a identifier + // but we are interested in the heading fragment, which is + // that with chained_to == NULL + + if (strcmp(string->identifier, identifier) == 0 && + string->chained_to == NULL) + { + return string; + } + + string = (YR_STRING*) yr_arena_next_address( + compiler->strings_arena, + string, + sizeof(YR_STRING)); + } + + yr_compiler_set_error_extra_info(compiler, identifier); + compiler->last_result = ERROR_UNDEFINED_STRING; + + return NULL; +} + + +int yr_parser_lookup_loop_variable( + yyscan_t yyscanner, + const char* identifier) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + int i; + + for (i = 0; i < compiler->loop_depth; i++) + { + if (compiler->loop_identifier[i] != NULL && + strcmp(identifier, compiler->loop_identifier[i]) == 0) + return i; + } + + return -1; +} + + +static int _yr_parser_write_string( + const char* identifier, + int flags, + YR_COMPILER* compiler, + SIZED_STRING* str, + RE_AST* re_ast, + YR_STRING** string, + int* min_atom_quality) +{ + SIZED_STRING* literal_string; + YR_ATOM_LIST_ITEM* atom_list = NULL; + + int result; + int max_string_len; + int free_literal = FALSE; + + *string = NULL; + + result = yr_arena_allocate_struct( + compiler->strings_arena, + sizeof(YR_STRING), + (void**) string, + offsetof(YR_STRING, identifier), + offsetof(YR_STRING, string), + offsetof(YR_STRING, chained_to), + offsetof(YR_STRING, rule), + EOL); + + if (result != ERROR_SUCCESS) + return result; + + result = yr_arena_write_string( + compiler->sz_arena, + identifier, + &(*string)->identifier); + + if (result != ERROR_SUCCESS) + return result; + + if (flags & STRING_GFLAGS_HEXADECIMAL || + flags & STRING_GFLAGS_REGEXP) + { + literal_string = yr_re_ast_extract_literal(re_ast); + + if (literal_string != NULL) + { + flags |= STRING_GFLAGS_LITERAL; + free_literal = TRUE; + } + else + { + // Non-literal strings can't be marked as fixed offset because once we + // find a string atom in the scanned data we don't know the offset where + // the string should start, as the non-literal strings can contain + // variable-length portions. + + flags &= ~STRING_GFLAGS_FIXED_OFFSET; + } + } + else + { + literal_string = str; + flags |= STRING_GFLAGS_LITERAL; + } + + (*string)->g_flags = flags; + (*string)->chained_to = NULL; + (*string)->fixed_offset = UNDEFINED; + (*string)->rule = compiler->current_rule; + + #ifdef PROFILING_ENABLED + (*string)->time_cost = 0; + #endif + + memset((*string)->matches, 0, + sizeof((*string)->matches)); + + memset((*string)->unconfirmed_matches, 0, + sizeof((*string)->unconfirmed_matches)); + + if (flags & STRING_GFLAGS_LITERAL) + { + (*string)->length = (uint32_t) literal_string->length; + + result = yr_arena_write_data( + compiler->sz_arena, + literal_string->c_string, + literal_string->length + 1, // +1 to include terminating NULL + (void**) &(*string)->string); + + if (result == ERROR_SUCCESS) + { + result = yr_atoms_extract_from_string( + (uint8_t*) literal_string->c_string, + (int32_t) literal_string->length, + flags, + &atom_list); + } + } + else + { + // Emit forwards code + result = yr_re_ast_emit_code(re_ast, compiler->re_code_arena, FALSE); + + // Emit backwards code + if (result == ERROR_SUCCESS) + result = yr_re_ast_emit_code(re_ast, compiler->re_code_arena, TRUE); + + if (result == ERROR_SUCCESS) + result = yr_atoms_extract_from_re(re_ast, flags, &atom_list); + } + + if (result == ERROR_SUCCESS) + { + // Add the string to Aho-Corasick automaton. + result = yr_ac_add_string( + compiler->automaton, + *string, + atom_list, + compiler->matches_arena); + } + + *min_atom_quality = yr_atoms_min_quality(atom_list); + + if (flags & STRING_GFLAGS_LITERAL) + { + if (flags & STRING_GFLAGS_WIDE) + max_string_len = (*string)->length * 2; + else + max_string_len = (*string)->length; + + if (max_string_len <= MAX_ATOM_LENGTH) + (*string)->g_flags |= STRING_GFLAGS_FITS_IN_ATOM; + } + + if (free_literal) + yr_free(literal_string); + + if (atom_list != NULL) + yr_atoms_list_destroy(atom_list); + + return result; +} + +#include + +#include + + +YR_STRING* yr_parser_reduce_string_declaration( + yyscan_t yyscanner, + int32_t string_flags, + const char* identifier, + SIZED_STRING* str) +{ + int min_atom_quality; + int min_atom_quality_aux; + + int32_t min_gap; + int32_t max_gap; + + char message[512]; + + YR_COMPILER* compiler = yyget_extra(yyscanner); + YR_STRING* string = NULL; + YR_STRING* aux_string; + YR_STRING* prev_string; + + RE_AST* re_ast = NULL; + RE_AST* remainder_re_ast = NULL; + + RE_ERROR re_error; + + // Determine if a string with the same identifier was already defined + // by searching for the identifier in string_table. + + string = (YR_STRING*) yr_hash_table_lookup( + compiler->strings_table, + identifier, + NULL); + + if (string != NULL) + { + compiler->last_result = ERROR_DUPLICATED_STRING_IDENTIFIER; + yr_compiler_set_error_extra_info(compiler, identifier); + goto _exit; + } + + // Empty strings are not allowed + + if (str->length == 0) + { + compiler->last_result = ERROR_EMPTY_STRING; + yr_compiler_set_error_extra_info(compiler, identifier); + goto _exit; + } + + if (str->flags & SIZED_STRING_FLAGS_NO_CASE) + string_flags |= STRING_GFLAGS_NO_CASE; + + if (str->flags & SIZED_STRING_FLAGS_DOT_ALL) + string_flags |= STRING_GFLAGS_DOT_ALL; + + if (strcmp(identifier,"$") == 0) + string_flags |= STRING_GFLAGS_ANONYMOUS; + + if (!(string_flags & STRING_GFLAGS_WIDE) && + !(string_flags & STRING_GFLAGS_XOR)) + string_flags |= STRING_GFLAGS_ASCII; + + // Hex strings are always handled as DOT_ALL regexps. + + if (string_flags & STRING_GFLAGS_HEXADECIMAL) + string_flags |= STRING_GFLAGS_DOT_ALL; + + // The STRING_GFLAGS_SINGLE_MATCH flag indicates that finding + // a single match for the string is enough. This is true in + // most cases, except when the string count (#) and string offset (@) + // operators are used. All strings are marked STRING_FLAGS_SINGLE_MATCH + // initially, and unmarked later if required. + + string_flags |= STRING_GFLAGS_SINGLE_MATCH; + + // The STRING_GFLAGS_FIXED_OFFSET indicates that the string doesn't + // need to be searched all over the file because the user is using the + // "at" operator. The string must be searched at a fixed offset in the + // file. All strings are marked STRING_GFLAGS_FIXED_OFFSET initially, + // and unmarked later if required. + + string_flags |= STRING_GFLAGS_FIXED_OFFSET; + + if (string_flags & STRING_GFLAGS_HEXADECIMAL || + string_flags & STRING_GFLAGS_REGEXP) + { + if (string_flags & STRING_GFLAGS_HEXADECIMAL) + compiler->last_result = yr_re_parse_hex( + str->c_string, &re_ast, &re_error); + else + compiler->last_result = yr_re_parse( + str->c_string, &re_ast, &re_error); + + if (compiler->last_result != ERROR_SUCCESS) + { + snprintf( + message, + sizeof(message), + "invalid %s \"%s\": %s", + (string_flags & STRING_GFLAGS_HEXADECIMAL) ? + "hex string" : "regular expression", + identifier, + re_error.message); + + yr_compiler_set_error_extra_info( + compiler, message); + + goto _exit; + } + + if (re_ast->flags & RE_FLAGS_FAST_REGEXP) + string_flags |= STRING_GFLAGS_FAST_REGEXP; + + // Regular expressions in the strings section can't mix greedy and ungreedy + // quantifiers like .* and .*?. That's because these regular expressions can + // be matched forwards and/or backwards depending on the atom found, and we + // need the regexp to be all-greedy or all-ungreedy to be able to properly + // calculate the length of the match. + + if ((re_ast->flags & RE_FLAGS_GREEDY) && + (re_ast->flags & RE_FLAGS_UNGREEDY)) + { + compiler->last_result = ERROR_INVALID_REGULAR_EXPRESSION; + + yr_compiler_set_error_extra_info(compiler, + "greedy and ungreedy quantifiers can't be mixed in a regular " + "expression"); + + goto _exit; + } + + if (re_ast->flags & RE_FLAGS_GREEDY) + string_flags |= STRING_GFLAGS_GREEDY_REGEXP; + + if (yr_re_ast_contains_dot_star(re_ast)) + { + yywarning( + yyscanner, + "%s contains .* or .+, consider using .{N} or .{1-N} with a reasonable value for N", + identifier); + } + + if (compiler->re_ast_callback != NULL) + { + compiler->re_ast_callback( + compiler->current_rule, + identifier, + re_ast, + compiler->re_ast_clbk_user_data); + } + + compiler->last_result = yr_re_ast_split_at_chaining_point( + re_ast, &re_ast, &remainder_re_ast, &min_gap, &max_gap); + + if (compiler->last_result != ERROR_SUCCESS) + goto _exit; + + compiler->last_result = _yr_parser_write_string( + identifier, + string_flags, + compiler, + NULL, + re_ast, + &string, + &min_atom_quality); + + if (compiler->last_result != ERROR_SUCCESS) + goto _exit; + + if (remainder_re_ast != NULL) + { + string->g_flags |= STRING_GFLAGS_CHAIN_TAIL | STRING_GFLAGS_CHAIN_PART; + string->chain_gap_min = min_gap; + string->chain_gap_max = max_gap; + } + + // Use "aux_string" from now on, we want to keep the value of "string" + // because it will returned. + + aux_string = string; + + while (remainder_re_ast != NULL) + { + // Destroy regexp pointed by 're_ast' before yr_re_split_at_chaining_point + // overwrites 're_ast' with another value. + + yr_re_ast_destroy(re_ast); + + compiler->last_result = yr_re_ast_split_at_chaining_point( + remainder_re_ast, &re_ast, &remainder_re_ast, &min_gap, &max_gap); + + if (compiler->last_result != ERROR_SUCCESS) + goto _exit; + + prev_string = aux_string; + + compiler->last_result = _yr_parser_write_string( + identifier, + string_flags, + compiler, + NULL, + re_ast, + &aux_string, + &min_atom_quality_aux); + + if (compiler->last_result != ERROR_SUCCESS) + goto _exit; + + if (min_atom_quality_aux < min_atom_quality) + min_atom_quality = min_atom_quality_aux; + + aux_string->g_flags |= STRING_GFLAGS_CHAIN_PART; + aux_string->chain_gap_min = min_gap; + aux_string->chain_gap_max = max_gap; + + prev_string->chained_to = aux_string; + + // prev_string is now chained to aux_string, an string chained + // to another one can't have a fixed offset, only the head of the + // string chain can have a fixed offset. + + prev_string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; + } + } + else + { + compiler->last_result = _yr_parser_write_string( + identifier, + string_flags, + compiler, + str, + NULL, + &string, + &min_atom_quality); + + if (compiler->last_result != ERROR_SUCCESS) + goto _exit; + } + + if (!STRING_IS_ANONYMOUS(string)) + { + compiler->last_result = yr_hash_table_add( + compiler->strings_table, + identifier, + NULL, + string); + + if (compiler->last_result != ERROR_SUCCESS) + goto _exit; + } + + if (min_atom_quality < 3 && compiler->callback != NULL) + { + yywarning( + yyscanner, + "%s is slowing down scanning%s", + string->identifier, + min_atom_quality < 2 ? " (critical!)" : ""); + } + +_exit: + + if (re_ast != NULL) + yr_re_ast_destroy(re_ast); + + if (remainder_re_ast != NULL) + yr_re_ast_destroy(remainder_re_ast); + + if (compiler->last_result != ERROR_SUCCESS) + return NULL; + + return string; +} + + +YR_RULE* yr_parser_reduce_rule_declaration_phase_1( + yyscan_t yyscanner, + int32_t flags, + const char* identifier) +{ + YR_FIXUP *fixup; + YR_INIT_RULE_ARGS *init_rule_args; + YR_COMPILER* compiler = yyget_extra(yyscanner); + YR_RULE* rule = NULL; + + if (yr_hash_table_lookup( + compiler->rules_table, + identifier, + compiler->current_namespace->name) != NULL || + yr_hash_table_lookup( + compiler->objects_table, + identifier, + compiler->current_namespace->name) != NULL) + { + // A rule or variable with the same identifier already exists, return the + // appropriate error. + + yr_compiler_set_error_extra_info(compiler, identifier); + compiler->last_result = ERROR_DUPLICATED_IDENTIFIER; + return NULL; + } + + compiler->last_result = yr_arena_allocate_struct( + compiler->rules_arena, + sizeof(YR_RULE), + (void**) &rule, + offsetof(YR_RULE, identifier), + offsetof(YR_RULE, tags), + offsetof(YR_RULE, strings), + offsetof(YR_RULE, metas), + offsetof(YR_RULE, ns), + EOL); + + if (compiler->last_result != ERROR_SUCCESS) + return NULL; + + rule->g_flags = flags; + rule->ns = compiler->current_namespace; + + #ifdef PROFILING_ENABLED + rule->time_cost = 0; + #endif + + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, + identifier, + (char**) &rule->identifier); + + if (compiler->last_result != ERROR_SUCCESS) + return NULL; + + compiler->last_result = yr_parser_emit( + yyscanner, + OP_INIT_RULE, + NULL); + + if (compiler->last_result != ERROR_SUCCESS) + return NULL; + + compiler->last_result = yr_arena_allocate_struct( + compiler->code_arena, + sizeof(YR_INIT_RULE_ARGS), + (void**) &init_rule_args, + offsetof(YR_INIT_RULE_ARGS, rule), + offsetof(YR_INIT_RULE_ARGS, jmp_addr), + EOL); + + if (compiler->last_result != ERROR_SUCCESS) + return NULL; + + init_rule_args->rule = rule; + + // jmp_addr holds the address to jump to when we want to skip the code for + // the rule. It is iniatialized as NULL at this point because we don't know + // the address until emmiting the code for the rule's condition. The address + // is set in yr_parser_reduce_rule_declaration_phase_2. + init_rule_args->jmp_addr = NULL; + + // Create a fixup entry for the jump and push it in the stack + fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); + + if (fixup == NULL) + { + compiler->last_result = ERROR_INSUFFICIENT_MEMORY; + return NULL; + } + + fixup->address = (void*) &(init_rule_args->jmp_addr); + fixup->next = compiler->fixup_stack_head; + compiler->fixup_stack_head = fixup; + + compiler->last_result = yr_hash_table_add( + compiler->rules_table, + identifier, + compiler->current_namespace->name, + (void*) rule); + + // Clean strings_table as we are starting to parse a new rule. + yr_hash_table_clean(compiler->strings_table, NULL); + + compiler->current_rule = rule; + return rule; +} + +int yr_parser_reduce_rule_declaration_phase_2( + yyscan_t yyscanner, + YR_RULE* rule) +{ + uint32_t max_strings_per_rule; + uint32_t strings_in_rule = 0; + uint8_t* nop_inst_addr = NULL; + + YR_FIXUP *fixup; + YR_COMPILER* compiler = yyget_extra(yyscanner); + + // Check for unreferenced (unused) strings. + + YR_STRING* string = rule->strings; + + yr_get_configuration( + YR_CONFIG_MAX_STRINGS_PER_RULE, + (void*) &max_strings_per_rule); + + while (!STRING_IS_NULL(string)) + { + // Only the heading fragment in a chain of strings (the one with + // chained_to == NULL) must be referenced. All other fragments + // are never marked as referenced. + + if (!STRING_IS_REFERENCED(string) && + string->chained_to == NULL) + { + yr_compiler_set_error_extra_info(compiler, string->identifier); + compiler->last_result = ERROR_UNREFERENCED_STRING; + return compiler->last_result; + } + + strings_in_rule++; + + if (strings_in_rule > max_strings_per_rule) { + yr_compiler_set_error_extra_info(compiler, rule->identifier); + compiler->last_result = ERROR_TOO_MANY_STRINGS; + return compiler->last_result; + } + + string = (YR_STRING*) yr_arena_next_address( + compiler->strings_arena, + string, + sizeof(YR_STRING)); + } + + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_MATCH_RULE, + rule, + NULL, + NULL); + + // Generate a do-nothing instruction (NOP) in order to get its address + // and use it as the destination for the OP_INIT_RULE skip jump. We can not + // simply use the address of the OP_MATCH_RULE instruction +1 because we + // can't be sure that the instruction following the OP_MATCH_RULE is going to + // be in the same arena page. As we don't have a reliable way of getting the + // address of the next instruction we generate the OP_NOP. + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit( + yyscanner, + OP_NOP, + &nop_inst_addr); + + fixup = compiler->fixup_stack_head; + *(void**)(fixup->address) = (void*) nop_inst_addr; + compiler->fixup_stack_head = fixup->next; + yr_free(fixup); + + return compiler->last_result; +} + + +int yr_parser_reduce_string_identifier( + yyscan_t yyscanner, + const char* identifier, + uint8_t instruction, + uint64_t at_offset) +{ + YR_STRING* string; + YR_COMPILER* compiler = yyget_extra(yyscanner); + + if (strcmp(identifier, "$") == 0) // is an anonymous string ? + { + if (compiler->loop_for_of_mem_offset >= 0) // inside a loop ? + { + yr_parser_emit_with_arg( + yyscanner, + OP_PUSH_M, + compiler->loop_for_of_mem_offset, + NULL, + NULL); + + yr_parser_emit(yyscanner, instruction, NULL); + + string = compiler->current_rule->strings; + + while(!STRING_IS_NULL(string)) + { + if (instruction != OP_FOUND) + string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH; + + if (instruction == OP_FOUND_AT) + { + // Avoid overwriting any previous fixed offset + + if (string->fixed_offset == UNDEFINED) + string->fixed_offset = at_offset; + + // If a previous fixed offset was different, disable + // the STRING_GFLAGS_FIXED_OFFSET flag because we only + // have room to store a single fixed offset value + + if (string->fixed_offset != at_offset) + string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; + } + else + { + string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; + } + + string = (YR_STRING*) yr_arena_next_address( + compiler->strings_arena, + string, + sizeof(YR_STRING)); + } + } + else + { + // Anonymous strings not allowed outside of a loop + compiler->last_result = ERROR_MISPLACED_ANONYMOUS_STRING; + } + } + else + { + string = yr_parser_lookup_string(yyscanner, identifier); + + if (string != NULL) + { + yr_parser_emit_with_arg_reloc( + yyscanner, + OP_PUSH, + string, + NULL, + NULL); + + if (instruction != OP_FOUND) + string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH; + + if (instruction == OP_FOUND_AT) + { + // Avoid overwriting any previous fixed offset + + if (string->fixed_offset == UNDEFINED) + string->fixed_offset = at_offset; + + // If a previous fixed offset was different, disable + // the STRING_GFLAGS_FIXED_OFFSET flag because we only + // have room to store a single fixed offset value + + if (string->fixed_offset == UNDEFINED || + string->fixed_offset != at_offset) + { + string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; + } + } + else + { + string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; + } + + yr_parser_emit(yyscanner, instruction, NULL); + + string->g_flags |= STRING_GFLAGS_REFERENCED; + } + } + + return compiler->last_result; +} + + +YR_META* yr_parser_reduce_meta_declaration( + yyscan_t yyscanner, + int32_t type, + const char* identifier, + const char* string, + int64_t integer) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + YR_META* meta; + + compiler->last_result = yr_arena_allocate_struct( + compiler->metas_arena, + sizeof(YR_META), + (void**) &meta, + offsetof(YR_META, identifier), + offsetof(YR_META, string), + EOL); + + if (compiler->last_result != ERROR_SUCCESS) + return NULL; + + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, + identifier, + (char**) &meta->identifier); + + if (compiler->last_result != ERROR_SUCCESS) + return NULL; + + if (string != NULL) + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, + string, + &meta->string); + else + meta->string = NULL; + + if (compiler->last_result != ERROR_SUCCESS) + return NULL; + + meta->integer = integer; + meta->type = type; + + return meta; +} + + +static int _yr_parser_valid_module_name( + SIZED_STRING* module_name) +{ + if (module_name->length == 0) + return FALSE; + + if (strlen(module_name->c_string) != module_name->length) + return FALSE; + + return TRUE; +} + + +int yr_parser_reduce_import( + yyscan_t yyscanner, + SIZED_STRING* module_name) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + YR_OBJECT* module_structure; + + char* name; + + if (!_yr_parser_valid_module_name(module_name)) + { + compiler->last_result = ERROR_INVALID_MODULE_NAME; + yr_compiler_set_error_extra_info(compiler, module_name->c_string); + + return ERROR_INVALID_MODULE_NAME; + } + + module_structure = (YR_OBJECT*) yr_hash_table_lookup( + compiler->objects_table, + module_name->c_string, + compiler->current_namespace->name); + + // if module already imported, do nothing + + if (module_structure != NULL) + return ERROR_SUCCESS; + + compiler->last_result = yr_object_create( + OBJECT_TYPE_STRUCTURE, + module_name->c_string, + NULL, + &module_structure); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_hash_table_add( + compiler->objects_table, + module_name->c_string, + compiler->current_namespace->name, + module_structure); + + if (compiler->last_result == ERROR_SUCCESS) + { + compiler->last_result = yr_modules_do_declarations( + module_name->c_string, + module_structure); + + if (compiler->last_result == ERROR_UNKNOWN_MODULE) + yr_compiler_set_error_extra_info(compiler, module_name->c_string); + } + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_arena_write_string( + compiler->sz_arena, + module_name->c_string, + &name); + + if (compiler->last_result == ERROR_SUCCESS) + compiler->last_result = yr_parser_emit_with_arg_reloc( + yyscanner, + OP_IMPORT, + name, + NULL, + NULL); + + return compiler->last_result; +} + + +static int _yr_parser_operator_to_opcode( + const char* op, + int expression_type) +{ + int opcode = 0; + + switch(expression_type) + { + case EXPRESSION_TYPE_INTEGER: + opcode = OP_INT_BEGIN; + break; + case EXPRESSION_TYPE_FLOAT: + opcode = OP_DBL_BEGIN; + break; + case EXPRESSION_TYPE_STRING: + opcode = OP_STR_BEGIN; + break; + default: + assert(FALSE); + } + + if (op[0] == '<') + { + if (op[1] == '=') + opcode += _OP_LE; + else + opcode += _OP_LT; + } + else if (op[0] == '>') + { + if (op[1] == '=') + opcode += _OP_GE; + else + opcode += _OP_GT; + } + else if (op[1] == '=') + { + if (op[0] == '=') + opcode += _OP_EQ; + else + opcode += _OP_NEQ; + } + else if (op[0] == '+') + { + opcode += _OP_ADD; + } + else if (op[0] == '-') + { + opcode += _OP_SUB; + } + else if (op[0] == '*') + { + opcode += _OP_MUL; + } + else if (op[0] == '\\') + { + opcode += _OP_DIV; + } + + if (IS_INT_OP(opcode) || IS_DBL_OP(opcode) || IS_STR_OP(opcode)) + { + return opcode; + } + + return OP_ERROR; +} + + +int yr_parser_reduce_operation( + yyscan_t yyscanner, + const char* op, + EXPRESSION left_operand, + EXPRESSION right_operand) +{ + YR_COMPILER* compiler = yyget_extra(yyscanner); + + if ((left_operand.type == EXPRESSION_TYPE_INTEGER || + left_operand.type == EXPRESSION_TYPE_FLOAT) && + (right_operand.type == EXPRESSION_TYPE_INTEGER || + right_operand.type == EXPRESSION_TYPE_FLOAT)) + { + if (left_operand.type != right_operand.type) + { + // One operand is double and the other is integer, + // cast the integer to double + + compiler->last_result = yr_parser_emit_with_arg( + yyscanner, + OP_INT_TO_DBL, + (left_operand.type == EXPRESSION_TYPE_INTEGER) ? 2 : 1, + NULL, + NULL); + } + + if (compiler->last_result == ERROR_SUCCESS) + { + int expression_type = EXPRESSION_TYPE_FLOAT; + + if (left_operand.type == EXPRESSION_TYPE_INTEGER && + right_operand.type == EXPRESSION_TYPE_INTEGER) + { + expression_type = EXPRESSION_TYPE_INTEGER; + } + + compiler->last_result = yr_parser_emit( + yyscanner, + _yr_parser_operator_to_opcode(op, expression_type), + NULL); + } + + } + else if (left_operand.type == EXPRESSION_TYPE_STRING && + right_operand.type == EXPRESSION_TYPE_STRING) + { + int opcode = _yr_parser_operator_to_opcode(op, EXPRESSION_TYPE_STRING); + + if (opcode != OP_ERROR) + { + compiler->last_result = yr_parser_emit( + yyscanner, + opcode, + NULL); + } + else + { + yr_compiler_set_error_extra_info_fmt( + compiler, "strings don't support \"%s\" operation", op); + + compiler->last_result = ERROR_WRONG_TYPE; + } + } + else + { + yr_compiler_set_error_extra_info(compiler, "type mismatch"); + compiler->last_result = ERROR_WRONG_TYPE; + } + + return compiler->last_result; +} diff --git a/yara-master/libyara/proc.c b/yara-master/libyara/proc.c new file mode 100644 index 0000000..23b4468 --- /dev/null +++ b/yara-master/libyara/proc.c @@ -0,0 +1,82 @@ +/* +Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include + +int _yr_process_attach(int, YR_PROC_ITERATOR_CTX*); +int _yr_process_detach(YR_PROC_ITERATOR_CTX*); + +YR_API int yr_process_open_iterator( + int pid, + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) \ + yr_malloc(sizeof(YR_PROC_ITERATOR_CTX)); + + if (context == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + iterator->context = context; + iterator->first = yr_process_get_first_memory_block; + iterator->next = yr_process_get_next_memory_block; + + context->buffer = NULL; + context->buffer_size = 0; + context->current_block.base = 0; + context->current_block.size = 0; + context->current_block.context = context; + context->current_block.fetch_data = yr_process_fetch_memory_block_data; + context->proc_info = NULL; + + return _yr_process_attach(pid, context); +} + + +YR_API int yr_process_close_iterator( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + + if (context != NULL) + { + _yr_process_detach(context); + + if (context->buffer != NULL) + yr_free((void*) context->buffer); + + yr_free(context->proc_info); + yr_free(context); + + iterator->context = NULL; + } + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/proc/freebsd.c b/yara-master/libyara/proc/freebsd.c new file mode 100644 index 0000000..35fb880 --- /dev/null +++ b/yara-master/libyara/proc/freebsd.c @@ -0,0 +1,173 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#if defined(USE_FREEBSD_PROC) + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct _YR_PROC_INFO { + int pid; + struct ptrace_vm_entry vm_entry; +} YR_PROC_INFO; + + +int _yr_process_attach( + int pid, + YR_PROC_ITERATOR_CTX* context) +{ + int status; + + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); + + if (proc_info == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + context->proc_info = proc_info; + + proc_info->pid = pid; + if (ptrace(PT_ATTACH, pid, NULL, 0) == -1) + { + yr_free(proc_info); + + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + status = 0; + + if (waitpid(pid, &status, 0) == -1) + { + ptrace(PT_DETACH, proc_info->pid, NULL, 0); + yr_free(proc_info); + + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + return ERROR_SUCCESS; +} + + +int _yr_process_detach( + YR_PROC_ITERATOR_CTX* context) +{ + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + ptrace(PT_DETACH, proc_info->pid, NULL, 0); + proc_info->vm_entry.pve_path = NULL; + + return ERROR_SUCCESS; +} + + +YR_API const uint8_t* yr_process_fetch_memory_block_data( + YR_MEMORY_BLOCK* block) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + struct ptrace_io_desc io_desc; + + if (context->buffer_size < block->size) + { + if (context->buffer != NULL) + yr_free((void*) context->buffer); + + context->buffer = (const uint8_t*) yr_malloc(block->size); + + if (context->buffer != NULL) + { + context->buffer_size = block->size; + } + else + { + context->buffer_size = 0; + return NULL; + } + } + + io_desc.piod_op = PIOD_READ_D; + io_desc.piod_offs = (void*)block->base; + io_desc.piod_addr = (void*)context->buffer; + io_desc.piod_len = block->size; + + if (ptrace(PT_IO, proc_info->pid, (char*)&io_desc, 0) == -1) + { + return NULL; + } + + return context->buffer; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + char buf[4096]; + + proc_info->vm_entry.pve_path = buf; + proc_info->vm_entry.pve_pathlen = sizeof(buf); + + if (ptrace(PT_VM_ENTRY, proc_info->pid, (char*)(&proc_info->vm_entry), 0) == -1) { + return NULL; + } + + context->current_block.base = proc_info->vm_entry.pve_start; + context->current_block.size = + proc_info->vm_entry.pve_end - proc_info->vm_entry.pve_start + 1; + + return &context->current_block; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + proc_info->vm_entry.pve_entry = 0; + + return yr_process_get_next_memory_block(iterator); +} + +#endif diff --git a/yara-master/libyara/proc/linux.c b/yara-master/libyara/proc/linux.c new file mode 100644 index 0000000..a719ad2 --- /dev/null +++ b/yara-master/libyara/proc/linux.c @@ -0,0 +1,218 @@ +/* +Copyright (c) 2007-2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#if defined(USE_LINUX_PROC) + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +#define PTRACE_ATTACH PT_ATTACH +#define PTRACE_DETACH PT_DETACH +#define _XOPEN_SOURCE 500 +#endif + +#include +#include +#include + + +typedef struct _YR_PROC_INFO { + int pid; + int mem_fd; + FILE* maps; +} YR_PROC_INFO; + + +int _yr_process_attach( + int pid, + YR_PROC_ITERATOR_CTX* context) +{ + int status; + char buffer[256]; + + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); + + if (proc_info == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + context->proc_info = proc_info; + + proc_info->pid = pid; + proc_info->maps = NULL; + proc_info->mem_fd = -1; + + snprintf(buffer, sizeof(buffer), "/proc/%u/maps", pid); + proc_info->maps = fopen(buffer, "r"); + + if (proc_info->maps == NULL) + { + yr_free(proc_info); + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + snprintf(buffer, sizeof(buffer), "/proc/%u/mem", pid); + proc_info->mem_fd = open(buffer, O_RDONLY); + + if (proc_info->mem_fd == -1) + { + fclose(proc_info->maps); + proc_info->maps = NULL; + + yr_free(proc_info); + + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + if (ptrace(PTRACE_ATTACH, pid, NULL, 0) == -1) + { + fclose(proc_info->maps); + proc_info->maps = NULL; + + close(proc_info->mem_fd); + proc_info->mem_fd = -1; + + yr_free(proc_info); + + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + status = 0; + + if (waitpid(pid, &status, 0) == -1) + { + // this is a strange error state where we attached but the proc didn't + // stop. Try to detach and clean up. + ptrace(PTRACE_DETACH, proc_info->pid, NULL, 0); + + fclose(proc_info->maps); + proc_info->maps = NULL; + + close(proc_info->mem_fd); + proc_info->mem_fd = -1; + + yr_free(proc_info); + + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + return ERROR_SUCCESS; +} + + +int _yr_process_detach( + YR_PROC_ITERATOR_CTX* context) +{ + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + fclose(proc_info->maps); + close(proc_info->mem_fd); + ptrace(PTRACE_DETACH, proc_info->pid, NULL, 0); + + return ERROR_SUCCESS; +} + + +YR_API const uint8_t* yr_process_fetch_memory_block_data( + YR_MEMORY_BLOCK* block) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + if (context->buffer_size < block->size) + { + if (context->buffer != NULL) + yr_free((void*) context->buffer); + + context->buffer = (const uint8_t*) yr_malloc(block->size); + + if (context->buffer != NULL) + { + context->buffer_size = block->size; + } + else + { + context->buffer_size = 0; + return NULL; + } + } + + if (pread(proc_info->mem_fd, + (void *) context->buffer, + block->size, + block->base) == -1) + { + return NULL; + } + + return context->buffer; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + char buffer[256]; + uint64_t begin, end; + + if (fgets(buffer, sizeof(buffer), proc_info->maps) != NULL) + { + sscanf(buffer, "%"SCNx64"-%"SCNx64, &begin, &end); + + context->current_block.base = begin; + context->current_block.size = end - begin; + + return &context->current_block; + } + + return NULL; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + if (fseek(proc_info->maps, 0, SEEK_SET) != 0) + return NULL; + + return yr_process_get_next_memory_block(iterator); +} + +#endif diff --git a/yara-master/libyara/proc/mach.c b/yara-master/libyara/proc/mach.c new file mode 100644 index 0000000..8ab6c52 --- /dev/null +++ b/yara-master/libyara/proc/mach.c @@ -0,0 +1,172 @@ +/* +Copyright (c) 2007-2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#if defined(USE_MACH_PROC) + +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct _YR_PROC_INFO { + task_t task; +} YR_PROC_INFO; + + +int _yr_process_attach( + int pid, + YR_PROC_ITERATOR_CTX* context) +{ + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); + + if (proc_info == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + kern_return_t kr = task_for_pid(mach_task_self(), pid, &proc_info->task); + + if (kr != KERN_SUCCESS) + { + yr_free(proc_info); + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + context->proc_info = proc_info; + + return ERROR_SUCCESS; +} + + +int _yr_process_detach( + YR_PROC_ITERATOR_CTX* context) +{ + YR_PROC_INFO* proc_info = context->proc_info; + + if (proc_info->task != MACH_PORT_NULL) + mach_port_deallocate(mach_task_self(), proc_info->task); + + return ERROR_SUCCESS; +} + + +YR_API const uint8_t* yr_process_fetch_memory_block_data( + YR_MEMORY_BLOCK* block) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; + YR_PROC_INFO* proc_info = context->proc_info; + vm_size_t size = block->size; + + if (context->buffer_size < block->size) + { + if (context->buffer != NULL) + yr_free((void*) context->buffer); + + context->buffer = (const uint8_t*) yr_malloc(block->size); + + if (context->buffer != NULL) + { + context->buffer_size = block->size; + } + else + { + context->buffer_size = 0; + return NULL; + } + } + + if (vm_read_overwrite( + proc_info->task, + (vm_address_t) block->base, + block->size, + (vm_address_t) context->buffer, + &size) != KERN_SUCCESS) + { + return NULL; + } + + return context->buffer; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = context->proc_info; + + kern_return_t kr; + mach_msg_type_number_t info_count; + mach_port_t object; + vm_region_basic_info_data_64_t info; + vm_size_t size = 0; + vm_address_t address = (vm_address_t) \ + context->current_block.base + context->current_block.size; + do + { + info_count = VM_REGION_BASIC_INFO_COUNT_64; + + kr = vm_region_64( + proc_info->task, + &address, + &size, + VM_REGION_BASIC_INFO, + (vm_region_info_t) &info, + &info_count, + &object); + + if (kr == KERN_SUCCESS) + { + context->current_block.base = address; + context->current_block.size = size; + + return &context->current_block; + } + + } while (kr != KERN_INVALID_ADDRESS); + + return NULL; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + + context->current_block.base = 0; + context->current_block.size = 0; + + return yr_process_get_next_memory_block(iterator); +} + +#endif diff --git a/yara-master/libyara/proc/none.c b/yara-master/libyara/proc/none.c new file mode 100644 index 0000000..41cc20f --- /dev/null +++ b/yara-master/libyara/proc/none.c @@ -0,0 +1,66 @@ +/* +Copyright (c) 2007-2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#if defined(USE_NO_PROC) + +#include +#include + +int _yr_process_attach( + int pid, + YR_PROC_ITERATOR_CTX* context) +{ + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; +} + +int _yr_process_detach( + YR_PROC_ITERATOR_CTX* context) +{ + return ERROR_INVALID_ARGUMENT; +} + +YR_API const uint8_t* yr_process_fetch_memory_block_data( + YR_MEMORY_BLOCK* block) +{ + return ERROR_INVALID_ARGUMENT; +} + +YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + return NULL; +} + +YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + return NULL; +} + +#endif diff --git a/yara-master/libyara/proc/openbsd.c b/yara-master/libyara/proc/openbsd.c new file mode 100644 index 0000000..5c7d51b --- /dev/null +++ b/yara-master/libyara/proc/openbsd.c @@ -0,0 +1,181 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#if defined(USE_OPENBSD_PROC) + +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct _YR_PROC_INFO { + int pid; + uint64_t old_end; + struct kinfo_vmentry vm_entry; +} YR_PROC_INFO; + + +int _yr_process_attach( + int pid, + YR_PROC_ITERATOR_CTX* context) +{ + int status; + size_t len = sizeof(struct kinfo_vmentry); + + int mib[] = { CTL_KERN, KERN_PROC_VMMAP, pid }; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); + + if (proc_info == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + proc_info->pid = pid; + if (ptrace(PT_ATTACH, pid, NULL, 0) == -1) + { + yr_free(proc_info); + + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + status = 0; + if (waitpid(pid, &status, 0) == -1) + { + ptrace(PT_DETACH, proc_info->pid, NULL, 0); + yr_free(proc_info); + + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + if (sysctl(mib, 3, &proc_info->vm_entry, &len, NULL, 0) < 0) + { + ptrace(PT_DETACH, proc_info->pid, NULL, 0); + yr_free(proc_info); + + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + context->proc_info = proc_info; + + return ERROR_SUCCESS; +} + + +int _yr_process_detach( + YR_PROC_ITERATOR_CTX* context) +{ + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + ptrace(PT_DETACH, proc_info->pid, NULL, 0); + + return ERROR_SUCCESS; +} + + +YR_API const uint8_t* yr_process_fetch_memory_block_data( + YR_MEMORY_BLOCK* block) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + struct ptrace_io_desc io_desc; + + if (context->buffer_size < block->size) + { + if (context->buffer != NULL) + yr_free((void*) context->buffer); + + context->buffer = (const uint8_t*) yr_malloc(block->size); + + if (context->buffer != NULL) + { + context->buffer_size = block->size; + } + else + { + context->buffer_size = 0; + return NULL; + } + } + + io_desc.piod_op = PIOD_READ_D; + io_desc.piod_offs = (void*)block->base; + io_desc.piod_addr = (void*)context->buffer; + io_desc.piod_len = block->size; + + if (ptrace(PT_IO, proc_info->pid, (char*)&io_desc, 0) == -1) + return NULL; + + return context->buffer; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + int mib[] = { CTL_KERN, KERN_PROC_VMMAP, proc_info->pid }; + size_t len = sizeof(struct kinfo_vmentry); + + if (sysctl(mib, 3, &proc_info->vm_entry, &len, NULL, 0) < 0) + return NULL; + + // no more blocks + if (proc_info->old_end == proc_info->vm_entry.kve_end) + return NULL; + + proc_info->old_end = proc_info->vm_entry.kve_end; + context->current_block.base = proc_info->vm_entry.kve_start; + context->current_block.size = + proc_info->vm_entry.kve_end - proc_info->vm_entry.kve_start; + + proc_info->vm_entry.kve_start = proc_info->vm_entry.kve_start + 1; + + return &context->current_block; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + proc_info->vm_entry.kve_start = 0; + + return yr_process_get_next_memory_block(iterator); +} + +#endif diff --git a/yara-master/libyara/proc/windows.c b/yara-master/libyara/proc/windows.c new file mode 100644 index 0000000..0fd063f --- /dev/null +++ b/yara-master/libyara/proc/windows.c @@ -0,0 +1,191 @@ +/* +Copyright (c) 2007-2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#if defined(USE_WINDOWS_PROC) + +#include + +#include +#include +#include + + +typedef struct _YR_PROC_INFO { + HANDLE hProcess; + SYSTEM_INFO si; +} YR_PROC_INFO; + +int _yr_process_attach( + int pid, + YR_PROC_ITERATOR_CTX* context) +{ + TOKEN_PRIVILEGES tokenPriv; + LUID luidDebug; + HANDLE hToken = NULL; + + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); + + if (proc_info == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) && + LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidDebug)) + { + tokenPriv.PrivilegeCount = 1; + tokenPriv.Privileges[0].Luid = luidDebug; + tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + AdjustTokenPrivileges( + hToken, + FALSE, + &tokenPriv, + sizeof(tokenPriv), + NULL, + NULL); + } + + if (hToken != NULL) + CloseHandle(hToken); + + proc_info->hProcess = OpenProcess( + PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, + FALSE, + pid); + + if (proc_info->hProcess == NULL) + { + yr_free(proc_info); + return ERROR_COULD_NOT_ATTACH_TO_PROCESS; + } + + GetSystemInfo(&proc_info->si); + + context->proc_info = proc_info; + + return ERROR_SUCCESS; +} + + +int _yr_process_detach( + YR_PROC_ITERATOR_CTX* context) +{ + YR_PROC_INFO* proc_info = (YR_PROC_INFO*)context->proc_info; + + CloseHandle(proc_info->hProcess); + return ERROR_SUCCESS; +} + + +YR_API const uint8_t* yr_process_fetch_memory_block_data( + YR_MEMORY_BLOCK* block) +{ + SIZE_T read; + + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + if (context->buffer_size < block->size) + { + if (context->buffer != NULL) + yr_free((void*) context->buffer); + + context->buffer = (const uint8_t*) yr_malloc(block->size); + + if (context->buffer != NULL) + { + context->buffer_size = block->size; + } + else + { + context->buffer_size = 0; + return NULL; + } + } + + if (ReadProcessMemory( + proc_info->hProcess, + (LPCVOID) block->base, + (LPVOID) context->buffer, + (SIZE_T) block->size, + &read) == FALSE) + { + return NULL; + } + + return context->buffer; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + MEMORY_BASIC_INFORMATION mbi; + PVOID address = (PVOID) (context->current_block.base + \ + context->current_block.size); + + while (address < proc_info->si.lpMaximumApplicationAddress && + VirtualQueryEx(proc_info->hProcess, address, &mbi, sizeof(mbi)) != 0) + { + // mbi.RegionSize can overflow address while scanning a 64-bit process + // with a 32-bit YARA. + if ((uint8_t*) address + mbi.RegionSize <= address) + break; + + if (mbi.State == MEM_COMMIT && ((mbi.Protect & PAGE_NOACCESS) == 0)) + { + context->current_block.base = (size_t) mbi.BaseAddress; + context->current_block.size = mbi.RegionSize; + + return &context->current_block; + } + + address = (uint8_t*) address + mbi.RegionSize; + } + + return NULL; +} + + +YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; + + context->current_block.size = 0; + context->current_block.base = \ + (size_t) proc_info->si.lpMinimumApplicationAddress; + + return yr_process_get_next_memory_block(iterator); +} + +#endif diff --git a/yara-master/libyara/re.c b/yara-master/libyara/re.c new file mode 100644 index 0000000..ba120b1 --- /dev/null +++ b/yara-master/libyara/re.c @@ -0,0 +1,2382 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + + +/* + +This module implements a regular expressions engine based on Thompson's +algorithm as described by Russ Cox in http://swtch.com/~rsc/regexp/regexp2.html. + +What the article names a "thread" has been named a "fiber" in this code, in +order to avoid confusion with operating system threads. + +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define EMIT_BACKWARDS 0x01 +#define EMIT_DONT_SET_FORWARDS_CODE 0x02 +#define EMIT_DONT_SET_BACKWARDS_CODE 0x04 + +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif + + +typedef uint8_t RE_SPLIT_ID_TYPE; + + +typedef struct _RE_REPEAT_ARGS +{ + uint16_t min; + uint16_t max; + int32_t offset; + +} RE_REPEAT_ARGS; + + +typedef struct _RE_REPEAT_ANY_ARGS +{ + uint16_t min; + uint16_t max; + +} RE_REPEAT_ANY_ARGS; + + +typedef struct _RE_EMIT_CONTEXT { + + YR_ARENA* arena; + RE_SPLIT_ID_TYPE next_split_id; + +} RE_EMIT_CONTEXT; + + +#define CHAR_IN_CLASS(cls, chr) \ + ((cls)[(chr) / 8] & 1 << ((chr) % 8)) + + +static int _yr_re_is_char_in_class( + RE_CLASS* re_class, + uint8_t chr, + int case_insensitive) +{ + int result = CHAR_IN_CLASS(re_class->bitmap, chr); + + if (case_insensitive) + result |= CHAR_IN_CLASS(re_class->bitmap, yr_altercase[chr]); + + if (re_class->negated) + result = !result; + + return result; +} + + +static int _yr_re_is_word_char( + const uint8_t* input, + uint8_t character_size) +{ + int result = ((isalnum(*input) || (*input) == '_')); + + if (character_size == 2) + result = result && (*(input + 1) == 0); + + return result; +} + + +RE_NODE* yr_re_node_create( + int type, + RE_NODE* left, + RE_NODE* right) +{ + RE_NODE* result = (RE_NODE*) yr_malloc(sizeof(RE_NODE)); + + if (result != NULL) + { + result->type = type; + result->left = left; + result->right = right; + result->greedy = TRUE; + result->forward_code = NULL; + result->backward_code = NULL; + } + + return result; +} + + +void yr_re_node_destroy( + RE_NODE* node) +{ + if (node->left != NULL) + yr_re_node_destroy(node->left); + + if (node->right != NULL) + yr_re_node_destroy(node->right); + + if (node->type == RE_NODE_CLASS) + yr_free(node->re_class); + + yr_free(node); +} + + +int yr_re_ast_create( + RE_AST** re_ast) +{ + *re_ast = (RE_AST*) yr_malloc(sizeof(RE_AST)); + + if (*re_ast == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + (*re_ast)->flags = 0; + (*re_ast)->levels = 0; + (*re_ast)->root_node = NULL; + + return ERROR_SUCCESS; +} + + +void yr_re_ast_destroy( + RE_AST* re_ast) +{ + if (re_ast->root_node != NULL) + yr_re_node_destroy(re_ast->root_node); + + yr_free(re_ast); +} + + +// +// yr_re_parse +// +// Parses a regexp but don't emit its code. A further call to +// yr_re_emit_code is required to get the code. +// + +int yr_re_parse( + const char* re_string, + RE_AST** re_ast, + RE_ERROR* error) +{ + return yr_parse_re_string(re_string, re_ast, error); +} + + +// +// yr_re_parse_hex +// +// Parses a hex string but don't emit its code. A further call to +// yr_re_emit_code is required to get the code. +// + +int yr_re_parse_hex( + const char* hex_string, + RE_AST** re_ast, + RE_ERROR* error) +{ + return yr_parse_hex_string(hex_string, re_ast, error); +} + + +// +// yr_re_compile +// +// Parses the regexp and emit its code to the provided code_arena. +// + +int yr_re_compile( + const char* re_string, + int flags, + YR_ARENA* code_arena, + RE** re, + RE_ERROR* error) +{ + RE_AST* re_ast; + RE _re; + + FAIL_ON_ERROR(yr_arena_reserve_memory( + code_arena, sizeof(int64_t) + RE_MAX_CODE_SIZE)); + + FAIL_ON_ERROR(yr_re_parse(re_string, &re_ast, error)); + + _re.flags = flags; + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_arena_write_data( + code_arena, + &_re, + sizeof(_re), + (void**) re), + yr_re_ast_destroy(re_ast)); + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_re_ast_emit_code(re_ast, code_arena, FALSE), + yr_re_ast_destroy(re_ast)); + + yr_re_ast_destroy(re_ast); + + return ERROR_SUCCESS; +} + + +// +// yr_re_match +// +// Verifies if the target string matches the pattern +// +// Args: +// YR_SCAN_CONTEXT* context - Scan context +// RE* re - A pointer to a compiled regexp +// char* target - Target string +// +// Returns: +// See return codes for yr_re_exec + + +int yr_re_match( + YR_SCAN_CONTEXT* context, + RE* re, + const char* target) +{ + int result; + + yr_re_exec( + context, + re->code, + (uint8_t*) target, + strlen(target), + 0, + re->flags | RE_FLAGS_SCAN, + NULL, + NULL, + &result); + + return result; +} + + +// +// yr_re_ast_extract_literal +// +// Verifies if the provided regular expression is just a literal string +// like "abc", "12345", without any wildcard, operator, etc. In that case +// returns the string as a SIZED_STRING, or returns NULL if otherwise. +// +// The caller is responsible for deallocating the returned SIZED_STRING by +// calling yr_free. +// + +SIZED_STRING* yr_re_ast_extract_literal( + RE_AST* re_ast) +{ + SIZED_STRING* string; + RE_NODE* node = re_ast->root_node; + + int i, length = 0; + + while (node != NULL) + { + length++; + + if (node->type == RE_NODE_LITERAL) + break; + + if (node->type != RE_NODE_CONCAT) + return NULL; + + if (node->right == NULL || + node->right->type != RE_NODE_LITERAL) + return NULL; + + node = node->left; + } + + string = (SIZED_STRING*) yr_malloc(sizeof(SIZED_STRING) + length); + + if (string == NULL) + return NULL; + + string->length = length; + node = re_ast->root_node; + + // The root node is the end of the string. So let's fill it up backwards. + for (i = length - 1; i > 0; i--) + { + string->c_string[i] = node->right->value; + node = node->left; + } + + if (length > 0) + string->c_string[0] = node->value; + + assert(node == NULL || node->type == RE_NODE_LITERAL); + + return string; +} + + +int _yr_re_node_contains_dot_star( + RE_NODE* re_node) +{ + if ((re_node->type == RE_NODE_STAR || re_node->type == RE_NODE_PLUS) && + re_node->left->type == RE_NODE_ANY) + return TRUE; + + if (re_node->left != NULL && _yr_re_node_contains_dot_star(re_node->left)) + return TRUE; + + if (re_node->right != NULL && _yr_re_node_contains_dot_star(re_node->right)) + return TRUE; + + return FALSE; +} + + +int yr_re_ast_contains_dot_star( + RE_AST* re_ast) +{ + return _yr_re_node_contains_dot_star(re_ast->root_node); +} + + +// +// yr_re_ast_split_at_chaining_point +// +// In some cases splitting a regular expression in two is more efficient that +// having a single regular expression. This happens when the regular expression +// contains a large repetition of any character, for example: /foo.{0,1000}bar/ +// In this case the regexp is split in /foo/ and /bar/ where /bar/ is "chained" +// to /foo/. This means that /foo/ and /bar/ are handled as individual regexps +// and when both matches YARA verifies if the distance between the matches +// complies with the {0,1000} restriction. + +// This function traverses the regexp's tree looking for nodes where the regxp +// should be split. It expects a left-unbalanced tree where the right child of +// a RE_NODE_CONCAT can't be another RE_NODE_CONCAT. A RE_NODE_CONCAT must be +// always the left child of its parent if the parent is also a RE_NODE_CONCAT. +// + +int yr_re_ast_split_at_chaining_point( + RE_AST* re_ast, + RE_AST** result_re_ast, + RE_AST** remainder_re_ast, + int32_t* min_gap, + int32_t* max_gap) +{ + RE_NODE* node = re_ast->root_node; + RE_NODE* child = re_ast->root_node->left; + RE_NODE* parent = NULL; + + int result; + + *result_re_ast = re_ast; + *remainder_re_ast = NULL; + *min_gap = 0; + *max_gap = 0; + + while (child != NULL && child->type == RE_NODE_CONCAT) + { + if (child->right != NULL && + child->right->type == RE_NODE_RANGE_ANY && + child->right->greedy == FALSE && + (child->right->start > STRING_CHAINING_THRESHOLD || + child->right->end > STRING_CHAINING_THRESHOLD)) + { + result = yr_re_ast_create(remainder_re_ast); + + if (result != ERROR_SUCCESS) + return result; + + (*remainder_re_ast)->root_node = child->left; + (*remainder_re_ast)->flags = re_ast->flags; + + child->left = NULL; + + if (parent != NULL) + parent->left = node->right; + else + (*result_re_ast)->root_node = node->right; + + node->right = NULL; + + *min_gap = child->right->start; + *max_gap = child->right->end; + + yr_re_node_destroy(node); + + return ERROR_SUCCESS; + } + + parent = node; + node = child; + child = child->left; + } + + return ERROR_SUCCESS; +} + + +int _yr_emit_inst( + RE_EMIT_CONTEXT* emit_context, + uint8_t opcode, + uint8_t** instruction_addr, + size_t* code_size) +{ + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &opcode, + sizeof(uint8_t), + (void**) instruction_addr)); + + *code_size = sizeof(uint8_t); + + return ERROR_SUCCESS; +} + + +int _yr_emit_inst_arg_uint8( + RE_EMIT_CONTEXT* emit_context, + uint8_t opcode, + uint8_t argument, + uint8_t** instruction_addr, + uint8_t** argument_addr, + size_t* code_size) +{ + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &opcode, + sizeof(uint8_t), + (void**) instruction_addr)); + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &argument, + sizeof(uint8_t), + (void**) argument_addr)); + + *code_size = 2 * sizeof(uint8_t); + + return ERROR_SUCCESS; +} + + +int _yr_emit_inst_arg_uint16( + RE_EMIT_CONTEXT* emit_context, + uint8_t opcode, + uint16_t argument, + uint8_t** instruction_addr, + uint16_t** argument_addr, + size_t* code_size) +{ + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &opcode, + sizeof(uint8_t), + (void**) instruction_addr)); + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &argument, + sizeof(uint16_t), + (void**) argument_addr)); + + *code_size = sizeof(uint8_t) + sizeof(uint16_t); + + return ERROR_SUCCESS; +} + + +int _yr_emit_inst_arg_uint32( + RE_EMIT_CONTEXT* emit_context, + uint8_t opcode, + uint32_t argument, + uint8_t** instruction_addr, + uint32_t** argument_addr, + size_t* code_size) +{ + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &opcode, + sizeof(uint8_t), + (void**) instruction_addr)); + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &argument, + sizeof(uint32_t), + (void**) argument_addr)); + + *code_size = sizeof(uint8_t) + sizeof(uint32_t); + + return ERROR_SUCCESS; +} + + +int _yr_emit_inst_arg_int16( + RE_EMIT_CONTEXT* emit_context, + uint8_t opcode, + int16_t argument, + uint8_t** instruction_addr, + int16_t** argument_addr, + size_t* code_size) +{ + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &opcode, + sizeof(uint8_t), + (void**) instruction_addr)); + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &argument, + sizeof(int16_t), + (void**) argument_addr)); + + *code_size = sizeof(uint8_t) + sizeof(int16_t); + + return ERROR_SUCCESS; +} + + +int _yr_emit_inst_arg_struct( + RE_EMIT_CONTEXT* emit_context, + uint8_t opcode, + void* structure, + size_t structure_size, + uint8_t** instruction_addr, + void** argument_addr, + size_t* code_size) +{ + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &opcode, + sizeof(uint8_t), + (void**) instruction_addr)); + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + structure, + structure_size, + (void**) argument_addr)); + + *code_size = sizeof(uint8_t) + structure_size; + + return ERROR_SUCCESS; +} + + +int _yr_emit_split( + RE_EMIT_CONTEXT* emit_context, + uint8_t opcode, + int16_t argument, + uint8_t** instruction_addr, + int16_t** argument_addr, + size_t* code_size) +{ + assert(opcode == RE_OPCODE_SPLIT_A || opcode == RE_OPCODE_SPLIT_B); + + if (emit_context->next_split_id == RE_MAX_SPLIT_ID) + return ERROR_REGULAR_EXPRESSION_TOO_COMPLEX; + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &opcode, + sizeof(uint8_t), + (void**) instruction_addr)); + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &emit_context->next_split_id, + sizeof(RE_SPLIT_ID_TYPE), + NULL)); + + emit_context->next_split_id++; + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + &argument, + sizeof(int16_t), + (void**) argument_addr)); + + *code_size = sizeof(uint8_t) + sizeof(RE_SPLIT_ID_TYPE) + sizeof(int16_t); + + return ERROR_SUCCESS; +} + + +static int _yr_re_emit( + RE_EMIT_CONTEXT* emit_context, + RE_NODE* re_node, + int flags, + uint8_t** code_addr, + size_t* code_size) +{ + size_t branch_size; + size_t split_size; + size_t inst_size; + size_t jmp_size; + + int emit_split; + int emit_repeat; + int emit_prolog; + int emit_epilog; + + RE_REPEAT_ARGS repeat_args; + RE_REPEAT_ARGS* repeat_start_args_addr; + RE_REPEAT_ANY_ARGS repeat_any_args; + + RE_NODE* left; + RE_NODE* right; + + int16_t* split_offset_addr = NULL; + int16_t* jmp_offset_addr = NULL; + uint8_t* instruction_addr = NULL; + + *code_size = 0; + + switch(re_node->type) + { + case RE_NODE_LITERAL: + + FAIL_ON_ERROR(_yr_emit_inst_arg_uint8( + emit_context, + RE_OPCODE_LITERAL, + re_node->value, + &instruction_addr, + NULL, + code_size)); + break; + + case RE_NODE_MASKED_LITERAL: + + FAIL_ON_ERROR(_yr_emit_inst_arg_uint16( + emit_context, + RE_OPCODE_MASKED_LITERAL, + re_node->mask << 8 | re_node->value, + &instruction_addr, + NULL, + code_size)); + break; + + case RE_NODE_WORD_CHAR: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_WORD_CHAR, + &instruction_addr, + code_size)); + break; + + case RE_NODE_NON_WORD_CHAR: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_NON_WORD_CHAR, + &instruction_addr, + code_size)); + break; + + case RE_NODE_WORD_BOUNDARY: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_WORD_BOUNDARY, + &instruction_addr, + code_size)); + break; + + case RE_NODE_NON_WORD_BOUNDARY: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_NON_WORD_BOUNDARY, + &instruction_addr, + code_size)); + break; + + case RE_NODE_SPACE: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_SPACE, + &instruction_addr, + code_size)); + break; + + case RE_NODE_NON_SPACE: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_NON_SPACE, + &instruction_addr, + code_size)); + break; + + case RE_NODE_DIGIT: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_DIGIT, + &instruction_addr, + code_size)); + break; + + case RE_NODE_NON_DIGIT: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_NON_DIGIT, + &instruction_addr, + code_size)); + break; + + case RE_NODE_ANY: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_ANY, + &instruction_addr, + code_size)); + break; + + case RE_NODE_CLASS: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_CLASS, + &instruction_addr, + code_size)); + + FAIL_ON_ERROR(yr_arena_write_data( + emit_context->arena, + re_node->re_class, + sizeof(*re_node->re_class), + NULL)); + + *code_size += sizeof(*re_node->re_class); + break; + + case RE_NODE_ANCHOR_START: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_MATCH_AT_START, + &instruction_addr, + code_size)); + break; + + case RE_NODE_ANCHOR_END: + + FAIL_ON_ERROR(_yr_emit_inst( + emit_context, + RE_OPCODE_MATCH_AT_END, + &instruction_addr, + code_size)); + break; + + case RE_NODE_CONCAT: + + if (flags & EMIT_BACKWARDS) + { + left = re_node->right; + right = re_node->left; + } + else + { + left = re_node->left; + right = re_node->right; + } + + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + left, + flags, + &instruction_addr, + &branch_size)); + + *code_size += branch_size; + + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + right, + flags, + NULL, + &branch_size)); + + *code_size += branch_size; + + break; + + case RE_NODE_PLUS: + + // Code for e+ looks like: + // + // L1: code for e + // split L1, L2 + // L2: + + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + re_node->left, + flags, + &instruction_addr, + &branch_size)); + + *code_size += branch_size; + + FAIL_ON_ERROR(_yr_emit_split( + emit_context, + re_node->greedy ? RE_OPCODE_SPLIT_B : RE_OPCODE_SPLIT_A, + -((int16_t) branch_size), + NULL, + &split_offset_addr, + &split_size)); + + *code_size += split_size; + break; + + case RE_NODE_STAR: + + // Code for e* looks like: + // + // L1: split L1, L2 + // code for e + // jmp L1 + // L2: + + FAIL_ON_ERROR(_yr_emit_split( + emit_context, + re_node->greedy ? RE_OPCODE_SPLIT_A : RE_OPCODE_SPLIT_B, + 0, + &instruction_addr, + &split_offset_addr, + &split_size)); + + *code_size += split_size; + + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + re_node->left, + flags, + NULL, + &branch_size)); + + *code_size += branch_size; + + // Emit jump with offset set to 0. + + FAIL_ON_ERROR(_yr_emit_inst_arg_int16( + emit_context, + RE_OPCODE_JUMP, + -((uint16_t)(branch_size + split_size)), + NULL, + &jmp_offset_addr, + &jmp_size)); + + *code_size += jmp_size; + + if (split_size + branch_size + jmp_size >= INT16_MAX) + return ERROR_REGULAR_EXPRESSION_TOO_LARGE; + + // Update split offset. + *split_offset_addr = (int16_t) (split_size + branch_size + jmp_size); + break; + + case RE_NODE_ALT: + + // Code for e1|e2 looks like: + // + // split L1, L2 + // L1: code for e1 + // jmp L3 + // L2: code for e2 + // L3: + + // Emit a split instruction with offset set to 0 temporarily. Offset + // will be updated after we know the size of the code generated for + // the left node (e1). + + FAIL_ON_ERROR(_yr_emit_split( + emit_context, + RE_OPCODE_SPLIT_A, + 0, + &instruction_addr, + &split_offset_addr, + &split_size)); + + *code_size += split_size; + + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + re_node->left, + flags, + NULL, + &branch_size)); + + *code_size += branch_size; + + // Emit jump with offset set to 0. + + FAIL_ON_ERROR(_yr_emit_inst_arg_int16( + emit_context, + RE_OPCODE_JUMP, + 0, + NULL, + &jmp_offset_addr, + &jmp_size)); + + *code_size += jmp_size; + + if (split_size + branch_size + jmp_size >= INT16_MAX) + return ERROR_REGULAR_EXPRESSION_TOO_LARGE; + + // Update split offset. + *split_offset_addr = (int16_t) (split_size + branch_size + jmp_size); + + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + re_node->right, + flags, + NULL, + &branch_size)); + + *code_size += branch_size; + + if (branch_size + jmp_size >= INT16_MAX) + return ERROR_REGULAR_EXPRESSION_TOO_LARGE; + + // Update offset for jmp instruction. + *jmp_offset_addr = (int16_t) (branch_size + jmp_size); + break; + + case RE_NODE_RANGE_ANY: + + repeat_any_args.min = re_node->start; + repeat_any_args.max = re_node->end; + + FAIL_ON_ERROR(_yr_emit_inst_arg_struct( + emit_context, + re_node->greedy ? + RE_OPCODE_REPEAT_ANY_GREEDY : + RE_OPCODE_REPEAT_ANY_UNGREEDY, + &repeat_any_args, + sizeof(repeat_any_args), + &instruction_addr, + NULL, + &inst_size)); + + *code_size += inst_size; + break; + + case RE_NODE_RANGE: + + // Code for e{n,m} looks like: + // + // code for e --- prolog + // repeat_start n, m, L1 --+ + // L0: code for e | repeat + // repeat_end n, m, L0 --+ + // L1: split L2, L3 --- split + // L2: code for e --- epilog + // L3: + // + // Not all sections (prolog, repeat, split and epilog) are generated in all + // cases, it depends on the values of n and m. The following table shows + // which sections are generated for the first few values of n and m. + // + // n,m prolog repeat split epilog + // (min,max) + // --------------------------------------- + // 0,0 - - - - + // 0,1 - - X X + // 0,2 - 0,1 X X + // 0,3 - 0,2 X X + // 0,M - 0,M-1 X X + // + // 1,1 X - - - + // 1,2 X - X X + // 1,3 X 0,1 X X + // 1,4 X 1,2 X X + // 1,M X 1,M-2 X X + // + // 2,2 X - - X + // 2,3 X 1,1 X X + // 2,4 X 1,2 X X + // 2,M X 1,M-2 X X + // + // 3,3 X 1,1 - X + // 3,4 X 2,2 X X + // 3,M X 2,M-2 X X + // + // 4,4 X 2,2 - X + // 4,5 X 3,3 X X + // 4,M X 3,M-2 X X + // + // The code can't consists simply in the repeat section, the prolog and + // epilog are required because we can't have atoms pointing to code inside + // the repeat loop. Atoms' forwards_code will point to code in the prolog + // and backwards_code will point to code in the epilog (or in prolog if + // epilog wasn't generated, like in n=1,m=1) + + emit_prolog = re_node->start > 0; + emit_repeat = re_node->end > re_node->start + 1 || re_node->end > 2; + emit_split = re_node->end > re_node->start; + emit_epilog = re_node->end > re_node->start || re_node->end > 1; + + if (emit_prolog) + { + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + re_node->left, + flags, + &instruction_addr, + &branch_size)); + + *code_size += branch_size; + } + + if (emit_repeat) + { + repeat_args.min = re_node->start; + repeat_args.max = re_node->end; + + if (emit_prolog) + { + repeat_args.max--; + repeat_args.min--; + } + + if (emit_split) + { + repeat_args.max--; + } + else + { + repeat_args.min--; + repeat_args.max--; + } + + repeat_args.offset = 0; + + FAIL_ON_ERROR(_yr_emit_inst_arg_struct( + emit_context, + re_node->greedy ? + RE_OPCODE_REPEAT_START_GREEDY : + RE_OPCODE_REPEAT_START_UNGREEDY, + &repeat_args, + sizeof(repeat_args), + emit_prolog ? NULL : &instruction_addr, + (void**) &repeat_start_args_addr, + &inst_size)); + + *code_size += inst_size; + + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + re_node->left, + flags | EMIT_DONT_SET_FORWARDS_CODE | EMIT_DONT_SET_BACKWARDS_CODE, + NULL, + &branch_size)); + + *code_size += branch_size; + + repeat_start_args_addr->offset = (int32_t)(2 * inst_size + branch_size); + repeat_args.offset = -((int32_t) branch_size); + + FAIL_ON_ERROR(_yr_emit_inst_arg_struct( + emit_context, + re_node->greedy ? + RE_OPCODE_REPEAT_END_GREEDY : + RE_OPCODE_REPEAT_END_UNGREEDY, + &repeat_args, + sizeof(repeat_args), + NULL, + NULL, + &inst_size)); + + *code_size += inst_size; + } + + if (emit_split) + { + FAIL_ON_ERROR(_yr_emit_split( + emit_context, + re_node->greedy ? + RE_OPCODE_SPLIT_A : + RE_OPCODE_SPLIT_B, + 0, + NULL, + &split_offset_addr, + &split_size)); + + *code_size += split_size; + } + + if (emit_epilog) + { + FAIL_ON_ERROR(_yr_re_emit( + emit_context, + re_node->left, + emit_prolog ? flags | EMIT_DONT_SET_FORWARDS_CODE : flags, + emit_prolog || emit_repeat ? NULL : &instruction_addr, + &branch_size)); + + *code_size += branch_size; + } + + if (emit_split) + { + if (split_size + branch_size >= INT16_MAX) + return ERROR_REGULAR_EXPRESSION_TOO_LARGE; + + *split_offset_addr = (int16_t) (split_size + branch_size); + } + + break; + } + + if (flags & EMIT_BACKWARDS) + { + if (!(flags & EMIT_DONT_SET_BACKWARDS_CODE)) + re_node->backward_code = instruction_addr + *code_size; + } + else + { + if (!(flags & EMIT_DONT_SET_FORWARDS_CODE)) + re_node->forward_code = instruction_addr; + } + + if (code_addr != NULL) + *code_addr = instruction_addr; + + return ERROR_SUCCESS; +} + + +int yr_re_ast_emit_code( + RE_AST* re_ast, + YR_ARENA* arena, + int backwards_code) +{ + RE_EMIT_CONTEXT emit_context; + + size_t code_size; + size_t total_size; + + // Ensure that we have enough contiguous memory space in the arena to + // contain the regular expression code. The code can't span over multiple + // non-contiguous pages. + + FAIL_ON_ERROR(yr_arena_reserve_memory(arena, RE_MAX_CODE_SIZE)); + + // Emit code for matching the regular expressions forwards. + + total_size = 0; + emit_context.arena = arena; + emit_context.next_split_id = 0; + + FAIL_ON_ERROR(_yr_re_emit( + &emit_context, + re_ast->root_node, + backwards_code ? EMIT_BACKWARDS : 0, + NULL, + &code_size)); + + total_size += code_size; + + FAIL_ON_ERROR(_yr_emit_inst( + &emit_context, + RE_OPCODE_MATCH, + NULL, + &code_size)); + + total_size += code_size; + + if (total_size > RE_MAX_CODE_SIZE) + return ERROR_REGULAR_EXPRESSION_TOO_LARGE; + + return ERROR_SUCCESS; +} + + +static int _yr_re_fiber_create( + RE_FIBER_POOL* fiber_pool, + RE_FIBER** new_fiber) +{ + RE_FIBER* fiber; + + if (fiber_pool->fibers.head != NULL) + { + fiber = fiber_pool->fibers.head; + fiber_pool->fibers.head = fiber->next; + + if (fiber_pool->fibers.tail == fiber) + fiber_pool->fibers.tail = NULL; + } + else + { + if (fiber_pool->fiber_count == RE_MAX_FIBERS) + return ERROR_TOO_MANY_RE_FIBERS; + + fiber = (RE_FIBER*) yr_malloc(sizeof(RE_FIBER)); + + if (fiber == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + fiber_pool->fiber_count++; + } + + fiber->ip = NULL; + fiber->sp = -1; + fiber->rc = -1; + fiber->next = NULL; + fiber->prev = NULL; + + *new_fiber = fiber; + + return ERROR_SUCCESS; +} + + +// +// _yr_re_fiber_append +// +// Appends 'fiber' to 'fiber_list' +// + +static void _yr_re_fiber_append( + RE_FIBER_LIST* fiber_list, + RE_FIBER* fiber) +{ + assert(fiber->prev == NULL); + assert(fiber->next == NULL); + + fiber->prev = fiber_list->tail; + + if (fiber_list->tail != NULL) + fiber_list->tail->next = fiber; + + fiber_list->tail = fiber; + + if (fiber_list->head == NULL) + fiber_list->head = fiber; + + assert(fiber_list->tail->next == NULL); + assert(fiber_list->head->prev == NULL); +} + + +// +// _yr_re_fiber_exists +// +// Verifies if a fiber with the same properties (ip, rc, sp, and stack values) +// than 'target_fiber' exists in 'fiber_list'. The list is iterated from +// the start until 'last_fiber' (inclusive). Fibers past 'last_fiber' are not +// taken into account. +// + +static int _yr_re_fiber_exists( + RE_FIBER_LIST* fiber_list, + RE_FIBER* target_fiber, + RE_FIBER* last_fiber) +{ + RE_FIBER* fiber = fiber_list->head; + + int equal_stacks; + int i; + + if (last_fiber == NULL) + return FALSE; + + while (fiber != last_fiber->next) + { + if (fiber->ip == target_fiber->ip && + fiber->sp == target_fiber->sp && + fiber->rc == target_fiber->rc) + { + equal_stacks = TRUE; + + for (i = 0; i <= fiber->sp; i++) + { + if (fiber->stack[i] != target_fiber->stack[i]) + { + equal_stacks = FALSE; + break; + } + } + + if (equal_stacks) + return TRUE; + } + + fiber = fiber->next; + } + + return FALSE; +} + + +// +// _yr_re_fiber_split +// +// Clones a fiber in fiber_list and inserts the cloned fiber just after. +// the original one. If fiber_list is: +// +// f1 -> f2 -> f3 -> f4 +// +// Splitting f2 will result in: +// +// f1 -> f2 -> cloned f2 -> f3 -> f4 +// + +static int _yr_re_fiber_split( + RE_FIBER_LIST* fiber_list, + RE_FIBER_POOL* fiber_pool, + RE_FIBER* fiber, + RE_FIBER** new_fiber) +{ + int32_t i; + + FAIL_ON_ERROR(_yr_re_fiber_create(fiber_pool, new_fiber)); + + (*new_fiber)->sp = fiber->sp; + (*new_fiber)->ip = fiber->ip; + (*new_fiber)->rc = fiber->rc; + + for (i = 0; i <= fiber->sp; i++) + (*new_fiber)->stack[i] = fiber->stack[i]; + + (*new_fiber)->next = fiber->next; + (*new_fiber)->prev = fiber; + + if (fiber->next != NULL) + fiber->next->prev = *new_fiber; + + fiber->next = *new_fiber; + + if (fiber_list->tail == fiber) + fiber_list->tail = *new_fiber; + + assert(fiber_list->tail->next == NULL); + assert(fiber_list->head->prev == NULL); + + return ERROR_SUCCESS; +} + + +// +// _yr_re_fiber_kill +// +// Kills a given fiber by removing it from the fiber list and putting it +// in the fiber pool. +// + +static RE_FIBER* _yr_re_fiber_kill( + RE_FIBER_LIST* fiber_list, + RE_FIBER_POOL* fiber_pool, + RE_FIBER* fiber) +{ + RE_FIBER* next_fiber = fiber->next; + + if (fiber->prev != NULL) + fiber->prev->next = next_fiber; + + if (next_fiber != NULL) + next_fiber->prev = fiber->prev; + + if (fiber_pool->fibers.tail != NULL) + fiber_pool->fibers.tail->next = fiber; + + if (fiber_list->tail == fiber) + fiber_list->tail = fiber->prev; + + if (fiber_list->head == fiber) + fiber_list->head = next_fiber; + + fiber->next = NULL; + fiber->prev = fiber_pool->fibers.tail; + fiber_pool->fibers.tail = fiber; + + if (fiber_pool->fibers.head == NULL) + fiber_pool->fibers.head = fiber; + + return next_fiber; +} + + +// +// _yr_re_fiber_kill_tail +// +// Kills all fibers from the given one up to the end of the fiber list. +// + +static void _yr_re_fiber_kill_tail( + RE_FIBER_LIST* fiber_list, + RE_FIBER_POOL* fiber_pool, + RE_FIBER* fiber) +{ + RE_FIBER* prev_fiber = fiber->prev; + + if (prev_fiber != NULL) + prev_fiber->next = NULL; + + fiber->prev = fiber_pool->fibers.tail; + + if (fiber_pool->fibers.tail != NULL) + fiber_pool->fibers.tail->next = fiber; + + fiber_pool->fibers.tail = fiber_list->tail; + fiber_list->tail = prev_fiber; + + if (fiber_list->head == fiber) + fiber_list->head = NULL; + + if (fiber_pool->fibers.head == NULL) + fiber_pool->fibers.head = fiber; +} + + +// +// _yr_re_fiber_kill_all +// +// Kills all fibers in the fiber list. +// + +static void _yr_re_fiber_kill_all( + RE_FIBER_LIST* fiber_list, + RE_FIBER_POOL* fiber_pool) +{ + if (fiber_list->head != NULL) + _yr_re_fiber_kill_tail(fiber_list, fiber_pool, fiber_list->head); +} + + +// +// _yr_re_fiber_sync +// +// Executes a fiber until reaching an "matching" instruction. A "matching" +// instruction is one that actually reads a byte from the input and performs +// some matching. If the fiber reaches a split instruction, the new fiber is +// also synced. +// + +static int _yr_re_fiber_sync( + RE_FIBER_LIST* fiber_list, + RE_FIBER_POOL* fiber_pool, + RE_FIBER* fiber_to_sync) +{ + // A array for keeping track of which split instructions has been already + // executed. Each split instruction within a regexp has an associated ID + // between 0 and RE_MAX_SPLIT_ID. Keeping track of executed splits is + // required to avoid infinite loops in regexps like (a*)* or (a|)* + + RE_SPLIT_ID_TYPE splits_executed[RE_MAX_SPLIT_ID]; + RE_SPLIT_ID_TYPE splits_executed_count = 0; + RE_SPLIT_ID_TYPE split_id, splits_executed_idx; + + int split_already_executed; + + RE_REPEAT_ARGS* repeat_args; + RE_REPEAT_ANY_ARGS* repeat_any_args; + + RE_FIBER* fiber; + RE_FIBER* last; + RE_FIBER* next; + RE_FIBER* branch_a; + RE_FIBER* branch_b; + + fiber = fiber_to_sync; + last = fiber_to_sync->next; + + while (fiber != last) + { + uint8_t opcode = *fiber->ip; + + switch (opcode) + { + case RE_OPCODE_SPLIT_A: + case RE_OPCODE_SPLIT_B: + + split_id = *(RE_SPLIT_ID_TYPE*)(fiber->ip + 1); + split_already_executed = FALSE; + + for (splits_executed_idx = 0; + splits_executed_idx < splits_executed_count; + splits_executed_idx++) + { + if (split_id == splits_executed[splits_executed_idx]) + { + split_already_executed = TRUE; + break; + } + } + + if (split_already_executed) + { + fiber = _yr_re_fiber_kill(fiber_list, fiber_pool, fiber); + } + else + { + branch_a = fiber; + + FAIL_ON_ERROR(_yr_re_fiber_split( + fiber_list, fiber_pool, branch_a, &branch_b)); + + // With RE_OPCODE_SPLIT_A the current fiber continues at the next + // instruction in the stream (branch A), while the newly created + // fiber starts at the address indicated by the instruction (branch B) + // RE_OPCODE_SPLIT_B has the opposite behavior. + + if (opcode == RE_OPCODE_SPLIT_B) + yr_swap(branch_a, branch_b, RE_FIBER*); + + // Branch A continues at the next instruction + + branch_a->ip += (sizeof(RE_SPLIT_ID_TYPE) + 3); + + // Branch B adds the offset encoded in the opcode to its instruction + // pointer. + + branch_b->ip += *(int16_t*)( + branch_b->ip + + 1 // opcode size + + sizeof(RE_SPLIT_ID_TYPE)); + + splits_executed[splits_executed_count] = split_id; + splits_executed_count++; + } + + break; + + case RE_OPCODE_REPEAT_START_GREEDY: + case RE_OPCODE_REPEAT_START_UNGREEDY: + + repeat_args = (RE_REPEAT_ARGS*)(fiber->ip + 1); + assert(repeat_args->max > 0); + branch_a = fiber; + + if (repeat_args->min == 0) + { + FAIL_ON_ERROR(_yr_re_fiber_split( + fiber_list, fiber_pool, branch_a, &branch_b)); + + if (opcode == RE_OPCODE_REPEAT_START_UNGREEDY) + yr_swap(branch_a, branch_b, RE_FIBER*); + + branch_b->ip += repeat_args->offset; + } + + branch_a->stack[++branch_a->sp] = 0; + branch_a->ip += (1 + sizeof(RE_REPEAT_ARGS)); + break; + + case RE_OPCODE_REPEAT_END_GREEDY: + case RE_OPCODE_REPEAT_END_UNGREEDY: + + repeat_args = (RE_REPEAT_ARGS*)(fiber->ip + 1); + fiber->stack[fiber->sp]++; + + if (fiber->stack[fiber->sp] < repeat_args->min) + { + fiber->ip += repeat_args->offset; + break; + } + + branch_a = fiber; + + if (fiber->stack[fiber->sp] < repeat_args->max) + { + FAIL_ON_ERROR(_yr_re_fiber_split( + fiber_list, fiber_pool, branch_a, &branch_b)); + + if (opcode == RE_OPCODE_REPEAT_END_GREEDY) + yr_swap(branch_a, branch_b, RE_FIBER*); + + branch_a->sp--; + branch_b->ip += repeat_args->offset; + } + + branch_a->ip += (1 + sizeof(RE_REPEAT_ARGS)); + break; + + case RE_OPCODE_REPEAT_ANY_GREEDY: + case RE_OPCODE_REPEAT_ANY_UNGREEDY: + + repeat_any_args = (RE_REPEAT_ANY_ARGS*)(fiber->ip + 1); + + // If repetition counter (rc) is -1 it means that we are reaching this + // instruction from the previous one in the instructions stream. In + // this case let's initialize the counter to 0 and start looping. + + if (fiber->rc == -1) + fiber->rc = 0; + + if (fiber->rc < repeat_any_args->min) + { + // Increase repetition counter and continue with next fiber. The + // instruction pointer for this fiber is not incremented yet, this + // fiber spins in this same instruction until reaching the minimum + // number of repetitions. + + fiber->rc++; + fiber = fiber->next; + } + else if (fiber->rc < repeat_any_args->max) + { + // Once the minimum number of repetitions are matched one fiber + // remains spinning in this instruction until reaching the maximum + // number of repetitions while new fibers are created. New fibers + // start executing at the next instruction. + + next = fiber->next; + branch_a = fiber; + + FAIL_ON_ERROR(_yr_re_fiber_split( + fiber_list, fiber_pool, branch_a, &branch_b)); + + if (opcode == RE_OPCODE_REPEAT_ANY_UNGREEDY) + yr_swap(branch_a, branch_b, RE_FIBER*); + + branch_a->rc++; + branch_b->ip += (1 + sizeof(RE_REPEAT_ANY_ARGS)); + branch_b->rc = -1; + + FAIL_ON_ERROR(_yr_re_fiber_sync( + fiber_list, fiber_pool, branch_b)); + + fiber = next; + } + else + { + // When the maximum number of repetitions is reached the fiber keeps + // executing at the next instruction. The repetition counter is set + // to -1 indicating that we are not spinning in a repeat instruction + // anymore. + + fiber->ip += (1 + sizeof(RE_REPEAT_ANY_ARGS)); + fiber->rc = -1; + } + + break; + + case RE_OPCODE_JUMP: + fiber->ip += *(int16_t*)(fiber->ip + 1); + break; + + default: + fiber = fiber->next; + } + } + + return ERROR_SUCCESS; +} + + +// +// yr_re_exec +// +// Executes a regular expression. The specified regular expression will try to +// match the data starting at the address specified by "input". The "input" +// pointer can point to any address inside a memory buffer. Arguments +// "input_forwards_size" and "input_backwards_size" indicate how many bytes +// can be accesible starting at "input" and going forwards and backwards +// respectively. +// +// <--- input_backwards_size -->|<----------- input_forwards_size --------> +// |-------- memory buffer -----------------------------------------------| +// ^ +// input +// +// Args: +// YR_SCAN_CONTEXT *context - Scan context. +// const uint8_t* code - Regexp code be executed +// const uint8_t* input - Pointer to input data +// size_t input_forwards_size - Number of accessible bytes starting at +// "input" and going forwards. +// size_t input_backwards_size - Number of accessible bytes starting at +// "input" and going backwards +// int flags - Flags: +// RE_FLAGS_SCAN +// RE_FLAGS_BACKWARDS +// RE_FLAGS_EXHAUSTIVE +// RE_FLAGS_WIDE +// RE_FLAGS_NO_CASE +// RE_FLAGS_DOT_ALL +// RE_MATCH_CALLBACK_FUNC callback - Callback function +// void* callback_args - Callback argument +// int* matches - Pointer to an integer receiving the +// number of matching bytes. Notice that +// 0 means a zero-length match, while no +// matches is -1. +// Returns: +// ERROR_SUCCESS or any other error code. + +int yr_re_exec( + YR_SCAN_CONTEXT* context, + const uint8_t* code, + const uint8_t* input_data, + size_t input_forwards_size, + size_t input_backwards_size, + int flags, + RE_MATCH_CALLBACK_FUNC callback, + void* callback_args, + int* matches) +{ + const uint8_t* input; + const uint8_t* ip; + + uint8_t mask; + uint8_t value; + uint8_t character_size; + + RE_FIBER_LIST fibers; + RE_FIBER* fiber; + RE_FIBER* next_fiber; + + int bytes_matched; + int max_bytes_matched; + int match; + int input_incr; + int kill; + int action; + + #define ACTION_NONE 0 + #define ACTION_CONTINUE 1 + #define ACTION_KILL 2 + #define ACTION_KILL_TAIL 3 + + #define prolog { \ + if ((bytes_matched >= max_bytes_matched) || \ + (character_size == 2 && *(input + 1) != 0)) \ + { \ + action = ACTION_KILL; \ + break; \ + } \ + } + + if (matches != NULL) + *matches = -1; + + if (flags & RE_FLAGS_WIDE) + character_size = 2; + else + character_size = 1; + + input = input_data; + input_incr = character_size; + + if (flags & RE_FLAGS_BACKWARDS) + { + max_bytes_matched = (int) yr_min(input_backwards_size, RE_SCAN_LIMIT); + input -= character_size; + input_incr = -input_incr; + } + else + { + max_bytes_matched = (int) yr_min(input_forwards_size, RE_SCAN_LIMIT); + } + + // Round down max_bytes_matched to a multiple of character_size, this way if + // character_size is 2 and max_bytes_matched is odd we are ignoring the + // extra byte which can't match anyways. + + max_bytes_matched = max_bytes_matched - max_bytes_matched % character_size; + bytes_matched = 0; + + FAIL_ON_ERROR(_yr_re_fiber_create(&context->re_fiber_pool, &fiber)); + + fiber->ip = code; + fibers.head = fiber; + fibers.tail = fiber; + + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), + _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); + + while (fibers.head != NULL) + { + fiber = fibers.head; + + while (fiber != NULL) + { + next_fiber = fiber->next; + + if (_yr_re_fiber_exists(&fibers, fiber, fiber->prev)) + _yr_re_fiber_kill(&fibers, &context->re_fiber_pool, fiber); + + fiber = next_fiber; + } + + fiber = fibers.head; + + while (fiber != NULL) + { + ip = fiber->ip; + action = ACTION_NONE; + + switch (*ip) + { + case RE_OPCODE_ANY: + prolog; + match = (flags & RE_FLAGS_DOT_ALL) || (*input != 0x0A); + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += 1; + break; + + case RE_OPCODE_REPEAT_ANY_GREEDY: + case RE_OPCODE_REPEAT_ANY_UNGREEDY: + prolog; + match = (flags & RE_FLAGS_DOT_ALL) || (*input != 0x0A); + action = match ? ACTION_NONE : ACTION_KILL; + + // The instruction pointer is not incremented here. The current fiber + // spins in this instruction until reaching the required number of + // repetitions. The code controlling the number of repetitions is in + // _yr_re_fiber_sync. + + break; + + case RE_OPCODE_LITERAL: + prolog; + if (flags & RE_FLAGS_NO_CASE) + match = yr_lowercase[*input] == yr_lowercase[*(ip + 1)]; + else + match = (*input == *(ip + 1)); + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += 2; + break; + + case RE_OPCODE_MASKED_LITERAL: + prolog; + value = *(int16_t*)(ip + 1) & 0xFF; + mask = *(int16_t*)(ip + 1) >> 8; + + // We don't need to take into account the case-insensitive + // case because this opcode is only used with hex strings, + // which can't be case-insensitive. + + match = ((*input & mask) == value); + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += 3; + break; + + case RE_OPCODE_CLASS: + prolog; + match = _yr_re_is_char_in_class( + (RE_CLASS*) (ip + 1), *input, flags & RE_FLAGS_NO_CASE); + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += (sizeof(RE_CLASS) + 1); + break; + + case RE_OPCODE_WORD_CHAR: + prolog; + match = _yr_re_is_word_char(input, character_size); + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += 1; + break; + + case RE_OPCODE_NON_WORD_CHAR: + prolog; + match = !_yr_re_is_word_char(input, character_size); + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += 1; + break; + + case RE_OPCODE_SPACE: + case RE_OPCODE_NON_SPACE: + + prolog; + + switch (*input) + { + case ' ': + case '\t': + case '\r': + case '\n': + case '\v': + case '\f': + match = TRUE; + break; + default: + match = FALSE; + } + + if (*ip == RE_OPCODE_NON_SPACE) + match = !match; + + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += 1; + break; + + case RE_OPCODE_DIGIT: + prolog; + match = isdigit(*input); + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += 1; + break; + + case RE_OPCODE_NON_DIGIT: + prolog; + match = !isdigit(*input); + action = match ? ACTION_NONE : ACTION_KILL; + fiber->ip += 1; + break; + + case RE_OPCODE_WORD_BOUNDARY: + case RE_OPCODE_NON_WORD_BOUNDARY: + + if (bytes_matched == 0 && input_backwards_size < character_size) + { + match = TRUE; + } + else if (bytes_matched >= max_bytes_matched) + { + match = TRUE; + } + else + { + assert(input < input_data + input_forwards_size); + assert(input >= input_data - input_backwards_size); + + assert(input - input_incr < input_data + input_forwards_size); + assert(input - input_incr >= input_data - input_backwards_size); + + match = _yr_re_is_word_char(input, character_size) != \ + _yr_re_is_word_char(input - input_incr, character_size); + } + + if (*ip == RE_OPCODE_NON_WORD_BOUNDARY) + match = !match; + + action = match ? ACTION_CONTINUE : ACTION_KILL; + fiber->ip += 1; + break; + + case RE_OPCODE_MATCH_AT_START: + if (flags & RE_FLAGS_BACKWARDS) + kill = input_backwards_size > (size_t) bytes_matched; + else + kill = input_backwards_size > 0 || (bytes_matched != 0); + action = kill ? ACTION_KILL : ACTION_CONTINUE; + fiber->ip += 1; + break; + + case RE_OPCODE_MATCH_AT_END: + kill = flags & RE_FLAGS_BACKWARDS || + input_forwards_size > (size_t) bytes_matched; + action = kill ? ACTION_KILL : ACTION_CONTINUE; + fiber->ip += 1; + break; + + case RE_OPCODE_MATCH: + + if (matches != NULL) + *matches = bytes_matched; + + if (flags & RE_FLAGS_EXHAUSTIVE) + { + if (callback != NULL) + { + if (flags & RE_FLAGS_BACKWARDS) + { + FAIL_ON_ERROR_WITH_CLEANUP( + callback( + input + character_size, + bytes_matched, + flags, + callback_args), + _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); + } + else + { + FAIL_ON_ERROR_WITH_CLEANUP( + callback( + input_data, + bytes_matched, + flags, + callback_args), + _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); + } + } + + action = ACTION_KILL; + } + else + { + action = ACTION_KILL_TAIL; + } + + break; + + default: + assert(FALSE); + } + + switch (action) + { + case ACTION_KILL: + fiber = _yr_re_fiber_kill(&fibers, &context->re_fiber_pool, fiber); + break; + + case ACTION_KILL_TAIL: + _yr_re_fiber_kill_tail(&fibers, &context->re_fiber_pool, fiber); + fiber = NULL; + break; + + case ACTION_CONTINUE: + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), + _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); + break; + + default: + next_fiber = fiber->next; + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), + _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); + fiber = next_fiber; + } + } + + input += input_incr; + bytes_matched += character_size; + + if (flags & RE_FLAGS_SCAN && bytes_matched < max_bytes_matched) + { + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_re_fiber_create(&context->re_fiber_pool, &fiber), + _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); + + fiber->ip = code; + _yr_re_fiber_append(&fibers, fiber); + + FAIL_ON_ERROR_WITH_CLEANUP( + _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), + _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); + } + } + + return ERROR_SUCCESS; +} + +// +// yr_re_fast_exec +// +// This function replaces yr_re_exec for regular expressions marked with flag +// RE_FLAGS_FAST_REGEXP. These are regular expression whose code contain only +// the following operations: RE_OPCODE_LITERAL, RE_OPCODE_MASKED_LITERAL, +// RE_OPCODE_ANY, RE_OPCODE_REPEAT_ANY_UNGREEDY and RE_OPCODE_MATCH. Some +// examples of regular expressions that can be executed with this function are: +// +// /foobar/ +// /foo.*?bar/ +// + +int yr_re_fast_exec( + YR_SCAN_CONTEXT* context, + const uint8_t* code, + const uint8_t* input_data, + size_t input_forwards_size, + size_t input_backwards_size, + int flags, + RE_MATCH_CALLBACK_FUNC callback, + void* callback_args, + int* matches) +{ + RE_REPEAT_ANY_ARGS* repeat_any_args; + + const uint8_t* code_stack[MAX_FAST_RE_STACK]; + const uint8_t* input_stack[MAX_FAST_RE_STACK]; + int matches_stack[MAX_FAST_RE_STACK]; + + const uint8_t* input = input_data; + const uint8_t* next_input; + const uint8_t* ip = code; + const uint8_t* next_opcode; + + uint8_t mask; + uint8_t value; + + int i; + int stop; + int input_incr; + int sp = 0; + int bytes_matched; + int max_bytes_matched; + + max_bytes_matched = flags & RE_FLAGS_BACKWARDS ? + (int) input_backwards_size : + (int) input_forwards_size; + + input_incr = flags & RE_FLAGS_BACKWARDS ? -1 : 1; + + if (flags & RE_FLAGS_BACKWARDS) + input--; + + code_stack[sp] = code; + input_stack[sp] = input; + matches_stack[sp] = 0; + sp++; + + while (sp > 0) + { + sp--; + ip = code_stack[sp]; + input = input_stack[sp]; + bytes_matched = matches_stack[sp]; + stop = FALSE; + + while (!stop) + { + if (*ip == RE_OPCODE_MATCH) + { + if (flags & RE_FLAGS_EXHAUSTIVE) + { + FAIL_ON_ERROR(callback( + flags & RE_FLAGS_BACKWARDS ? input + 1 : input_data, + bytes_matched, + flags, + callback_args)); + + break; + } + else + { + if (matches != NULL) + *matches = bytes_matched; + + return ERROR_SUCCESS; + } + } + + if (bytes_matched >= max_bytes_matched) + break; + + switch (*ip) + { + case RE_OPCODE_LITERAL: + + if (*input == *(ip + 1)) + { + bytes_matched++; + input += input_incr; + ip += 2; + } + else + { + stop = TRUE; + } + + break; + + case RE_OPCODE_MASKED_LITERAL: + + value = *(int16_t*)(ip + 1) & 0xFF; + mask = *(int16_t*)(ip + 1) >> 8; + + if ((*input & mask) == value) + { + bytes_matched++; + input += input_incr; + ip += 3; + } + else + { + stop = TRUE; + } + + break; + + case RE_OPCODE_ANY: + + bytes_matched++; + input += input_incr; + ip += 1; + + break; + + case RE_OPCODE_REPEAT_ANY_UNGREEDY: + + repeat_any_args = (RE_REPEAT_ANY_ARGS*)(ip + 1); + next_opcode = ip + 1 + sizeof(RE_REPEAT_ANY_ARGS); + + for (i = repeat_any_args->min + 1; i <= repeat_any_args->max; i++) + { + if (bytes_matched + i >= max_bytes_matched) + break; + + next_input = input + i * input_incr; + + if ( *(next_opcode) != RE_OPCODE_LITERAL || + (*(next_opcode) == RE_OPCODE_LITERAL && + *(next_opcode + 1) == *next_input)) + { + if (sp >= MAX_FAST_RE_STACK) + return ERROR_TOO_MANY_RE_FIBERS; + + code_stack[sp] = next_opcode; + input_stack[sp] = next_input; + matches_stack[sp] = bytes_matched + i; + sp++; + } + } + + input += input_incr * repeat_any_args->min; + bytes_matched += repeat_any_args->min; + bytes_matched = yr_min(bytes_matched, max_bytes_matched); + ip = next_opcode; + + break; + + default: + assert(FALSE); + } + } + } + + if (matches != NULL) + *matches = -1; + + return ERROR_SUCCESS; +} + + +static void _yr_re_print_node( + RE_NODE* re_node) +{ + int i; + + if (re_node == NULL) + return; + + switch (re_node->type) + { + case RE_NODE_ALT: + printf("Alt("); + _yr_re_print_node(re_node->left); + printf(", "); + _yr_re_print_node(re_node->right); + printf(")"); + break; + + case RE_NODE_CONCAT: + printf("Cat("); + _yr_re_print_node(re_node->left); + printf(", "); + _yr_re_print_node(re_node->right); + printf(")"); + break; + + case RE_NODE_STAR: + printf("Star("); + _yr_re_print_node(re_node->left); + printf(")"); + break; + + case RE_NODE_PLUS: + printf("Plus("); + _yr_re_print_node(re_node->left); + printf(")"); + break; + + case RE_NODE_LITERAL: + printf("Lit(%02X)", re_node->value); + break; + + case RE_NODE_MASKED_LITERAL: + printf("MaskedLit(%02X,%02X)", re_node->value, re_node->mask); + break; + + case RE_NODE_WORD_CHAR: + printf("WordChar"); + break; + + case RE_NODE_NON_WORD_CHAR: + printf("NonWordChar"); + break; + + case RE_NODE_SPACE: + printf("Space"); + break; + + case RE_NODE_NON_SPACE: + printf("NonSpace"); + break; + + case RE_NODE_DIGIT: + printf("Digit"); + break; + + case RE_NODE_NON_DIGIT: + printf("NonDigit"); + break; + + case RE_NODE_ANY: + printf("Any"); + break; + + case RE_NODE_RANGE: + printf("Range(%d-%d, ", re_node->start, re_node->end); + _yr_re_print_node(re_node->left); + printf(")"); + break; + + case RE_NODE_CLASS: + printf("Class("); + for (i = 0; i < 256; i++) + if (_yr_re_is_char_in_class(re_node->re_class, i, FALSE)) + printf("%02X,", i); + printf(")"); + break; + + default: + printf("???"); + break; + } +} + +void yr_re_print( + RE_AST* re_ast) +{ + _yr_re_print_node(re_ast->root_node); +} diff --git a/yara-master/libyara/re_grammar.c b/yara-master/libyara/re_grammar.c new file mode 100644 index 0000000..674acc0 --- /dev/null +++ b/yara-master/libyara/re_grammar.c @@ -0,0 +1,1995 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse re_yyparse +#define yylex re_yylex +#define yyerror re_yyerror +#define yydebug re_yydebug +#define yynerrs re_yynerrs + + +/* Copy the first part of user declarations. */ +#line 30 "re_grammar.y" /* yacc.c:339 */ + + +#include +#include +#include +#include +#include +#include +#include + + +#define YYERROR_VERBOSE + +#define YYMALLOC yr_malloc +#define YYFREE yr_free + +#define mark_as_not_fast_regexp() \ + ((RE_AST*) yyget_extra(yyscanner))->flags &= ~RE_FLAGS_FAST_REGEXP + +#define fail_if_too_many_ast_levels(cleanup_code) \ + if (((RE_AST*) yyget_extra(yyscanner))->levels++ > RE_MAX_AST_LEVELS) \ + { \ + { cleanup_code } \ + yyerror(yyscanner, lex_env, "regexp too long"); \ + YYABORT; \ + } + +#define fail_if(x, error) \ + if (x) \ + { \ + lex_env->last_error_code = error; \ + YYABORT; \ + } \ + +#define destroy_node_if(x, node) \ + if (x) \ + { \ + yr_re_node_destroy(node); \ + } \ + + +#line 114 "re_grammar.c" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "y.tab.h". */ +#ifndef YY_RE_YY_RE_GRAMMAR_H_INCLUDED +# define YY_RE_YY_RE_GRAMMAR_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int re_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + _CHAR_ = 258, + _ANY_ = 259, + _RANGE_ = 260, + _CLASS_ = 261, + _WORD_CHAR_ = 262, + _NON_WORD_CHAR_ = 263, + _SPACE_ = 264, + _NON_SPACE_ = 265, + _DIGIT_ = 266, + _NON_DIGIT_ = 267, + _WORD_BOUNDARY_ = 268, + _NON_WORD_BOUNDARY_ = 269 + }; +#endif +/* Tokens. */ +#define _CHAR_ 258 +#define _ANY_ 259 +#define _RANGE_ 260 +#define _CLASS_ 261 +#define _WORD_CHAR_ 262 +#define _NON_WORD_CHAR_ 263 +#define _SPACE_ 264 +#define _NON_SPACE_ 265 +#define _DIGIT_ 266 +#define _NON_DIGIT_ 267 +#define _WORD_BOUNDARY_ 268 +#define _NON_WORD_BOUNDARY_ 269 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 81 "re_grammar.y" /* yacc.c:355 */ + + int integer; + uint32_t range; + RE_NODE* re_node; + RE_CLASS* re_class; + +#line 189 "re_grammar.c" /* yacc.c:355 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int re_yyparse (void *yyscanner, RE_LEX_ENVIRONMENT *lex_env); + +#endif /* !YY_RE_YY_RE_GRAMMAR_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + +#line 205 "re_grammar.c" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 22 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 45 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 24 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 6 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 31 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 35 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 269 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 20, 2, 2, 2, + 21, 22, 16, 18, 2, 2, 23, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 17, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 19, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 112, 112, 117, 121, 125, 141, 163, 167, 184, + 198, 214, 228, 244, 267, 291, 313, 336, 340, 346, + 352, 358, 367, 375, 381, 389, 395, 401, 407, 413, + 419, 425 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "_CHAR_", "_ANY_", "_RANGE_", "_CLASS_", + "_WORD_CHAR_", "_NON_WORD_CHAR_", "_SPACE_", "_NON_SPACE_", "_DIGIT_", + "_NON_DIGIT_", "_WORD_BOUNDARY_", "_NON_WORD_BOUNDARY_", "'|'", "'*'", + "'?'", "'+'", "'^'", "'$'", "'('", "')'", "'.'", "$accept", "re", + "alternative", "concatenation", "repeat", "single", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 124, 42, 63, 43, 94, + 36, 40, 41, 46 +}; +# endif + +#define YYPACT_NINF -12 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-12))) + +#define YYTABLE_NINF -1 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int8 yypact[] = +{ + -1, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, 18, -12, 1, -11, 18, -12, + -2, 21, -12, 18, -12, 0, 16, 17, 23, -12, + 18, -12, -12, -12, -12 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 3, 24, 31, 25, 26, 27, 28, 29, 30, + 18, 19, 20, 21, 0, 23, 0, 2, 4, 7, + 17, 0, 1, 6, 8, 15, 9, 13, 11, 22, + 5, 16, 10, 14, 12 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -12, -12, 28, 22, 5, -12 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 16, 17, 18, 19, 20 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint8 yytable[] = +{ + 1, 22, 2, 25, 23, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 26, 27, 28, 31, 12, 13, + 14, 2, 15, 24, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 32, 33, 24, 23, 12, 13, 14, + 34, 15, 21, 29, 0, 30 +}; + +static const yytype_int8 yycheck[] = +{ + 1, 0, 3, 5, 15, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 16, 17, 18, 17, 19, 20, + 21, 3, 23, 18, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 17, 17, 30, 15, 19, 20, 21, + 17, 23, 14, 22, -1, 23 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 1, 3, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 19, 20, 21, 23, 25, 26, 27, 28, + 29, 26, 0, 15, 28, 5, 16, 17, 18, 22, + 27, 17, 17, 17, 17 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 24, 25, 25, 26, 26, 26, 27, 27, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 1, 3, 2, 1, 2, 2, + 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, + 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (yyscanner, lex_env, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, yyscanner, lex_env); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (yyscanner); + YYUSE (lex_env); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yyscanner, lex_env); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , yyscanner, lex_env); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, yyscanner, lex_env); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) +{ + YYUSE (yyvaluep); + YYUSE (yyscanner); + YYUSE (lex_env); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + switch (yytype) + { + case 6: /* _CLASS_ */ +#line 104 "re_grammar.y" /* yacc.c:1257 */ + { yr_free(((*yyvaluep).re_class)); ((*yyvaluep).re_class) = NULL; } +#line 1053 "re_grammar.c" /* yacc.c:1257 */ + break; + + case 26: /* alternative */ +#line 105 "re_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1059 "re_grammar.c" /* yacc.c:1257 */ + break; + + case 27: /* concatenation */ +#line 106 "re_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1065 "re_grammar.c" /* yacc.c:1257 */ + break; + + case 28: /* repeat */ +#line 107 "re_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1071 "re_grammar.c" /* yacc.c:1257 */ + break; + + case 29: /* single */ +#line 108 "re_grammar.y" /* yacc.c:1257 */ + { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } +#line 1077 "re_grammar.c" /* yacc.c:1257 */ + break; + + + default: + break; + } + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, yyscanner, lex_env); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 113 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->root_node = (yyvsp[0].re_node); + } +#line 1348 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 4: +#line 122 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + } +#line 1356 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 5: +#line 126 "re_grammar.y" /* yacc.c:1646 */ + { + mark_as_not_fast_regexp(); + + fail_if_too_many_ast_levels({ + yr_re_node_destroy((yyvsp[-2].re_node)); + yr_re_node_destroy((yyvsp[0].re_node)); + }); + + (yyval.re_node) = yr_re_node_create(RE_NODE_ALT, (yyvsp[-2].re_node), (yyvsp[0].re_node)); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1376 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 6: +#line 142 "re_grammar.y" /* yacc.c:1646 */ + { + RE_NODE* node; + + mark_as_not_fast_regexp(); + + fail_if_too_many_ast_levels({ + yr_re_node_destroy((yyvsp[-1].re_node)); + }); + + node = yr_re_node_create(RE_NODE_EMPTY, NULL, NULL); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + fail_if(node == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node) = yr_re_node_create(RE_NODE_ALT, (yyvsp[-1].re_node), node); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1399 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 7: +#line 164 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + } +#line 1407 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 8: +#line 168 "re_grammar.y" /* yacc.c:1646 */ + { + fail_if_too_many_ast_levels({ + yr_re_node_destroy((yyvsp[-1].re_node)); + yr_re_node_destroy((yyvsp[0].re_node)); + }); + + (yyval.re_node) = yr_re_node_create(RE_NODE_CONCAT, (yyvsp[-1].re_node), (yyvsp[0].re_node)); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1425 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 9: +#line 185 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast; + + mark_as_not_fast_regexp(); + + re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_GREEDY; + + (yyval.re_node) = yr_re_node_create(RE_NODE_STAR, (yyvsp[-1].re_node), NULL); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1443 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 10: +#line 199 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast; + + mark_as_not_fast_regexp(); + + re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_UNGREEDY; + + (yyval.re_node) = yr_re_node_create(RE_NODE_STAR, (yyvsp[-2].re_node), NULL); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->greedy = FALSE; + } +#line 1463 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 11: +#line 215 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast; + + mark_as_not_fast_regexp(); + + re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_GREEDY; + + (yyval.re_node) = yr_re_node_create(RE_NODE_PLUS, (yyvsp[-1].re_node), NULL); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1481 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 12: +#line 229 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast; + + mark_as_not_fast_regexp(); + + re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_UNGREEDY; + + (yyval.re_node) = yr_re_node_create(RE_NODE_PLUS, (yyvsp[-2].re_node), NULL); + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->greedy = FALSE; + } +#line 1501 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 13: +#line 245 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_GREEDY; + + if ((yyvsp[-1].re_node)->type == RE_NODE_ANY) + { + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + destroy_node_if(TRUE, (yyvsp[-1].re_node)); + } + else + { + mark_as_not_fast_regexp(); + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE, (yyvsp[-1].re_node), NULL); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + } + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->start = 0; + (yyval.re_node)->end = 1; + } +#line 1528 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 14: +#line 268 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_UNGREEDY; + + if ((yyvsp[-2].re_node)->type == RE_NODE_ANY) + { + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + destroy_node_if(TRUE, (yyvsp[-2].re_node)); + } + else + { + mark_as_not_fast_regexp(); + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE, (yyvsp[-2].re_node), NULL); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); + } + + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->start = 0; + (yyval.re_node)->end = 1; + (yyval.re_node)->greedy = FALSE; + } +#line 1556 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 15: +#line 292 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_GREEDY; + + if ((yyvsp[-1].re_node)->type == RE_NODE_ANY) + { + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + destroy_node_if(TRUE, (yyvsp[-1].re_node)); + } + else + { + mark_as_not_fast_regexp(); + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE, (yyvsp[-1].re_node), NULL); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); + } + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->start = (yyvsp[0].range) & 0xFFFF;; + (yyval.re_node)->end = (yyvsp[0].range) >> 16;; + } +#line 1582 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 16: +#line 314 "re_grammar.y" /* yacc.c:1646 */ + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_UNGREEDY; + + if ((yyvsp[-2].re_node)->type == RE_NODE_ANY) + { + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + destroy_node_if(TRUE, (yyvsp[-2].re_node)); + } + else + { + mark_as_not_fast_regexp(); + (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE, (yyvsp[-2].re_node), NULL); + destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); + } + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->start = (yyvsp[-1].range) & 0xFFFF;; + (yyval.re_node)->end = (yyvsp[-1].range) >> 16;; + (yyval.re_node)->greedy = FALSE; + } +#line 1609 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 17: +#line 337 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = (yyvsp[0].re_node); + } +#line 1617 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 18: +#line 341 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_WORD_BOUNDARY, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1627 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 19: +#line 347 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_NON_WORD_BOUNDARY, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1637 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 20: +#line 353 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_ANCHOR_START, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1647 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 21: +#line 359 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_ANCHOR_END, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1657 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 22: +#line 368 "re_grammar.y" /* yacc.c:1646 */ + { + fail_if_too_many_ast_levels({ + yr_re_node_destroy((yyvsp[-1].re_node)); + }); + + (yyval.re_node) = (yyvsp[-1].re_node); + } +#line 1669 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 23: +#line 376 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_ANY, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1679 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 24: +#line 382 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_LITERAL, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->value = (yyvsp[0].integer); + } +#line 1691 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 25: +#line 390 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_WORD_CHAR, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1701 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 26: +#line 396 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_NON_WORD_CHAR, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1711 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 27: +#line 402 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_SPACE, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1721 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 28: +#line 408 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_NON_SPACE, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1731 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 29: +#line 414 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_DIGIT, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1741 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 30: +#line 420 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_NON_DIGIT, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + } +#line 1751 "re_grammar.c" /* yacc.c:1646 */ + break; + + case 31: +#line 426 "re_grammar.y" /* yacc.c:1646 */ + { + (yyval.re_node) = yr_re_node_create(RE_NODE_CLASS, NULL, NULL); + + fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); + + (yyval.re_node)->re_class = (yyvsp[0].re_class); + } +#line 1763 "re_grammar.c" /* yacc.c:1646 */ + break; + + +#line 1767 "re_grammar.c" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (yyscanner, lex_env, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yyscanner, lex_env, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, yyscanner, lex_env); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yyscanner, lex_env); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (yyscanner, lex_env, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, yyscanner, lex_env); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yyscanner, lex_env); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 434 "re_grammar.y" /* yacc.c:1906 */ + diff --git a/yara-master/libyara/re_grammar.h b/yara-master/libyara/re_grammar.h new file mode 100644 index 0000000..c181b44 --- /dev/null +++ b/yara-master/libyara/re_grammar.h @@ -0,0 +1,100 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_RE_YY_RE_GRAMMAR_H_INCLUDED +# define YY_RE_YY_RE_GRAMMAR_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int re_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + _CHAR_ = 258, + _ANY_ = 259, + _RANGE_ = 260, + _CLASS_ = 261, + _WORD_CHAR_ = 262, + _NON_WORD_CHAR_ = 263, + _SPACE_ = 264, + _NON_SPACE_ = 265, + _DIGIT_ = 266, + _NON_DIGIT_ = 267, + _WORD_BOUNDARY_ = 268, + _NON_WORD_BOUNDARY_ = 269 + }; +#endif +/* Tokens. */ +#define _CHAR_ 258 +#define _ANY_ 259 +#define _RANGE_ 260 +#define _CLASS_ 261 +#define _WORD_CHAR_ 262 +#define _NON_WORD_CHAR_ 263 +#define _SPACE_ 264 +#define _NON_SPACE_ 265 +#define _DIGIT_ 266 +#define _NON_DIGIT_ 267 +#define _WORD_BOUNDARY_ 268 +#define _NON_WORD_BOUNDARY_ 269 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 81 "re_grammar.y" /* yacc.c:1909 */ + + int integer; + uint32_t range; + RE_NODE* re_node; + RE_CLASS* re_class; + +#line 89 "re_grammar.h" /* yacc.c:1909 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int re_yyparse (void *yyscanner, RE_LEX_ENVIRONMENT *lex_env); + +#endif /* !YY_RE_YY_RE_GRAMMAR_H_INCLUDED */ diff --git a/yara-master/libyara/re_grammar.y b/yara-master/libyara/re_grammar.y new file mode 100644 index 0000000..77c608a --- /dev/null +++ b/yara-master/libyara/re_grammar.y @@ -0,0 +1,434 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +%{ + +#include +#include +#include +#include +#include +#include +#include + + +#define YYERROR_VERBOSE + +#define YYMALLOC yr_malloc +#define YYFREE yr_free + +#define mark_as_not_fast_regexp() \ + ((RE_AST*) yyget_extra(yyscanner))->flags &= ~RE_FLAGS_FAST_REGEXP + +#define fail_if_too_many_ast_levels(cleanup_code) \ + if (((RE_AST*) yyget_extra(yyscanner))->levels++ > RE_MAX_AST_LEVELS) \ + { \ + { cleanup_code } \ + yyerror(yyscanner, lex_env, "regexp too long"); \ + YYABORT; \ + } + +#define fail_if(x, error) \ + if (x) \ + { \ + lex_env->last_error_code = error; \ + YYABORT; \ + } \ + +#define destroy_node_if(x, node) \ + if (x) \ + { \ + yr_re_node_destroy(node); \ + } \ + +%} + +%name-prefix "re_yy" +%pure-parser + +%parse-param {void *yyscanner} +%parse-param {RE_LEX_ENVIRONMENT *lex_env} + +%lex-param {yyscan_t yyscanner} +%lex-param {RE_LEX_ENVIRONMENT *lex_env} + +%union { + int integer; + uint32_t range; + RE_NODE* re_node; + RE_CLASS* re_class; +} + + +%token _CHAR_ _ANY_ +%token _RANGE_ +%token _CLASS_ + +%token _WORD_CHAR_ +%token _NON_WORD_CHAR_ +%token _SPACE_ +%token _NON_SPACE_ +%token _DIGIT_ +%token _NON_DIGIT_ +%token _WORD_BOUNDARY_ +%token _NON_WORD_BOUNDARY_ + +%type alternative concatenation repeat single + +%destructor { yr_free($$); $$ = NULL; } _CLASS_ +%destructor { yr_re_node_destroy($$); $$ = NULL; } alternative +%destructor { yr_re_node_destroy($$); $$ = NULL; } concatenation +%destructor { yr_re_node_destroy($$); $$ = NULL; } repeat +%destructor { yr_re_node_destroy($$); $$ = NULL; } single + +%% + +re : alternative + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->root_node = $1; + } + | error + ; + +alternative + : concatenation + { + $$ = $1; + } + | alternative '|' concatenation + { + mark_as_not_fast_regexp(); + + fail_if_too_many_ast_levels({ + yr_re_node_destroy($1); + yr_re_node_destroy($3); + }); + + $$ = yr_re_node_create(RE_NODE_ALT, $1, $3); + + destroy_node_if($$ == NULL, $1); + destroy_node_if($$ == NULL, $3); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | alternative '|' + { + RE_NODE* node; + + mark_as_not_fast_regexp(); + + fail_if_too_many_ast_levels({ + yr_re_node_destroy($1); + }); + + node = yr_re_node_create(RE_NODE_EMPTY, NULL, NULL); + + destroy_node_if($$ == NULL, $1); + fail_if(node == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$ = yr_re_node_create(RE_NODE_ALT, $1, node); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + ; + +concatenation + : repeat + { + $$ = $1; + } + | concatenation repeat + { + fail_if_too_many_ast_levels({ + yr_re_node_destroy($1); + yr_re_node_destroy($2); + }); + + $$ = yr_re_node_create(RE_NODE_CONCAT, $1, $2); + + destroy_node_if($$ == NULL, $1); + destroy_node_if($$ == NULL, $2); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + ; + +repeat + : single '*' + { + RE_AST* re_ast; + + mark_as_not_fast_regexp(); + + re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_GREEDY; + + $$ = yr_re_node_create(RE_NODE_STAR, $1, NULL); + + destroy_node_if($$ == NULL, $1); + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | single '*' '?' + { + RE_AST* re_ast; + + mark_as_not_fast_regexp(); + + re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_UNGREEDY; + + $$ = yr_re_node_create(RE_NODE_STAR, $1, NULL); + + destroy_node_if($$ == NULL, $1); + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->greedy = FALSE; + } + | single '+' + { + RE_AST* re_ast; + + mark_as_not_fast_regexp(); + + re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_GREEDY; + + $$ = yr_re_node_create(RE_NODE_PLUS, $1, NULL); + + destroy_node_if($$ == NULL, $1); + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | single '+' '?' + { + RE_AST* re_ast; + + mark_as_not_fast_regexp(); + + re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_UNGREEDY; + + $$ = yr_re_node_create(RE_NODE_PLUS, $1, NULL); + + destroy_node_if($$ == NULL, $1); + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->greedy = FALSE; + } + | single '?' + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_GREEDY; + + if ($1->type == RE_NODE_ANY) + { + $$ = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + destroy_node_if(TRUE, $1); + } + else + { + mark_as_not_fast_regexp(); + $$ = yr_re_node_create(RE_NODE_RANGE, $1, NULL); + destroy_node_if($$ == NULL, $1); + } + + destroy_node_if($$ == NULL, $1); + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->start = 0; + $$->end = 1; + } + | single '?' '?' + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_UNGREEDY; + + if ($1->type == RE_NODE_ANY) + { + $$ = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + destroy_node_if(TRUE, $1); + } + else + { + mark_as_not_fast_regexp(); + $$ = yr_re_node_create(RE_NODE_RANGE, $1, NULL); + destroy_node_if($$ == NULL, $1); + } + + destroy_node_if($$ == NULL, $1); + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->start = 0; + $$->end = 1; + $$->greedy = FALSE; + } + | single _RANGE_ + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_GREEDY; + + if ($1->type == RE_NODE_ANY) + { + $$ = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + destroy_node_if(TRUE, $1); + } + else + { + mark_as_not_fast_regexp(); + $$ = yr_re_node_create(RE_NODE_RANGE, $1, NULL); + destroy_node_if($$ == NULL, $1); + } + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->start = $2 & 0xFFFF;; + $$->end = $2 >> 16;; + } + | single _RANGE_ '?' + { + RE_AST* re_ast = yyget_extra(yyscanner); + re_ast->flags |= RE_FLAGS_UNGREEDY; + + if ($1->type == RE_NODE_ANY) + { + $$ = yr_re_node_create(RE_NODE_RANGE_ANY, NULL, NULL); + destroy_node_if(TRUE, $1); + } + else + { + mark_as_not_fast_regexp(); + $$ = yr_re_node_create(RE_NODE_RANGE, $1, NULL); + destroy_node_if($$ == NULL, $1); + } + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->start = $2 & 0xFFFF;; + $$->end = $2 >> 16;; + $$->greedy = FALSE; + } + | single + { + $$ = $1; + } + | _WORD_BOUNDARY_ + { + $$ = yr_re_node_create(RE_NODE_WORD_BOUNDARY, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | _NON_WORD_BOUNDARY_ + { + $$ = yr_re_node_create(RE_NODE_NON_WORD_BOUNDARY, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | '^' + { + $$ = yr_re_node_create(RE_NODE_ANCHOR_START, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | '$' + { + $$ = yr_re_node_create(RE_NODE_ANCHOR_END, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + ; + +single + : '(' alternative ')' + { + fail_if_too_many_ast_levels({ + yr_re_node_destroy($2); + }); + + $$ = $2; + } + | '.' + { + $$ = yr_re_node_create(RE_NODE_ANY, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | _CHAR_ + { + $$ = yr_re_node_create(RE_NODE_LITERAL, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->value = $1; + } + | _WORD_CHAR_ + { + $$ = yr_re_node_create(RE_NODE_WORD_CHAR, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | _NON_WORD_CHAR_ + { + $$ = yr_re_node_create(RE_NODE_NON_WORD_CHAR, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | _SPACE_ + { + $$ = yr_re_node_create(RE_NODE_SPACE, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | _NON_SPACE_ + { + $$ = yr_re_node_create(RE_NODE_NON_SPACE, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | _DIGIT_ + { + $$ = yr_re_node_create(RE_NODE_DIGIT, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | _NON_DIGIT_ + { + $$ = yr_re_node_create(RE_NODE_NON_DIGIT, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + } + | _CLASS_ + { + $$ = yr_re_node_create(RE_NODE_CLASS, NULL, NULL); + + fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); + + $$->re_class = $1; + } + ; +%% diff --git a/yara-master/libyara/re_lexer.c b/yara-master/libyara/re_lexer.c new file mode 100644 index 0000000..6a12fee --- /dev/null +++ b/yara-master/libyara/re_lexer.c @@ -0,0 +1,2879 @@ +#line 1 "re_lexer.c" + +#line 3 "re_lexer.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define re_yy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer re_yy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define re_yy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer re_yy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define re_yy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer re_yy_scan_buffer +#endif + +#ifdef yy_scan_string +#define re_yy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string re_yy_scan_string +#endif + +#ifdef yy_scan_bytes +#define re_yy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes re_yy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define re_yy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer re_yy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define re_yy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer re_yy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define re_yy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state re_yy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define re_yy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer re_yy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define re_yypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state re_yypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define re_yypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state re_yypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define re_yyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack re_yyensure_buffer_stack +#endif + +#ifdef yylex +#define re_yylex_ALREADY_DEFINED +#else +#define yylex re_yylex +#endif + +#ifdef yyrestart +#define re_yyrestart_ALREADY_DEFINED +#else +#define yyrestart re_yyrestart +#endif + +#ifdef yylex_init +#define re_yylex_init_ALREADY_DEFINED +#else +#define yylex_init re_yylex_init +#endif + +#ifdef yylex_init_extra +#define re_yylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra re_yylex_init_extra +#endif + +#ifdef yylex_destroy +#define re_yylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy re_yylex_destroy +#endif + +#ifdef yyget_debug +#define re_yyget_debug_ALREADY_DEFINED +#else +#define yyget_debug re_yyget_debug +#endif + +#ifdef yyset_debug +#define re_yyset_debug_ALREADY_DEFINED +#else +#define yyset_debug re_yyset_debug +#endif + +#ifdef yyget_extra +#define re_yyget_extra_ALREADY_DEFINED +#else +#define yyget_extra re_yyget_extra +#endif + +#ifdef yyset_extra +#define re_yyset_extra_ALREADY_DEFINED +#else +#define yyset_extra re_yyset_extra +#endif + +#ifdef yyget_in +#define re_yyget_in_ALREADY_DEFINED +#else +#define yyget_in re_yyget_in +#endif + +#ifdef yyset_in +#define re_yyset_in_ALREADY_DEFINED +#else +#define yyset_in re_yyset_in +#endif + +#ifdef yyget_out +#define re_yyget_out_ALREADY_DEFINED +#else +#define yyget_out re_yyget_out +#endif + +#ifdef yyset_out +#define re_yyset_out_ALREADY_DEFINED +#else +#define yyset_out re_yyset_out +#endif + +#ifdef yyget_leng +#define re_yyget_leng_ALREADY_DEFINED +#else +#define yyget_leng re_yyget_leng +#endif + +#ifdef yyget_text +#define re_yyget_text_ALREADY_DEFINED +#else +#define yyget_text re_yyget_text +#endif + +#ifdef yyget_lineno +#define re_yyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno re_yyget_lineno +#endif + +#ifdef yyset_lineno +#define re_yyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno re_yyset_lineno +#endif + +#ifdef yyget_column +#define re_yyget_column_ALREADY_DEFINED +#else +#define yyget_column re_yyget_column +#endif + +#ifdef yyset_column +#define re_yyset_column_ALREADY_DEFINED +#else +#define yyset_column re_yyset_column +#endif + +#ifdef yywrap +#define re_yywrap_ALREADY_DEFINED +#else +#define yywrap re_yywrap +#endif + +#ifdef yyget_lval +#define re_yyget_lval_ALREADY_DEFINED +#else +#define yyget_lval re_yyget_lval +#endif + +#ifdef yyset_lval +#define re_yyset_lval_ALREADY_DEFINED +#else +#define yyset_lval re_yyset_lval +#endif + +#ifdef yyalloc +#define re_yyalloc_ALREADY_DEFINED +#else +#define yyalloc re_yyalloc +#endif + +#ifdef yyrealloc +#define re_yyrealloc_ALREADY_DEFINED +#else +#define yyrealloc re_yyrealloc +#endif + +#ifdef yyfree +#define re_yyfree_ALREADY_DEFINED +#else +#define yyfree re_yyfree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define re_yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 29 +#define YY_END_OF_BUFFER 30 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[45] = + { 0, + 0, 0, 0, 0, 30, 7, 7, 28, 6, 17, + 7, 27, 29, 26, 18, 5, 3, 16, 15, 13, + 11, 9, 14, 12, 10, 8, 0, 0, 0, 0, + 25, 23, 21, 24, 22, 20, 0, 4, 0, 1, + 2, 19, 0, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, + 3, 3, 3, 4, 5, 3, 1, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, + 1, 1, 3, 1, 7, 8, 7, 9, 7, 7, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 10, 1, 1, 1, 11, 1, 1, 1, + 12, 13, 14, 15, 1, 1, 7, 16, 7, 17, + + 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 18, 1, 1, 1, 19, 20, + 1, 1, 21, 3, 22, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[23] = + { 0, + 1, 2, 1, 1, 3, 4, 4, 4, 4, 1, + 1, 1, 1, 5, 1, 4, 4, 1, 1, 1, + 1, 1 + } ; + +static const flex_int16_t yy_base[51] = + { 0, + 0, 20, 3, 5, 50, 89, 89, 89, 10, 36, + 0, 44, 43, 47, 38, 89, 26, 33, 89, 89, + 89, 89, 89, 89, 89, 89, 4, 5, 0, 33, + 32, 31, 29, 26, 24, 23, 15, 89, 8, 89, + 89, 89, 0, 89, 67, 72, 77, 82, 84, 4 + } ; + +static const flex_int16_t yy_def[51] = + { 0, + 45, 45, 46, 46, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 47, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 48, 44, + 44, 44, 44, 44, 44, 44, 49, 44, 44, 44, + 44, 44, 50, 0, 44, 44, 44, 44, 44, 44 + } ; + +static const flex_int16_t yy_nxt[112] = + { 0, + 44, 7, 8, 27, 13, 28, 13, 30, 27, 39, + 28, 9, 10, 39, 8, 14, 15, 14, 15, 29, + 11, 7, 8, 16, 17, 40, 41, 29, 29, 40, + 29, 9, 10, 29, 8, 29, 29, 29, 18, 38, + 11, 18, 29, 19, 20, 21, 22, 29, 29, 44, + 44, 23, 24, 25, 26, 31, 32, 33, 44, 44, + 44, 44, 44, 34, 35, 36, 37, 6, 6, 6, + 6, 6, 12, 12, 12, 12, 12, 30, 44, 30, + 30, 30, 42, 42, 42, 42, 43, 43, 5, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44 + } ; + +static const flex_int16_t yy_chk[112] = + { 0, + 0, 1, 1, 11, 3, 11, 4, 50, 28, 27, + 28, 1, 1, 39, 1, 3, 3, 4, 4, 37, + 1, 2, 2, 9, 9, 27, 28, 36, 35, 39, + 34, 2, 2, 33, 2, 32, 31, 30, 18, 17, + 2, 10, 15, 10, 10, 10, 10, 13, 12, 5, + 0, 10, 10, 10, 10, 14, 14, 14, 0, 0, + 0, 0, 0, 14, 14, 14, 14, 45, 45, 45, + 45, 45, 46, 46, 46, 46, 46, 47, 0, 47, + 47, 47, 48, 48, 48, 48, 49, 49, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44 + } ; + +/* Table of booleans, true if rule could match eol. */ +static const flex_int32_t yy_rule_can_match_eol[30] = + { 0, +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "re_lexer.l" +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ +/* Lexical analyzer for regular expressions */ +#line 33 "re_lexer.l" + +/* Disable warnings for unused functions in this file. + +As we redefine YY_FATAL_ERROR macro to use our own function re_yyfatal, the +yy_fatal_error function generated by Flex is not actually used, causing a +compiler warning. Flex doesn't offer any options to remove the yy_fatal_error +function. When they include something like %option noyy_fatal_error as they do +with noyywrap then we can remove this pragma. +*/ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +static uint8_t word_chars[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, + 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + +int escaped_char_value( + char* text, + uint8_t* value); + +int read_escaped_char( + yyscan_t yyscanner, + uint8_t* escaped_char); + +#line 783 "re_lexer.c" +#define YY_NO_UNISTD_H 1 + +#line 786 "re_lexer.c" + +#define INITIAL 0 +#define char_class 1 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yylval = yylval_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +#line 100 "re_lexer.l" + + +#line 1062 "re_lexer.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 45 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 44 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 102 "re_lexer.l" +{ + + // Examples: {3,8} {0,5} {,5} {7,} + + int hi_bound; + int lo_bound = atoi(yytext + 1); + + char* comma = strchr(yytext, ','); + + if (comma - yytext == strlen(yytext) - 2) + // if comma is followed by the closing curly bracket + // (example: {2,}) set high bound value to maximum. + hi_bound = INT16_MAX; + else + hi_bound = atoi(comma + 1); + + if (hi_bound > INT16_MAX) + { + yyerror(yyscanner, lex_env, "repeat interval too large"); + yyterminate(); + } + + if (hi_bound < lo_bound || hi_bound < 0 || lo_bound < 0) + { + yyerror(yyscanner, lex_env, "bad repeat interval"); + yyterminate(); + } + + if (hi_bound == 0 && lo_bound == 0) + { + yyerror(yyscanner, lex_env, "bad repeat interval"); + yyterminate(); + } + + yylval->range = (hi_bound << 16) | lo_bound; + + return _RANGE_; +} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 142 "re_lexer.l" +{ + + // Example: {10} + + int value = atoi(yytext + 1); + + // atoi can return a negative value if the input string represents a number + // too large to fit in an integer. + + if (value > INT16_MAX || value < 0) + { + yyerror(yyscanner, lex_env, "repeat interval too large"); + yyterminate(); + } + + if (value == 0) + { + yyerror(yyscanner, lex_env, "bad repeat interval"); + yyterminate(); + } + + yylval->range = (value << 16) | value; + + return _RANGE_; +} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 169 "re_lexer.l" +{ + + // Start of a negated character class. Example: [^abcd] + + BEGIN(char_class); + memset(LEX_ENV->re_class.bitmap, 0, 32); + LEX_ENV->re_class.negated = TRUE; +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 178 "re_lexer.l" +{ + + // Start of character negated class containing a ]. + // Example: [^]abc] this must be interpreted as a class + // not matching ], a, b, nor c + + BEGIN(char_class); + memset(LEX_ENV->re_class.bitmap, 0, 32); + LEX_ENV->re_class.negated = TRUE; + LEX_ENV->re_class.bitmap[']' / 8] |= 1 << ']' % 8; +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 191 "re_lexer.l" +{ + + // Start of character class containing a ]. + // Example: []abc] this must be interpreted as a class + // matching ], a, b, or c. + + BEGIN(char_class); + memset(LEX_ENV->re_class.bitmap, 0, 32); + LEX_ENV->re_class.negated = FALSE; + LEX_ENV->re_class.bitmap[']' / 8] |= 1 << ']' % 8; +} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 204 "re_lexer.l" +{ + + // Start of character class. Example: [abcd] + + BEGIN(char_class); + memset(LEX_ENV->re_class.bitmap, 0, 32); + LEX_ENV->re_class.negated = FALSE; +} + YY_BREAK +case 7: +/* rule 7 can match eol */ +YY_RULE_SETUP +#line 214 "re_lexer.l" +{ + + // Any non-special character is passed as a CHAR token to the scanner. + + yylval->integer = yytext[0]; + return _CHAR_; +} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 223 "re_lexer.l" +{ + return _WORD_CHAR_; +} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 228 "re_lexer.l" +{ + return _NON_WORD_CHAR_; +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 233 "re_lexer.l" +{ + return _SPACE_; +} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 238 "re_lexer.l" +{ + return _NON_SPACE_; +} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 243 "re_lexer.l" +{ + return _DIGIT_; +} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 248 "re_lexer.l" +{ + return _NON_DIGIT_; +} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 253 "re_lexer.l" +{ + return _WORD_BOUNDARY_; +} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 257 "re_lexer.l" +{ + return _NON_WORD_BOUNDARY_; +} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 262 "re_lexer.l" +{ + + yyerror(yyscanner, lex_env, "backreferences are not allowed"); + yyterminate(); +} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 269 "re_lexer.l" +{ + + uint8_t c; + + if (read_escaped_char(yyscanner, &c)) + { + yylval->integer = c; + return _CHAR_; + } + else + { + yyerror(yyscanner, lex_env, "illegal escape sequence"); + yyterminate(); + } +} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 286 "re_lexer.l" +{ + + // End of character class. + yylval->re_class = (RE_CLASS*) yr_malloc(sizeof(RE_CLASS)); + memcpy(yylval->re_class->bitmap, LEX_ENV->re_class.bitmap, 32); + + yylval->re_class->negated = LEX_ENV->re_class.negated; + + BEGIN(INITIAL); + return _CLASS_; +} + YY_BREAK +case 19: +/* rule 19 can match eol */ +YY_RULE_SETUP +#line 300 "re_lexer.l" +{ + + // A range inside a character class. + // [abc0-9] + // ^- matching here + + uint16_t c; + uint8_t start = yytext[0]; + uint8_t end = yytext[2]; + + if (start == '\\') + { + if (!escaped_char_value(yytext, &start)) + { + yyerror(yyscanner, lex_env, "illegal escape sequence"); + yyterminate(); + } + + if (yytext[1] == 'x') + end = yytext[5]; + else + end = yytext[3]; + } + + if (end == '\\') + { + if (!read_escaped_char(yyscanner, &end)) + { + yyerror(yyscanner, lex_env, "illegal escape sequence"); + yyterminate(); + } + } + + if (end < start) + { + yyerror(yyscanner, lex_env, "bad character range"); + yyterminate(); + } + + for (c = start; c <= end; c++) + { + LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; + } +} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 346 "re_lexer.l" +{ + + int i; + + for (i = 0; i < 32; i++) + LEX_ENV->re_class.bitmap[i] |= word_chars[i]; +} + YY_BREAK +case 21: +YY_RULE_SETUP +#line 355 "re_lexer.l" +{ + + int i; + + for (i = 0; i < 32; i++) + LEX_ENV->re_class.bitmap[i] |= ~word_chars[i]; +} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 364 "re_lexer.l" +{ + + LEX_ENV->re_class.bitmap[' ' / 8] |= 1 << ' ' % 8; + LEX_ENV->re_class.bitmap['\t' / 8] |= 1 << '\t' % 8; +} + YY_BREAK +case 23: +YY_RULE_SETUP +#line 371 "re_lexer.l" +{ + + int i; + + for (i = 0; i < 32; i++) + { + if (i == ' ' / 8) + LEX_ENV->re_class.bitmap[i] |= ~(1 << ' ' % 8); + else if (i == '\t' / 8) + LEX_ENV->re_class.bitmap[i] |= ~(1 << '\t' % 8); + else + LEX_ENV->re_class.bitmap[i] = 0xFF; + } +} + YY_BREAK +case 24: +YY_RULE_SETUP +#line 387 "re_lexer.l" +{ + + char c; + + for (c = '0'; c <= '9'; c++) + LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; +} + YY_BREAK +case 25: +YY_RULE_SETUP +#line 396 "re_lexer.l" +{ + + int i; + + for (i = 0; i < 32; i++) + { + // digits 0-7 are in the sixth byte of the vector, let that byte alone + if (i == 6) + continue; + + // digits 8 and 9 are the lowest two bits in the seventh byte of the + // vector, let those bits alone. + if (i == 7) + LEX_ENV->re_class.bitmap[i] |= 0xFC; + else + LEX_ENV->re_class.bitmap[i] = 0xFF; + } +} + YY_BREAK +case 26: +YY_RULE_SETUP +#line 416 "re_lexer.l" +{ + + uint8_t c; + + if (read_escaped_char(yyscanner, &c)) + { + LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; + } + else + { + yyerror(yyscanner, lex_env, "illegal escape sequence"); + yyterminate(); + } +} + YY_BREAK +case 27: +YY_RULE_SETUP +#line 432 "re_lexer.l" +{ + + if (yytext[0] >= 32 && yytext[0] < 127) + { + // A character class (i.e: [0-9a-f]) is represented by a 256-bits vector, + // here we set to 1 the vector's bit corresponding to the input character. + + LEX_ENV->re_class.bitmap[yytext[0] / 8] |= 1 << yytext[0] % 8; + } + else + { + yyerror(yyscanner, lex_env, "non-ascii character"); + yyterminate(); + } +} + YY_BREAK +case YY_STATE_EOF(char_class): +#line 449 "re_lexer.l" +{ + + // End of regexp reached while scanning a character class. + + yyerror(yyscanner, lex_env, "missing terminating ] for character class"); + yyterminate(); +} + YY_BREAK +case 28: +YY_RULE_SETUP +#line 458 "re_lexer.l" +{ + + if (yytext[0] >= 32 && yytext[0] < 127) + { + return yytext[0]; + } + else + { + yyerror(yyscanner, lex_env, "non-ascii character"); + yyterminate(); + } +} + YY_BREAK +case YY_STATE_EOF(INITIAL): +#line 472 "re_lexer.l" +{ + + yyterminate(); +} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 477 "re_lexer.l" +ECHO; + YY_BREAK +#line 1569 "re_lexer.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 45 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 45 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 44); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 477 "re_lexer.l" + + +int escaped_char_value( + char* text, + uint8_t* value) +{ + unsigned int hex_value; + char hex[3]; + + assert(text[0] == '\\'); + + switch(text[1]) + { + case 'x': + if (!isxdigit(text[2]) || !isxdigit(text[3])) + return 0; + hex[0] = text[2]; + hex[1] = text[3]; + hex[2] = '\0'; + sscanf(hex, "%x", &hex_value); + *value = (uint8_t) hex_value; + break; + + case 'n': + *value = '\n'; + break; + + case 't': + *value = '\t'; + break; + + case 'r': + *value = '\r'; + break; + + case 'f': + *value = '\f'; + break; + + case 'a': + *value = '\a'; + break; + + default: + *value = text[1]; + } + + return 1; +} + + +#ifdef __cplusplus +#define RE_YY_INPUT yyinput +#else +#define RE_YY_INPUT input +#endif + + +int read_escaped_char( + yyscan_t yyscanner, + uint8_t* escaped_char) +{ + char text[4] = {0, 0, 0, 0}; + + text[0] = '\\'; + text[1] = RE_YY_INPUT(yyscanner); + + if (text[1] == EOF || text[1] == 0) + return 0; + + if (text[1] == 'x') + { + text[2] = RE_YY_INPUT(yyscanner); + + if (text[2] == EOF || text[2] == 0) + return 0; + + text[3] = RE_YY_INPUT(yyscanner); + + if (text[3] == EOF || text[3] == 0) + return 0; + } + + return escaped_char_value(text, escaped_char); +} + + +void yyfatal( + yyscan_t yyscanner, + const char *error_message) +{ + jmp_buf* recovery_state = (jmp_buf*) yr_thread_storage_get_value( + &yr_recovery_state_key); + + longjmp(*recovery_state, 1); +} + + +void yyerror( + yyscan_t yyscanner, + RE_LEX_ENVIRONMENT* lex_env, + const char *error_message) +{ + // if lex_env->last_error_code was set to some error code before + // don't overwrite it, we are interested in the first error, not in + // subsequent errors like "syntax error, unexpected $end" caused by + // early parser termination. + + if (lex_env->last_error_code == ERROR_SUCCESS) + { + lex_env->last_error_code = ERROR_INVALID_REGULAR_EXPRESSION; + + strlcpy( + lex_env->last_error_message, + error_message, + sizeof(lex_env->last_error_message)); + } +} + + +int yr_parse_re_string( + const char* re_string, + RE_AST** re_ast, + RE_ERROR* error) +{ + yyscan_t yyscanner; + jmp_buf recovery_state; + RE_LEX_ENVIRONMENT lex_env; + + lex_env.last_error_code = ERROR_SUCCESS; + lex_env.last_error_message[0] = '\0'; + + yr_thread_storage_set_value(&yr_recovery_state_key, &recovery_state); + + if (setjmp(recovery_state) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + FAIL_ON_ERROR(yr_re_ast_create(re_ast)); + + yylex_init(&yyscanner); + yyset_extra(*re_ast, yyscanner); + yy_scan_string(re_string, yyscanner); + yyparse(yyscanner, &lex_env); + yylex_destroy(yyscanner); + + if (lex_env.last_error_code != ERROR_SUCCESS) + { + yr_re_ast_destroy(*re_ast); + *re_ast = NULL; + + strlcpy( + error->message, + lex_env.last_error_message, + sizeof(error->message)); + + return lex_env.last_error_code; + } + + return ERROR_SUCCESS; +} + diff --git a/yara-master/libyara/re_lexer.l b/yara-master/libyara/re_lexer.l new file mode 100644 index 0000000..53cdaa3 --- /dev/null +++ b/yara-master/libyara/re_lexer.l @@ -0,0 +1,636 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +/* Lexical analyzer for regular expressions */ + +%{ + +/* Disable warnings for unused functions in this file. + +As we redefine YY_FATAL_ERROR macro to use our own function re_yyfatal, the +yy_fatal_error function generated by Flex is not actually used, causing a +compiler warning. Flex doesn't offer any options to remove the yy_fatal_error +function. When they include something like %option noyy_fatal_error as they do +with noyywrap then we can remove this pragma. +*/ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +static uint8_t word_chars[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, + 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + +int escaped_char_value( + char* text, + uint8_t* value); + +int read_escaped_char( + yyscan_t yyscanner, + uint8_t* escaped_char); + +%} + +%option reentrant bison-bridge +%option noyywrap +%option nounistd +%option nounput +%option never-interactive +%option yylineno +%option prefix="re_yy" + +%option outfile="lex.yy.c" + +%option verbose +%option warn + +%x char_class + +digit [0-9] +hex_digit [0-9a-fA-F] + +%% + +\{{digit}*,{digit}*\} { + + // Examples: {3,8} {0,5} {,5} {7,} + + int hi_bound; + int lo_bound = atoi(yytext + 1); + + char* comma = strchr(yytext, ','); + + if (comma - yytext == strlen(yytext) - 2) + // if comma is followed by the closing curly bracket + // (example: {2,}) set high bound value to maximum. + hi_bound = INT16_MAX; + else + hi_bound = atoi(comma + 1); + + if (hi_bound > INT16_MAX) + { + yyerror(yyscanner, lex_env, "repeat interval too large"); + yyterminate(); + } + + if (hi_bound < lo_bound || hi_bound < 0 || lo_bound < 0) + { + yyerror(yyscanner, lex_env, "bad repeat interval"); + yyterminate(); + } + + if (hi_bound == 0 && lo_bound == 0) + { + yyerror(yyscanner, lex_env, "bad repeat interval"); + yyterminate(); + } + + yylval->range = (hi_bound << 16) | lo_bound; + + return _RANGE_; +} + + +\{{digit}+\} { + + // Example: {10} + + int value = atoi(yytext + 1); + + // atoi can return a negative value if the input string represents a number + // too large to fit in an integer. + + if (value > INT16_MAX || value < 0) + { + yyerror(yyscanner, lex_env, "repeat interval too large"); + yyterminate(); + } + + if (value == 0) + { + yyerror(yyscanner, lex_env, "bad repeat interval"); + yyterminate(); + } + + yylval->range = (value << 16) | value; + + return _RANGE_; +} + + +\[\^ { + + // Start of a negated character class. Example: [^abcd] + + BEGIN(char_class); + memset(LEX_ENV->re_class.bitmap, 0, 32); + LEX_ENV->re_class.negated = TRUE; +} + +\[\^\] { + + // Start of character negated class containing a ]. + // Example: [^]abc] this must be interpreted as a class + // not matching ], a, b, nor c + + BEGIN(char_class); + memset(LEX_ENV->re_class.bitmap, 0, 32); + LEX_ENV->re_class.negated = TRUE; + LEX_ENV->re_class.bitmap[']' / 8] |= 1 << ']' % 8; +} + + +\[\] { + + // Start of character class containing a ]. + // Example: []abc] this must be interpreted as a class + // matching ], a, b, or c. + + BEGIN(char_class); + memset(LEX_ENV->re_class.bitmap, 0, 32); + LEX_ENV->re_class.negated = FALSE; + LEX_ENV->re_class.bitmap[']' / 8] |= 1 << ']' % 8; +} + + +\[ { + + // Start of character class. Example: [abcd] + + BEGIN(char_class); + memset(LEX_ENV->re_class.bitmap, 0, 32); + LEX_ENV->re_class.negated = FALSE; +} + + +[^\\\[\(\)\|\$\.\^\+\*\?] { + + // Any non-special character is passed as a CHAR token to the scanner. + + yylval->integer = yytext[0]; + return _CHAR_; +} + + +\\w { + return _WORD_CHAR_; +} + + +\\W { + return _NON_WORD_CHAR_; +} + + +\\s { + return _SPACE_; +} + + +\\S { + return _NON_SPACE_; +} + + +\\d { + return _DIGIT_; +} + + +\\D { + return _NON_DIGIT_; +} + + +\\b { + return _WORD_BOUNDARY_; +} + +\\B { + return _NON_WORD_BOUNDARY_; +} + + +\\{digit}+ { + + yyerror(yyscanner, lex_env, "backreferences are not allowed"); + yyterminate(); +} + + +\\ { + + uint8_t c; + + if (read_escaped_char(yyscanner, &c)) + { + yylval->integer = c; + return _CHAR_; + } + else + { + yyerror(yyscanner, lex_env, "illegal escape sequence"); + yyterminate(); + } +} + + +\] { + + // End of character class. + yylval->re_class = (RE_CLASS*) yr_malloc(sizeof(RE_CLASS)); + memcpy(yylval->re_class->bitmap, LEX_ENV->re_class.bitmap, 32); + + yylval->re_class->negated = LEX_ENV->re_class.negated; + + BEGIN(INITIAL); + return _CLASS_; +} + + + +(\\x{hex_digit}{2}|\\.|[^\\])\-[^]] { + + // A range inside a character class. + // [abc0-9] + // ^- matching here + + uint16_t c; + uint8_t start = yytext[0]; + uint8_t end = yytext[2]; + + if (start == '\\') + { + if (!escaped_char_value(yytext, &start)) + { + yyerror(yyscanner, lex_env, "illegal escape sequence"); + yyterminate(); + } + + if (yytext[1] == 'x') + end = yytext[5]; + else + end = yytext[3]; + } + + if (end == '\\') + { + if (!read_escaped_char(yyscanner, &end)) + { + yyerror(yyscanner, lex_env, "illegal escape sequence"); + yyterminate(); + } + } + + if (end < start) + { + yyerror(yyscanner, lex_env, "bad character range"); + yyterminate(); + } + + for (c = start; c <= end; c++) + { + LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; + } +} + + +\\w { + + int i; + + for (i = 0; i < 32; i++) + LEX_ENV->re_class.bitmap[i] |= word_chars[i]; +} + + +\\W { + + int i; + + for (i = 0; i < 32; i++) + LEX_ENV->re_class.bitmap[i] |= ~word_chars[i]; +} + + +\\s { + + LEX_ENV->re_class.bitmap[' ' / 8] |= 1 << ' ' % 8; + LEX_ENV->re_class.bitmap['\t' / 8] |= 1 << '\t' % 8; +} + + +\\S { + + int i; + + for (i = 0; i < 32; i++) + { + if (i == ' ' / 8) + LEX_ENV->re_class.bitmap[i] |= ~(1 << ' ' % 8); + else if (i == '\t' / 8) + LEX_ENV->re_class.bitmap[i] |= ~(1 << '\t' % 8); + else + LEX_ENV->re_class.bitmap[i] = 0xFF; + } +} + + +\\d { + + char c; + + for (c = '0'; c <= '9'; c++) + LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; +} + + +\\D { + + int i; + + for (i = 0; i < 32; i++) + { + // digits 0-7 are in the sixth byte of the vector, let that byte alone + if (i == 6) + continue; + + // digits 8 and 9 are the lowest two bits in the seventh byte of the + // vector, let those bits alone. + if (i == 7) + LEX_ENV->re_class.bitmap[i] |= 0xFC; + else + LEX_ENV->re_class.bitmap[i] = 0xFF; + } +} + + +\\ { + + uint8_t c; + + if (read_escaped_char(yyscanner, &c)) + { + LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; + } + else + { + yyerror(yyscanner, lex_env, "illegal escape sequence"); + yyterminate(); + } +} + + +. { + + if (yytext[0] >= 32 && yytext[0] < 127) + { + // A character class (i.e: [0-9a-f]) is represented by a 256-bits vector, + // here we set to 1 the vector's bit corresponding to the input character. + + LEX_ENV->re_class.bitmap[yytext[0] / 8] |= 1 << yytext[0] % 8; + } + else + { + yyerror(yyscanner, lex_env, "non-ascii character"); + yyterminate(); + } +} + + +<> { + + // End of regexp reached while scanning a character class. + + yyerror(yyscanner, lex_env, "missing terminating ] for character class"); + yyterminate(); +} + + +. { + + if (yytext[0] >= 32 && yytext[0] < 127) + { + return yytext[0]; + } + else + { + yyerror(yyscanner, lex_env, "non-ascii character"); + yyterminate(); + } +} + + +<> { + + yyterminate(); +} + +%% + +int escaped_char_value( + char* text, + uint8_t* value) +{ + unsigned int hex_value; + char hex[3]; + + assert(text[0] == '\\'); + + switch(text[1]) + { + case 'x': + if (!isxdigit(text[2]) || !isxdigit(text[3])) + return 0; + hex[0] = text[2]; + hex[1] = text[3]; + hex[2] = '\0'; + sscanf(hex, "%x", &hex_value); + *value = (uint8_t) hex_value; + break; + + case 'n': + *value = '\n'; + break; + + case 't': + *value = '\t'; + break; + + case 'r': + *value = '\r'; + break; + + case 'f': + *value = '\f'; + break; + + case 'a': + *value = '\a'; + break; + + default: + *value = text[1]; + } + + return 1; +} + + +#ifdef __cplusplus +#define RE_YY_INPUT yyinput +#else +#define RE_YY_INPUT input +#endif + + +int read_escaped_char( + yyscan_t yyscanner, + uint8_t* escaped_char) +{ + char text[4] = {0, 0, 0, 0}; + + text[0] = '\\'; + text[1] = RE_YY_INPUT(yyscanner); + + if (text[1] == EOF || text[1] == 0) + return 0; + + if (text[1] == 'x') + { + text[2] = RE_YY_INPUT(yyscanner); + + if (text[2] == EOF || text[2] == 0) + return 0; + + text[3] = RE_YY_INPUT(yyscanner); + + if (text[3] == EOF || text[3] == 0) + return 0; + } + + return escaped_char_value(text, escaped_char); +} + + +void yyfatal( + yyscan_t yyscanner, + const char *error_message) +{ + jmp_buf* recovery_state = (jmp_buf*) yr_thread_storage_get_value( + &yr_recovery_state_key); + + longjmp(*recovery_state, 1); +} + + +void yyerror( + yyscan_t yyscanner, + RE_LEX_ENVIRONMENT* lex_env, + const char *error_message) +{ + // if lex_env->last_error_code was set to some error code before + // don't overwrite it, we are interested in the first error, not in + // subsequent errors like "syntax error, unexpected $end" caused by + // early parser termination. + + if (lex_env->last_error_code == ERROR_SUCCESS) + { + lex_env->last_error_code = ERROR_INVALID_REGULAR_EXPRESSION; + + strlcpy( + lex_env->last_error_message, + error_message, + sizeof(lex_env->last_error_message)); + } +} + + +int yr_parse_re_string( + const char* re_string, + RE_AST** re_ast, + RE_ERROR* error) +{ + yyscan_t yyscanner; + jmp_buf recovery_state; + RE_LEX_ENVIRONMENT lex_env; + + lex_env.last_error_code = ERROR_SUCCESS; + lex_env.last_error_message[0] = '\0'; + + yr_thread_storage_set_value(&yr_recovery_state_key, &recovery_state); + + if (setjmp(recovery_state) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + FAIL_ON_ERROR(yr_re_ast_create(re_ast)); + + yylex_init(&yyscanner); + yyset_extra(*re_ast, yyscanner); + yy_scan_string(re_string, yyscanner); + yyparse(yyscanner, &lex_env); + yylex_destroy(yyscanner); + + if (lex_env.last_error_code != ERROR_SUCCESS) + { + yr_re_ast_destroy(*re_ast); + *re_ast = NULL; + + strlcpy( + error->message, + lex_env.last_error_message, + sizeof(error->message)); + + return lex_env.last_error_code; + } + + return ERROR_SUCCESS; +} diff --git a/yara-master/libyara/rules.c b/yara-master/libyara/rules.c new file mode 100644 index 0000000..db11793 --- /dev/null +++ b/yara-master/libyara/rules.c @@ -0,0 +1,494 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +YR_API int yr_rules_define_integer_variable( + YR_RULES* rules, + const char* identifier, + int64_t value) +{ + YR_EXTERNAL_VARIABLE* external; + + external = rules->externals_list_head; + + while (!EXTERNAL_VARIABLE_IS_NULL(external)) + { + if (strcmp(external->identifier, identifier) == 0) + { + if (external->type != EXTERNAL_VARIABLE_TYPE_INTEGER) + return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; + + external->value.i = value; + return ERROR_SUCCESS; + } + + external++; + } + + return ERROR_INVALID_ARGUMENT; +} + + +YR_API int yr_rules_define_boolean_variable( + YR_RULES* rules, + const char* identifier, + int value) +{ + YR_EXTERNAL_VARIABLE* external; + + external = rules->externals_list_head; + + while (!EXTERNAL_VARIABLE_IS_NULL(external)) + { + if (strcmp(external->identifier, identifier) == 0) + { + if (external->type != EXTERNAL_VARIABLE_TYPE_BOOLEAN) + return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; + + external->value.i = value; + return ERROR_SUCCESS; + } + + external++; + } + + return ERROR_INVALID_ARGUMENT; +} + + +YR_API int yr_rules_define_float_variable( + YR_RULES* rules, + const char* identifier, + double value) +{ + YR_EXTERNAL_VARIABLE* external; + + external = rules->externals_list_head; + + while (!EXTERNAL_VARIABLE_IS_NULL(external)) + { + if (strcmp(external->identifier, identifier) == 0) + { + if (external->type != EXTERNAL_VARIABLE_TYPE_FLOAT) + return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; + + external->value.f = value; + return ERROR_SUCCESS; + } + + external++; + } + + return ERROR_INVALID_ARGUMENT; +} + + +YR_API int yr_rules_define_string_variable( + YR_RULES* rules, + const char* identifier, + const char* value) +{ + YR_EXTERNAL_VARIABLE* external; + + external = rules->externals_list_head; + + while (!EXTERNAL_VARIABLE_IS_NULL(external)) + { + if (strcmp(external->identifier, identifier) == 0) + { + if (external->type != EXTERNAL_VARIABLE_TYPE_STRING && + external->type != EXTERNAL_VARIABLE_TYPE_MALLOC_STRING) + return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; + + if (external->type == EXTERNAL_VARIABLE_TYPE_MALLOC_STRING && + external->value.s != NULL) + { + yr_free(external->value.s); + } + + external->type = EXTERNAL_VARIABLE_TYPE_MALLOC_STRING; + external->value.s = yr_strdup(value); + + if (external->value.s == NULL) + return ERROR_INSUFFICIENT_MEMORY; + else + return ERROR_SUCCESS; + } + + external++; + } + + return ERROR_INVALID_ARGUMENT; +} + + +#ifdef PROFILING_ENABLED +void yr_rules_print_profiling_info( + YR_RULES* rules) +{ + YR_RULE* rule; + + printf("\n===== PROFILING INFORMATION =====\n\n"); + + yr_rules_foreach(rules, rule) + { + printf( + "%s:%s: %" PRIu64 " (%0.3f%%)\n", + rule->ns->name, + rule->identifier, + rule->time_cost, + (float) rule->time_cost / rules->time_cost * 100); + } + + printf("\n=================================\n"); +} +#endif + + +YR_API int yr_rules_scan_mem_blocks( + YR_RULES* rules, + YR_MEMORY_BLOCK_ITERATOR* iterator, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout) +{ + YR_SCANNER* scanner; + int result; + + FAIL_ON_ERROR(yr_scanner_create(rules, &scanner)); + + yr_scanner_set_callback(scanner, callback, user_data); + yr_scanner_set_timeout(scanner, timeout); + yr_scanner_set_flags(scanner, flags); + + result = yr_scanner_scan_mem_blocks(scanner, iterator); + + yr_scanner_destroy(scanner); + + return result; +} + + +static YR_MEMORY_BLOCK* _yr_get_first_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + return (YR_MEMORY_BLOCK*) iterator->context; +} + + +static YR_MEMORY_BLOCK* _yr_get_next_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + return NULL; +} + + +static const uint8_t* _yr_fetch_block_data( + YR_MEMORY_BLOCK* block) +{ + return (const uint8_t*) block->context; +} + + +YR_API int yr_rules_scan_mem( + YR_RULES* rules, + const uint8_t* buffer, + size_t buffer_size, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout) +{ + YR_MEMORY_BLOCK block; + YR_MEMORY_BLOCK_ITERATOR iterator; + + block.size = buffer_size; + block.base = 0; + block.fetch_data = _yr_fetch_block_data; + block.context = (void*) buffer; + + iterator.context = █ + iterator.first = _yr_get_first_block; + iterator.next = _yr_get_next_block; + + return yr_rules_scan_mem_blocks( + rules, + &iterator, + flags, + callback, + user_data, + timeout); +} + + +YR_API int yr_rules_scan_file( + YR_RULES* rules, + const char* filename, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout) +{ + YR_MAPPED_FILE mfile; + + int result = yr_filemap_map(filename, &mfile); + + if (result == ERROR_SUCCESS) + { + result = yr_rules_scan_mem( + rules, + mfile.data, + mfile.size, + flags, + callback, + user_data, + timeout); + + yr_filemap_unmap(&mfile); + } + + return result; +} + + +YR_API int yr_rules_scan_fd( + YR_RULES* rules, + YR_FILE_DESCRIPTOR fd, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout) +{ + YR_MAPPED_FILE mfile; + + int result = yr_filemap_map_fd(fd, 0, 0, &mfile); + + if (result == ERROR_SUCCESS) + { + result = yr_rules_scan_mem( + rules, + mfile.data, + mfile.size, + flags, + callback, + user_data, + timeout); + + yr_filemap_unmap_fd(&mfile); + } + + return result; +} + + +YR_API int yr_rules_scan_proc( + YR_RULES* rules, + int pid, + int flags, + YR_CALLBACK_FUNC callback, + void* user_data, + int timeout) +{ + YR_MEMORY_BLOCK_ITERATOR iterator; + + int result = yr_process_open_iterator( + pid, + &iterator); + + if (result == ERROR_SUCCESS) + { + result = yr_rules_scan_mem_blocks( + rules, + &iterator, + flags | SCAN_FLAGS_PROCESS_MEMORY, + callback, + user_data, + timeout); + + yr_process_close_iterator(&iterator); + } + + return result; +} + + +YR_API int yr_rules_load_stream( + YR_STREAM* stream, + YR_RULES** rules) +{ + YARA_RULES_FILE_HEADER* header; + YR_RULES* new_rules = (YR_RULES*) yr_malloc(sizeof(YR_RULES)); + + if (new_rules == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_arena_load_stream(stream, &new_rules->arena), + // cleanup + yr_free(new_rules)); + + header = (YARA_RULES_FILE_HEADER*) + yr_arena_base_address(new_rules->arena); + + new_rules->code_start = header->code_start; + new_rules->externals_list_head = header->externals_list_head; + new_rules->rules_list_head = header->rules_list_head; + new_rules->match_table = header->match_table; + new_rules->transition_table = header->transition_table; + memset(new_rules->tidx_mask, 0, sizeof(new_rules->tidx_mask)); + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_mutex_create(&new_rules->mutex), + // cleanup + yr_free(new_rules)); + + *rules = new_rules; + + return ERROR_SUCCESS; +} + + +YR_API int yr_rules_load( + const char* filename, + YR_RULES** rules) +{ + int result; + + YR_STREAM stream; + FILE* fh = fopen(filename, "rb"); + + if (fh == NULL) + return ERROR_COULD_NOT_OPEN_FILE; + + stream.user_data = fh; + stream.read = (YR_STREAM_READ_FUNC) fread; + + result = yr_rules_load_stream(&stream, rules); + + fclose(fh); + return result; +} + + +YR_API int yr_rules_save_stream( + YR_RULES* rules, + YR_STREAM* stream) +{ + int i; + + for (i = 0; i < YR_BITARRAY_NCHARS(MAX_THREADS); ++i) + assert(rules->tidx_mask[i] == 0); + + return yr_arena_save_stream(rules->arena, stream); +} + + +YR_API int yr_rules_save( + YR_RULES* rules, + const char* filename) +{ + int result; + + YR_STREAM stream; + FILE* fh = fopen(filename, "wb"); + + if (fh == NULL) + return ERROR_COULD_NOT_OPEN_FILE; + + stream.user_data = fh; + stream.write = (YR_STREAM_WRITE_FUNC) fwrite; + + result = yr_rules_save_stream(rules, &stream); + + fclose(fh); + return result; +} + + +YR_API int yr_rules_destroy( + YR_RULES* rules) +{ + YR_EXTERNAL_VARIABLE* external = rules->externals_list_head; + + while (!EXTERNAL_VARIABLE_IS_NULL(external)) + { + if (external->type == EXTERNAL_VARIABLE_TYPE_MALLOC_STRING) + yr_free(external->value.s); + + external++; + } + + yr_mutex_destroy(&rules->mutex); + yr_arena_destroy(rules->arena); + yr_free(rules); + + return ERROR_SUCCESS; +} + +YR_API void yr_rule_disable( + YR_RULE* rule) +{ + YR_STRING* string; + + rule->g_flags |= RULE_GFLAGS_DISABLED; + + yr_rule_strings_foreach(rule, string) + { + string->g_flags |= STRING_GFLAGS_DISABLED; + } +} + + +YR_API void yr_rule_enable( + YR_RULE* rule) +{ + YR_STRING* string; + + rule->g_flags &= ~RULE_GFLAGS_DISABLED; + + yr_rule_strings_foreach(rule, string) + { + string->g_flags &= ~STRING_GFLAGS_DISABLED; + } +} diff --git a/yara-master/libyara/scan.c b/yara-master/libyara/scan.c new file mode 100644 index 0000000..aea2cd1 --- /dev/null +++ b/yara-master/libyara/scan.c @@ -0,0 +1,880 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +typedef struct _CALLBACK_ARGS +{ + YR_STRING* string; + YR_SCAN_CONTEXT* context; + + const uint8_t* data; + size_t data_size; + uint64_t data_base; + + int forward_matches; + int full_word; + +} CALLBACK_ARGS; + + +static int _yr_scan_xor_compare( + const uint8_t* data, + size_t data_size, + uint8_t* string, + size_t string_length) +{ + const uint8_t* s1 = data; + const uint8_t* s2 = string; + uint8_t k = 0; + + size_t i = 0; + + if (data_size < string_length) + return 0; + + // Calculate the xor key to compare with. *s1 is the start of the string we + // matched on and *s2 is the "plaintext" string, so *s1 ^ *s2 is the key to + // every *s2 as we compare. + k = *s1 ^ *s2; + + while (i < string_length && *s1++ == ((*s2++) ^ k)) + i++; + + return (int) ((i == string_length) ? i : 0); +} + +static int _yr_scan_xor_wcompare( + const uint8_t* data, + size_t data_size, + uint8_t* string, + size_t string_length) +{ + const uint8_t* s1 = data; + const uint8_t* s2 = string; + uint8_t k = 0; + + size_t i = 0; + + if (data_size < string_length * 2) + return 0; + + // Calculate the xor key to compare with. *s1 is the start of the string we + // matched on and *s2 is the "plaintext" string, so *s1 ^ *s2 is the key to + // every *s2 as we compare. + k = *s1 ^ *s2; + + while (i < string_length && *s1 == ((*s2) ^ k) && ((*(s1 + 1)) ^ k) == 0x00) + { + s1+=2; + s2++; + i++; + } + + return (int) ((i == string_length) ? i * 2 : 0); +} + + +static int _yr_scan_compare( + const uint8_t* data, + size_t data_size, + uint8_t* string, + size_t string_length) +{ + const uint8_t* s1 = data; + const uint8_t* s2 = string; + + size_t i = 0; + + if (data_size < string_length) + return 0; + + while (i < string_length && *s1++ == *s2++) + i++; + + return (int) ((i == string_length) ? i : 0); +} + + +static int _yr_scan_icompare( + const uint8_t* data, + size_t data_size, + uint8_t* string, + size_t string_length) +{ + const uint8_t* s1 = data; + const uint8_t* s2 = string; + + size_t i = 0; + + if (data_size < string_length) + return 0; + + while (i < string_length && yr_lowercase[*s1++] == yr_lowercase[*s2++]) + i++; + + return (int) ((i == string_length) ? i : 0); +} + + +static int _yr_scan_wcompare( + const uint8_t* data, + size_t data_size, + uint8_t* string, + size_t string_length) +{ + const uint8_t* s1 = data; + const uint8_t* s2 = string; + + size_t i = 0; + + if (data_size < string_length * 2) + return 0; + + while (i < string_length && *s1 == *s2 && *(s1 + 1) == 0x00) + { + s1+=2; + s2++; + i++; + } + + return (int) ((i == string_length) ? i * 2 : 0); +} + + +static int _yr_scan_wicompare( + const uint8_t* data, + size_t data_size, + uint8_t* string, + size_t string_length) +{ + const uint8_t* s1 = data; + const uint8_t* s2 = string; + + size_t i = 0; + + if (data_size < string_length * 2) + return 0; + + while (i < string_length && yr_lowercase[*s1] == yr_lowercase[*s2]) + { + s1+=2; + s2++; + i++; + } + + return (int) ((i == string_length) ? i * 2 : 0); +} + + +static void _yr_scan_update_match_chain_length( + int tidx, + YR_STRING* string, + YR_MATCH* match_to_update, + int chain_length) +{ + YR_MATCH* match; + + if (match_to_update->chain_length == chain_length) + return; + + match_to_update->chain_length = chain_length; + + if (string->chained_to == NULL) + return; + + match = string->chained_to->unconfirmed_matches[tidx].head; + + while (match != NULL) + { + int64_t ending_offset = match->offset + match->match_length; + + if (ending_offset + string->chain_gap_max >= match_to_update->offset && + ending_offset + string->chain_gap_min <= match_to_update->offset) + { + _yr_scan_update_match_chain_length( + tidx, string->chained_to, match, chain_length + 1); + } + + match = match->next; + } +} + + +static int _yr_scan_add_match_to_list( + YR_MATCH* match, + YR_MATCHES* matches_list, + int replace_if_exists) +{ + YR_MATCH* insertion_point = matches_list->tail; + + if (matches_list->count == MAX_STRING_MATCHES) + return ERROR_TOO_MANY_MATCHES; + + while (insertion_point != NULL) + { + if (match->offset == insertion_point->offset) + { + if (replace_if_exists) + { + insertion_point->match_length = match->match_length; + insertion_point->data_length = match->data_length; + insertion_point->data = match->data; + } + + return ERROR_SUCCESS; + } + + if (match->offset > insertion_point->offset) + break; + + insertion_point = insertion_point->prev; + } + + match->prev = insertion_point; + + if (insertion_point != NULL) + { + match->next = insertion_point->next; + insertion_point->next = match; + } + else + { + match->next = matches_list->head; + matches_list->head = match; + } + + matches_list->count++; + + if (match->next != NULL) + match->next->prev = match; + else + matches_list->tail = match; + + return ERROR_SUCCESS; +} + + +static void _yr_scan_remove_match_from_list( + YR_MATCH* match, + YR_MATCHES* matches_list) +{ + if (match->prev != NULL) + match->prev->next = match->next; + + if (match->next != NULL) + match->next->prev = match->prev; + + if (matches_list->head == match) + matches_list->head = match->next; + + if (matches_list->tail == match) + matches_list->tail = match->prev; + + matches_list->count--; + match->next = NULL; + match->prev = NULL; +} + + +static int _yr_scan_verify_chained_string_match( + YR_STRING* matching_string, + YR_SCAN_CONTEXT* context, + const uint8_t* match_data, + uint64_t match_base, + uint64_t match_offset, + int32_t match_length) +{ + YR_STRING* string; + YR_MATCH* match; + YR_MATCH* next_match; + YR_MATCH* new_match; + + uint64_t lower_offset; + uint64_t ending_offset; + int32_t full_chain_length; + + int tidx = context->tidx; + int add_match = FALSE; + + if (matching_string->chained_to == NULL) + { + add_match = TRUE; + } + else + { + if (matching_string->unconfirmed_matches[tidx].head != NULL) + lower_offset = matching_string->unconfirmed_matches[tidx].head->offset; + else + lower_offset = match_offset; + + match = matching_string->chained_to->unconfirmed_matches[tidx].head; + + while (match != NULL) + { + next_match = match->next; + ending_offset = match->offset + match->match_length; + + if (ending_offset + matching_string->chain_gap_max < lower_offset) + { + _yr_scan_remove_match_from_list( + match, &matching_string->chained_to->unconfirmed_matches[tidx]); + } + else + { + if (ending_offset + matching_string->chain_gap_max >= match_offset && + ending_offset + matching_string->chain_gap_min <= match_offset) + { + add_match = TRUE; + break; + } + } + + match = next_match; + } + } + + if (add_match) + { + uint32_t max_match_data; + + FAIL_ON_ERROR(yr_get_configuration( + YR_CONFIG_MAX_MATCH_DATA, + &max_match_data)) + + if (STRING_IS_CHAIN_TAIL(matching_string)) + { + // Chain tails must be chained to some other string + assert(matching_string->chained_to != NULL); + + match = matching_string->chained_to->unconfirmed_matches[tidx].head; + + while (match != NULL) + { + ending_offset = match->offset + match->match_length; + + if (ending_offset + matching_string->chain_gap_max >= match_offset && + ending_offset + matching_string->chain_gap_min <= match_offset) + { + _yr_scan_update_match_chain_length( + tidx, matching_string->chained_to, match, 1); + } + + match = match->next; + } + + full_chain_length = 0; + string = matching_string; + + while(string->chained_to != NULL) + { + full_chain_length++; + string = string->chained_to; + } + + // "string" points now to the head of the strings chain + + match = string->unconfirmed_matches[tidx].head; + + while (match != NULL) + { + next_match = match->next; + + if (match->chain_length == full_chain_length) + { + _yr_scan_remove_match_from_list( + match, &string->unconfirmed_matches[tidx]); + + match->match_length = (int32_t) \ + (match_offset - match->offset + match_length); + + match->data_length = yr_min(match->match_length, max_match_data); + + FAIL_ON_ERROR(yr_arena_write_data( + context->matches_arena, + match_data - match_offset + match->offset, + match->data_length, + (void**) &match->data)); + + FAIL_ON_ERROR(_yr_scan_add_match_to_list( + match, &string->matches[tidx], FALSE)); + } + + match = next_match; + } + } + else + { + if (matching_string->matches[tidx].count == 0 && + matching_string->unconfirmed_matches[tidx].count == 0) + { + // If this is the first match for the string, put the string in the + // list of strings whose flags needs to be cleared after the scan. + + FAIL_ON_ERROR(yr_arena_write_data( + context->matching_strings_arena, + &matching_string, + sizeof(matching_string), + NULL)); + } + + FAIL_ON_ERROR(yr_arena_allocate_memory( + context->matches_arena, + sizeof(YR_MATCH), + (void**) &new_match)); + + new_match->data_length = yr_min(match_length, max_match_data); + + if (new_match->data_length > 0) + { + FAIL_ON_ERROR(yr_arena_write_data( + context->matches_arena, + match_data, + new_match->data_length, + (void**) &new_match->data)); + } + else + { + new_match->data = NULL; + } + + new_match->base = match_base; + new_match->offset = match_offset; + new_match->match_length = match_length; + new_match->chain_length = 0; + new_match->prev = NULL; + new_match->next = NULL; + + FAIL_ON_ERROR(_yr_scan_add_match_to_list( + new_match, + &matching_string->unconfirmed_matches[tidx], + FALSE)); + } + } + + return ERROR_SUCCESS; +} + + +static int _yr_scan_match_callback( + const uint8_t* match_data, + int32_t match_length, + int flags, + void* args) +{ + CALLBACK_ARGS* callback_args = (CALLBACK_ARGS*) args; + + YR_STRING* string = callback_args->string; + YR_MATCH* new_match; + + int result = ERROR_SUCCESS; + int tidx = callback_args->context->tidx; + + size_t match_offset = match_data - callback_args->data; + + // total match length is the sum of backward and forward matches. + match_length += callback_args->forward_matches; + + // make sure that match fits into the data. + assert(match_offset + match_length <= callback_args->data_size); + + if (callback_args->full_word) + { + if (flags & RE_FLAGS_WIDE) + { + if (match_offset >= 2 && + *(match_data - 1) == 0 && + isalnum(*(match_data - 2))) + return ERROR_SUCCESS; + + if (match_offset + match_length + 1 < callback_args->data_size && + *(match_data + match_length + 1) == 0 && + isalnum(*(match_data + match_length))) + return ERROR_SUCCESS; + } + else + { + if (match_offset >= 1 && + isalnum(*(match_data - 1))) + return ERROR_SUCCESS; + + if (match_offset + match_length < callback_args->data_size && + isalnum(*(match_data + match_length))) + return ERROR_SUCCESS; + } + } + + if (STRING_IS_CHAIN_PART(string)) + { + result = _yr_scan_verify_chained_string_match( + string, + callback_args->context, + match_data, + callback_args->data_base, + match_offset, + match_length); + } + else + { + uint32_t max_match_data; + + FAIL_ON_ERROR(yr_get_configuration( + YR_CONFIG_MAX_MATCH_DATA, + &max_match_data)) + + if (string->matches[tidx].count == 0) + { + // If this is the first match for the string, put the string in the + // list of strings whose flags needs to be cleared after the scan. + + FAIL_ON_ERROR(yr_arena_write_data( + callback_args->context->matching_strings_arena, + &string, + sizeof(string), + NULL)); + } + + FAIL_ON_ERROR(yr_arena_allocate_memory( + callback_args->context->matches_arena, + sizeof(YR_MATCH), + (void**) &new_match)); + + new_match->data_length = yr_min(match_length, max_match_data); + + if (new_match->data_length > 0) + { + FAIL_ON_ERROR(yr_arena_write_data( + callback_args->context->matches_arena, + match_data, + new_match->data_length, + (void**) &new_match->data)); + } + else + { + new_match->data = NULL; + } + + if (result == ERROR_SUCCESS) + { + new_match->base = callback_args->data_base; + new_match->offset = match_offset; + new_match->match_length = match_length; + new_match->prev = NULL; + new_match->next = NULL; + + FAIL_ON_ERROR(_yr_scan_add_match_to_list( + new_match, + &string->matches[tidx], + STRING_IS_GREEDY_REGEXP(string))); + } + } + + return result; +} + + +typedef int (*RE_EXEC_FUNC)( + YR_SCAN_CONTEXT* context, + const uint8_t* code, + const uint8_t* input, + size_t input_forwards_size, + size_t input_backwards_size, + int flags, + RE_MATCH_CALLBACK_FUNC callback, + void* callback_args, + int* matches); + + +static int _yr_scan_verify_re_match( + YR_SCAN_CONTEXT* context, + YR_AC_MATCH* ac_match, + const uint8_t* data, + size_t data_size, + uint64_t data_base, + size_t offset) +{ + CALLBACK_ARGS callback_args; + RE_EXEC_FUNC exec; + + int forward_matches = -1; + int backward_matches = -1; + int flags = 0; + + if (STRING_IS_GREEDY_REGEXP(ac_match->string)) + flags |= RE_FLAGS_GREEDY; + + if (STRING_IS_NO_CASE(ac_match->string)) + flags |= RE_FLAGS_NO_CASE; + + if (STRING_IS_DOT_ALL(ac_match->string)) + flags |= RE_FLAGS_DOT_ALL; + + if (STRING_IS_FAST_REGEXP(ac_match->string)) + exec = yr_re_fast_exec; + else + exec = yr_re_exec; + + if (STRING_IS_ASCII(ac_match->string)) + { + FAIL_ON_ERROR(exec( + context, + ac_match->forward_code, + data + offset, + data_size - offset, + offset, + flags, + NULL, + NULL, + &forward_matches)); + } + + if (STRING_IS_WIDE(ac_match->string) && forward_matches == -1) + { + flags |= RE_FLAGS_WIDE; + FAIL_ON_ERROR(exec( + context, + ac_match->forward_code, + data + offset, + data_size - offset, + offset, + flags, + NULL, + NULL, + &forward_matches)); + } + + if (forward_matches == -1) + return ERROR_SUCCESS; + + if (forward_matches == 0 && ac_match->backward_code == NULL) + return ERROR_SUCCESS; + + callback_args.string = ac_match->string; + callback_args.context = context; + callback_args.data = data; + callback_args.data_size = data_size; + callback_args.data_base = data_base; + callback_args.forward_matches = forward_matches; + callback_args.full_word = STRING_IS_FULL_WORD(ac_match->string); + + if (ac_match->backward_code != NULL) + { + FAIL_ON_ERROR(exec( + context, + ac_match->backward_code, + data + offset, + data_size - offset, + offset, + flags | RE_FLAGS_BACKWARDS | RE_FLAGS_EXHAUSTIVE, + _yr_scan_match_callback, + (void*) &callback_args, + &backward_matches)); + } + else + { + FAIL_ON_ERROR(_yr_scan_match_callback( + data + offset, 0, flags, &callback_args)); + } + + return ERROR_SUCCESS; +} + + +static int _yr_scan_verify_literal_match( + YR_SCAN_CONTEXT* context, + YR_AC_MATCH* ac_match, + const uint8_t* data, + size_t data_size, + uint64_t data_base, + size_t offset) +{ + int flags = 0; + int forward_matches = 0; + + CALLBACK_ARGS callback_args; + YR_STRING* string = ac_match->string; + + if (STRING_FITS_IN_ATOM(string)) + { + forward_matches = ac_match->backtrack; + } + else if (STRING_IS_NO_CASE(string)) + { + if (STRING_IS_ASCII(string)) + { + forward_matches = _yr_scan_icompare( + data + offset, + data_size - offset, + string->string, + string->length); + } + + if (STRING_IS_WIDE(string) && forward_matches == 0) + { + forward_matches = _yr_scan_wicompare( + data + offset, + data_size - offset, + string->string, + string->length); + } + } + else + { + if (STRING_IS_ASCII(string)) + { + forward_matches = _yr_scan_compare( + data + offset, + data_size - offset, + string->string, + string->length); + } + + if (STRING_IS_WIDE(string) && forward_matches == 0) + { + forward_matches = _yr_scan_wcompare( + data + offset, + data_size - offset, + string->string, + string->length); + } + + if (STRING_IS_XOR(string) && forward_matches == 0) + { + if (STRING_IS_WIDE(string)) + { + forward_matches = _yr_scan_xor_wcompare( + data + offset, + data_size - offset, + string->string, + string->length); + } + + if (forward_matches == 0) + { + forward_matches = _yr_scan_xor_compare( + data + offset, + data_size - offset, + string->string, + string->length); + } + } + + } + + if (forward_matches == 0) + return ERROR_SUCCESS; + + if (forward_matches == string->length * 2) + flags |= RE_FLAGS_WIDE; + + if (STRING_IS_NO_CASE(string)) + flags |= RE_FLAGS_NO_CASE; + + callback_args.context = context; + callback_args.string = string; + callback_args.data = data; + callback_args.data_size = data_size; + callback_args.data_base = data_base; + callback_args.forward_matches = forward_matches; + callback_args.full_word = STRING_IS_FULL_WORD(string); + + FAIL_ON_ERROR(_yr_scan_match_callback( + data + offset, 0, flags, &callback_args)); + + return ERROR_SUCCESS; +} + + +int yr_scan_verify_match( + YR_SCAN_CONTEXT* context, + YR_AC_MATCH* ac_match, + const uint8_t* data, + size_t data_size, + uint64_t data_base, + size_t offset) +{ + YR_STRING* string = ac_match->string; + + int result; + + if (data_size - offset <= 0) + return ERROR_SUCCESS; + + if (STRING_IS_DISABLED(string)) + return ERROR_SUCCESS; + + if (context->flags & SCAN_FLAGS_FAST_MODE && + STRING_IS_SINGLE_MATCH(string) && + string->matches[context->tidx].head != NULL) + return ERROR_SUCCESS; + + if (STRING_IS_FIXED_OFFSET(string) && + string->fixed_offset != data_base + offset) + return ERROR_SUCCESS; + + #ifdef PROFILING_ENABLED + uint64_t start_time = yr_stopwatch_elapsed_us(&context->stopwatch); + #endif + + if (STRING_IS_LITERAL(string)) + { + result = _yr_scan_verify_literal_match( + context, ac_match, data, data_size, data_base, offset); + } + else + { + result = _yr_scan_verify_re_match( + context, ac_match, data, data_size, data_base, offset); + } + + if (result != ERROR_SUCCESS) + context->last_error_string = string; + + #ifdef PROFILING_ENABLED + uint64_t finish_time = yr_stopwatch_elapsed_us(&context->stopwatch); + string->time_cost += (finish_time - start_time); + string->rule->time_cost += (finish_time - start_time); + #endif + + return result; +} diff --git a/yara-master/libyara/scanner.c b/yara-master/libyara/scanner.c new file mode 100644 index 0000000..25ba865 --- /dev/null +++ b/yara-master/libyara/scanner.c @@ -0,0 +1,617 @@ +/* +Copyright (c) 2018. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exception.h" + + +static int _yr_scanner_scan_mem_block( + YR_SCANNER* scanner, + const uint8_t* block_data, + YR_MEMORY_BLOCK* block) +{ + YR_RULES* rules = scanner->rules; + YR_AC_TRANSITION_TABLE transition_table = rules->transition_table; + YR_AC_MATCH_TABLE match_table = rules->match_table; + + YR_AC_MATCH* match; + YR_AC_TRANSITION transition; + + size_t i = 0; + uint32_t state = YR_AC_ROOT_STATE; + uint16_t index; + + while (i < block->size) + { + match = match_table[state].match; + + if (i % 4096 == 0 && scanner->timeout > 0) + { + if (yr_stopwatch_elapsed_us(&scanner->stopwatch) > scanner->timeout) + return ERROR_SCAN_TIMEOUT; + } + + while (match != NULL) + { + if (match->backtrack <= i) + { + FAIL_ON_ERROR(yr_scan_verify_match( + scanner, + match, + block_data, + block->size, + block->base, + i - match->backtrack)); + } + + match = match->next; + } + + index = block_data[i++] + 1; + transition = transition_table[state + index]; + + while (YR_AC_INVALID_TRANSITION(transition, index)) + { + if (state != YR_AC_ROOT_STATE) + { + state = transition_table[state] >> 32; + transition = transition_table[state + index]; + } + else + { + transition = 0; + break; + } + } + + state = transition >> 32; + + } + + match = match_table[state].match; + + while (match != NULL) + { + if (match->backtrack <= i) + { + FAIL_ON_ERROR(yr_scan_verify_match( + scanner, + match, + block_data, + block->size, + block->base, + i - match->backtrack)); + } + + match = match->next; + } + + return ERROR_SUCCESS; +} + + +static void _yr_scanner_clean_matches( + YR_SCANNER* scanner) +{ + YR_RULE* rule; + YR_STRING** string; + + int tidx = scanner->tidx; + + yr_rules_foreach(scanner->rules, rule) + { + rule->t_flags[tidx] &= ~RULE_TFLAGS_MATCH; + rule->ns->t_flags[tidx] &= ~NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL; + } + + if (scanner->matching_strings_arena != NULL) + { + string = (YR_STRING**) yr_arena_base_address( + scanner->matching_strings_arena); + + while (string != NULL) + { + (*string)->matches[tidx].count = 0; + (*string)->matches[tidx].head = NULL; + (*string)->matches[tidx].tail = NULL; + (*string)->unconfirmed_matches[tidx].count = 0; + (*string)->unconfirmed_matches[tidx].head = NULL; + (*string)->unconfirmed_matches[tidx].tail = NULL; + + string = (YR_STRING**) yr_arena_next_address( + scanner->matching_strings_arena, + string, + sizeof(YR_STRING*)); + } + } +} + + +YR_API int yr_scanner_create( + YR_RULES* rules, + YR_SCANNER** scanner) +{ + YR_EXTERNAL_VARIABLE* external; + YR_SCANNER* new_scanner; + + new_scanner = (YR_SCANNER*) yr_calloc(1, sizeof(YR_SCANNER)); + + if (new_scanner == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_hash_table_create(64, &new_scanner->objects_table), + yr_scanner_destroy(new_scanner)); + + external = rules->externals_list_head; + + while (!EXTERNAL_VARIABLE_IS_NULL(external)) + { + YR_OBJECT* object; + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_object_from_external_variable(external, &object), + yr_scanner_destroy(new_scanner)); + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_hash_table_add( + new_scanner->objects_table, + external->identifier, + NULL, + (void*) object), + yr_scanner_destroy(new_scanner)); + + external++; + } + + new_scanner->rules = rules; + new_scanner->tidx = -1; + new_scanner->entry_point = UNDEFINED; + + *scanner = new_scanner; + + return ERROR_SUCCESS; +} + + +YR_API void yr_scanner_destroy( + YR_SCANNER* scanner) +{ + RE_FIBER* fiber; + RE_FIBER* next_fiber; + + fiber = scanner->re_fiber_pool.fibers.head; + + while (fiber != NULL) + { + next_fiber = fiber->next; + yr_free(fiber); + fiber = next_fiber; + } + + if (scanner->objects_table != NULL) + { + yr_hash_table_destroy( + scanner->objects_table, + (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy); + } + + yr_free(scanner); +} + + +YR_API void yr_scanner_set_callback( + YR_SCANNER* scanner, + YR_CALLBACK_FUNC callback, + void* user_data) +{ + scanner->callback = callback; + scanner->user_data = user_data; +} + + +YR_API void yr_scanner_set_timeout( + YR_SCANNER* scanner, + int timeout) +{ + scanner->timeout = timeout * 1000000L; // convert timeout to microseconds. +} + + +YR_API void yr_scanner_set_flags( + YR_SCANNER* scanner, + int flags) +{ + scanner->flags = flags; +} + + +YR_API int yr_scanner_define_integer_variable( + YR_SCANNER* scanner, + const char* identifier, + int64_t value) +{ + YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup( + scanner->objects_table, + identifier, + NULL); + + if (obj == NULL) + return ERROR_INVALID_ARGUMENT; + + if (obj->type != OBJECT_TYPE_INTEGER) + return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; + + return yr_object_set_integer(value, obj, NULL); +} + + +YR_API int yr_scanner_define_boolean_variable( + YR_SCANNER* scanner, + const char* identifier, + int value) +{ + return yr_scanner_define_integer_variable(scanner, identifier, value); +} + + +YR_API int yr_scanner_define_float_variable( + YR_SCANNER* scanner, + const char* identifier, + double value) +{ + YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup( + scanner->objects_table, + identifier, + NULL); + + if (obj == NULL) + return ERROR_INVALID_ARGUMENT; + + if (obj->type != OBJECT_TYPE_FLOAT) + return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; + + return yr_object_set_float(value, obj, NULL); +} + + +YR_API int yr_scanner_define_string_variable( + YR_SCANNER* scanner, + const char* identifier, + const char* value) +{ + YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup( + scanner->objects_table, + identifier, + NULL); + + if (obj == NULL) + return ERROR_INVALID_ARGUMENT; + + if (obj->type != OBJECT_TYPE_STRING) + return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; + + return yr_object_set_string(value, strlen(value), obj, NULL); +} + + +YR_API int yr_scanner_scan_mem_blocks( + YR_SCANNER* scanner, + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + YR_RULES* rules; + YR_RULE* rule; + YR_MEMORY_BLOCK* block; + + int tidx = 0; + int result = ERROR_SUCCESS; + + if (scanner->callback == NULL) + return ERROR_CALLBACK_REQUIRED; + + scanner->iterator = iterator; + rules = scanner->rules; + block = iterator->first(iterator); + + if (block == NULL) + return ERROR_SUCCESS; + + yr_mutex_lock(&rules->mutex); + + while (tidx < MAX_THREADS && YR_BITARRAY_TEST(rules->tidx_mask, tidx)) + { + tidx++; + } + + if (tidx < MAX_THREADS) + YR_BITARRAY_SET(rules->tidx_mask, tidx); + else + result = ERROR_TOO_MANY_SCAN_THREADS; + + yr_mutex_unlock(&rules->mutex); + + if (result != ERROR_SUCCESS) + return result; + + scanner->tidx = tidx; + scanner->file_size = block->size; + + yr_set_tidx(tidx); + + result = yr_arena_create(1048576, 0, &scanner->matches_arena); + + if (result != ERROR_SUCCESS) + goto _exit; + + result = yr_arena_create(4096, 0, &scanner->matching_strings_arena); + + if (result != ERROR_SUCCESS) + goto _exit; + + yr_stopwatch_start(&scanner->stopwatch); + + while (block != NULL) + { + const uint8_t* data = block->fetch_data(block); + + // fetch may fail + if (data == NULL) + { + block = iterator->next(iterator); + continue; + } + + if (scanner->entry_point == UNDEFINED) + { + YR_TRYCATCH( + !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH), + { + if (scanner->flags & SCAN_FLAGS_PROCESS_MEMORY) + scanner->entry_point = yr_get_entry_point_address( + data, + block->size, + block->base); + else + scanner->entry_point = yr_get_entry_point_offset( + data, + block->size); + },{}); + } + + YR_TRYCATCH( + !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH), + { + result = _yr_scanner_scan_mem_block( + scanner, + data, + block); + },{ + result = ERROR_COULD_NOT_MAP_FILE; + }); + + if (result != ERROR_SUCCESS) + goto _exit; + + block = iterator->next(iterator); + } + + YR_TRYCATCH( + !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH), + { + result = yr_execute_code(scanner); + },{ + result = ERROR_COULD_NOT_MAP_FILE; + }); + + if (result != ERROR_SUCCESS) + goto _exit; + + yr_rules_foreach(rules, rule) + { + int message; + + if (rule->t_flags[tidx] & RULE_TFLAGS_MATCH && + !(rule->ns->t_flags[tidx] & NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL)) + { + message = CALLBACK_MSG_RULE_MATCHING; + } + else + { + message = CALLBACK_MSG_RULE_NOT_MATCHING; + } + + if (!RULE_IS_PRIVATE(rule)) + { + switch (scanner->callback(message, rule, scanner->user_data)) + { + case CALLBACK_ABORT: + result = ERROR_SUCCESS; + goto _exit; + + case CALLBACK_ERROR: + result = ERROR_CALLBACK_ERROR; + goto _exit; + } + } + } + + scanner->callback(CALLBACK_MSG_SCAN_FINISHED, NULL, scanner->user_data); + +_exit: + + scanner->rules->time_cost += yr_stopwatch_elapsed_us(&scanner->stopwatch); + + _yr_scanner_clean_matches(scanner); + + if (scanner->matches_arena != NULL) + { + yr_arena_destroy(scanner->matches_arena); + scanner->matches_arena = NULL; + } + + if (scanner->matching_strings_arena != NULL) + { + yr_arena_destroy(scanner->matching_strings_arena); + scanner->matching_strings_arena = NULL; + } + + yr_mutex_lock(&rules->mutex); + YR_BITARRAY_UNSET(rules->tidx_mask, tidx); + yr_mutex_unlock(&rules->mutex); + + yr_set_tidx(-1); + + return result; +} + + +static YR_MEMORY_BLOCK* _yr_get_first_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + return (YR_MEMORY_BLOCK*) iterator->context; +} + + +static YR_MEMORY_BLOCK* _yr_get_next_block( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + return NULL; +} + + +static const uint8_t* _yr_fetch_block_data( + YR_MEMORY_BLOCK* block) +{ + return (const uint8_t*) block->context; +} + + +YR_API int yr_scanner_scan_mem( + YR_SCANNER* scanner, + const uint8_t* buffer, + size_t buffer_size) +{ + YR_MEMORY_BLOCK block; + YR_MEMORY_BLOCK_ITERATOR iterator; + + block.size = buffer_size; + block.base = 0; + block.fetch_data = _yr_fetch_block_data; + block.context = (void*) buffer; + + iterator.context = █ + iterator.first = _yr_get_first_block; + iterator.next = _yr_get_next_block; + + return yr_scanner_scan_mem_blocks(scanner, &iterator); +} + + +YR_API int yr_scanner_scan_file( + YR_SCANNER* scanner, + const char* filename) +{ + YR_MAPPED_FILE mfile; + + int result = yr_filemap_map(filename, &mfile); + + if (result == ERROR_SUCCESS) + { + result = yr_scanner_scan_mem(scanner, mfile.data, mfile.size); + yr_filemap_unmap(&mfile); + } + + return result; +} + + +YR_API int yr_scanner_scan_fd( + YR_SCANNER* scanner, + YR_FILE_DESCRIPTOR fd) +{ + YR_MAPPED_FILE mfile; + + int result = yr_filemap_map_fd(fd, 0, 0, &mfile); + + if (result == ERROR_SUCCESS) + { + result = yr_scanner_scan_mem(scanner, mfile.data, mfile.size); + yr_filemap_unmap_fd(&mfile); + } + + return result; +} + + +YR_API int yr_scanner_scan_proc( + YR_SCANNER* scanner, + int pid) +{ + YR_MEMORY_BLOCK_ITERATOR iterator; + + int result = yr_process_open_iterator(pid, &iterator); + + if (result == ERROR_SUCCESS) + { + int prev_flags = scanner->flags; + scanner->flags |= SCAN_FLAGS_PROCESS_MEMORY; + result = yr_scanner_scan_mem_blocks(scanner, &iterator); + scanner->flags = prev_flags; + yr_process_close_iterator(&iterator); + } + + return result; +} + + +YR_API YR_STRING* yr_scanner_last_error_string( + YR_SCANNER* scanner) +{ + return scanner->last_error_string; +} + + +YR_API YR_RULE* yr_scanner_last_error_rule( + YR_SCANNER* scanner) +{ + if (scanner->last_error_string == NULL) + return NULL; + + return scanner->last_error_string->rule; +} diff --git a/yara-master/libyara/sizedstr.c b/yara-master/libyara/sizedstr.c new file mode 100644 index 0000000..3bf058a --- /dev/null +++ b/yara-master/libyara/sizedstr.c @@ -0,0 +1,76 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include + + +int sized_string_cmp( + SIZED_STRING* s1, + SIZED_STRING* s2) +{ + size_t i = 0; + + while (s1->length > i && + s2->length > i && + s1->c_string[i] == s2->c_string[i]) + { + i++; + } + + if (i == s1->length && i == s2->length) + return 0; + else if (i == s1->length) + return -1; + else if (i == s2->length) + return 1; + else if (s1->c_string[i] < s2->c_string[i]) + return -1; + else + return 1; +} + + +SIZED_STRING* sized_string_dup( + SIZED_STRING* s) +{ + SIZED_STRING* result = (SIZED_STRING*) yr_malloc( + sizeof(SIZED_STRING) + s->length); + + if (result == NULL) + return NULL; + + result->length = s->length; + result->flags = s->flags; + + strncpy(result->c_string, s->c_string, s->length + 1); + + return result; +} diff --git a/yara-master/libyara/stino.settings b/yara-master/libyara/stino.settings new file mode 100644 index 0000000..19b6947 --- /dev/null +++ b/yara-master/libyara/stino.settings @@ -0,0 +1,5 @@ +{ + "baudrate": 4, + "line_ending": 1, + "serial_port": 1 +} \ No newline at end of file diff --git a/yara-master/libyara/stopwatch.c b/yara-master/libyara/stopwatch.c new file mode 100644 index 0000000..edbca68 --- /dev/null +++ b/yara-master/libyara/stopwatch.c @@ -0,0 +1,114 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#include + +#if defined(_WIN32) + +void yr_stopwatch_start( + YR_STOPWATCH* sw) +{ + QueryPerformanceFrequency(&sw->frequency); + QueryPerformanceCounter(&sw->start); +} + + +uint64_t yr_stopwatch_elapsed_us( + YR_STOPWATCH* sw) +{ + LARGE_INTEGER li; + + QueryPerformanceCounter(&li); + + return (li.QuadPart - sw->start.QuadPart) * 1000000L / sw->frequency.QuadPart; +} + + +#elif defined(__MACH__) + +void yr_stopwatch_start( + YR_STOPWATCH* sw) +{ + mach_timebase_info(&sw->timebase); + sw->start = mach_absolute_time(); +} + + +uint64_t yr_stopwatch_elapsed_us( + YR_STOPWATCH* sw) +{ + uint64_t now; + + now = mach_absolute_time(); + return (now - sw->start) * sw->timebase.numer / + (sw->timebase.denom * 1000ULL); +} + + +#else + +#define timespecsub(tsp, usp, vsp) \ +do { \ + (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ + if ((vsp)->tv_nsec < 0) { \ + (vsp)->tv_sec--; \ + (vsp)->tv_nsec += 1000000000L; \ + } \ +} while (0) + + +void yr_stopwatch_start( + YR_STOPWATCH* stopwatch) +{ + #if defined(HAVE_CLOCK_GETTIME) + clock_gettime(CLOCK_MONOTONIC, &stopwatch->ts_start); + #else + #endif +} + + +uint64_t yr_stopwatch_elapsed_us( + YR_STOPWATCH* stopwatch) +{ + struct timespec ts_stop; + struct timespec ts_elapsed; + + #if defined(HAVE_CLOCK_GETTIME) + clock_gettime(CLOCK_MONOTONIC, &ts_stop); + timespecsub(&ts_stop, &stopwatch->ts_start, &ts_elapsed); + #else + #endif + + return ts_elapsed.tv_sec * 1000000L + ts_elapsed.tv_nsec / 1000; +} + +#endif diff --git a/yara-master/libyara/stream.c b/yara-master/libyara/stream.c new file mode 100644 index 0000000..63fce5e --- /dev/null +++ b/yara-master/libyara/stream.c @@ -0,0 +1,57 @@ +/* +Copyright (c) 2015. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + + +size_t yr_stream_read( + void* ptr, + size_t size, + size_t count, + YR_STREAM* stream) +{ + if (stream->read == NULL) + return 0; + + return stream->read(ptr, size, count, stream->user_data); +} + + +size_t yr_stream_write( + const void* ptr, + size_t size, + size_t count, + YR_STREAM* stream) +{ + if (stream->write == NULL) + return 0; + + return stream->write(ptr, size, count, stream->user_data); +} diff --git a/yara-master/libyara/strutils.c b/yara-master/libyara/strutils.c new file mode 100644 index 0000000..1bd0a15 --- /dev/null +++ b/yara-master/libyara/strutils.c @@ -0,0 +1,252 @@ +/* +Copyright (c) 2007-2014. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#include + +uint64_t xtoi( + const char* hexstr) +{ + size_t i; + size_t l = strlen(hexstr); + + uint64_t r = 0; + + for (i = 0; i < l; i++) + { + switch (hexstr[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + r |= ((uint64_t)(hexstr[i] - '0')) << ((l - i - 1) * 4); + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + r |= ((uint64_t)(hexstr[i] - 'a' + 10)) << ((l - i - 1) * 4); + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + r |= ((uint64_t)(hexstr[i] - 'A' + 10)) << ((l - i - 1) * 4); + break; + default: + i = l; // force loop exit + } + } + + return r; +} + +/* + +strlcpy and strlcat are defined in FreeBSD and OpenBSD, +the following implementations were taken from OpenBSD. + +*/ + +#if !HAVE_STRLCPY && !defined(strlcpy) + +size_t strlcpy( + char* dst, + const char* src, + size_t size) +{ + register char* d = dst; + register const char* s = src; + register size_t n = size; + + // Copy as many bytes as will fit + + if (n != 0 && --n != 0) + { + do + { + if ((*d++ = *s++) == 0) + break; + + } while (--n != 0); + } + + // Not enough room in dst, add NUL and traverse rest of src + + if (n == 0) + { + if (size != 0) + *d = '\0'; // NULL-terminate dst + + while (*s++); + } + + return (s - src - 1); // count does not include NULL +} + +#endif + + +#if !HAVE_STRLCAT && !defined(strlcat) + +size_t strlcat( + char* dst, + const char* src, + size_t size) +{ + register char* d = dst; + register const char* s = src; + register size_t n = size; + size_t dlen; + + // Find the end of dst and adjust bytes left but don't go past end + + while (n-- != 0 && *d != '\0') d++; + + dlen = d - dst; + n = size - dlen; + + if (n == 0) + return(dlen + strlen(s)); + + while (*s != '\0') + { + if (n != 1) + { + *d++ = *s; + n--; + } + s++; + } + + *d = '\0'; + + return (dlen + (s - src)); // count does not include NULL +} + +#endif + + +int strnlen_w( + const char* w_str) +{ + int len = 0; + + while (w_str[0] || w_str[1]) + { + w_str += 2; + len += 1; + } + + return len; +} + + +int strcmp_w( + const char* w_str, + const char* str) +{ + while (*str != 0 && w_str[0] == *str && w_str[1] == 0) + { + w_str += 2; + str += 1; + } + + // Higher-order byte of wide char non-zero? -> w_str is larger than str + + if (w_str[1] != 0) + return 1; + + return w_str[0] - *str; +} + + +size_t strlcpy_w( + char* dst, + const char* w_src, + size_t n) +{ + register char* d = dst; + register const char* s = w_src; + + while (n > 1 && *s != 0) + { + *d = *s; + d += 1; + n -= 1; + s += 2; + } + + while (*s) s += 2; + + *d = '\0'; + + return (s - w_src) / 2; +} + + +#if !HAVE_MEMMEM && !defined(memmem) +void* memmem( + const void *haystack, + size_t haystack_size, + const void *needle, + size_t needle_size) +{ + char *sp = (char *) haystack; + char *pp = (char *) needle; + char *eos = sp + haystack_size - needle_size; + + if (haystack == NULL || haystack_size == 0 || + needle == NULL || needle_size == 0) + return NULL; + + while (sp <= eos) + { + if (*sp == *pp && memcmp(sp, pp, needle_size) == 0) + return sp; + + sp++; + } + + return NULL; +} +#endif diff --git a/yara-master/libyara/threading.c b/yara-master/libyara/threading.c new file mode 100644 index 0000000..1fa0098 --- /dev/null +++ b/yara-master/libyara/threading.c @@ -0,0 +1,209 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#if defined(_WIN32) || defined(__CYGWIN__) + +YR_THREAD_ID yr_current_thread_id(void) +{ + return GetCurrentThreadId(); +} + + +int yr_mutex_create( + YR_MUTEX* mutex) +{ + *mutex = CreateMutex(NULL, FALSE, NULL); + + if (*mutex == NULL) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_mutex_destroy( + YR_MUTEX* mutex) +{ + if (CloseHandle(*mutex) == FALSE) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_mutex_lock( + YR_MUTEX* mutex) +{ + if (WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_mutex_unlock( + YR_MUTEX* mutex) +{ + if (ReleaseMutex(*mutex) == FALSE) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_thread_storage_create( + YR_THREAD_STORAGE_KEY* storage) +{ + *storage = TlsAlloc(); + + if (*storage == TLS_OUT_OF_INDEXES) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_thread_storage_destroy( + YR_THREAD_STORAGE_KEY* storage) +{ + if (TlsFree(*storage) == FALSE) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_thread_storage_set_value( + YR_THREAD_STORAGE_KEY* storage, + void* value) +{ + if (TlsSetValue(*storage, value) == FALSE) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +void* yr_thread_storage_get_value( + YR_THREAD_STORAGE_KEY* storage) +{ + return TlsGetValue(*storage); +} + + +#else // POSIX implementation + + +YR_THREAD_ID yr_current_thread_id(void) +{ + return pthread_self(); +} + + +int yr_mutex_create( + YR_MUTEX* mutex) +{ + if (pthread_mutex_init(mutex, NULL) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_mutex_destroy( + YR_MUTEX* mutex) +{ + if (pthread_mutex_destroy(mutex) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_mutex_lock( + YR_MUTEX* mutex) +{ + if (pthread_mutex_lock(mutex) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_mutex_unlock( + YR_MUTEX* mutex) +{ + if (pthread_mutex_unlock(mutex) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_thread_storage_create( + YR_THREAD_STORAGE_KEY* storage) +{ + if (pthread_key_create(storage, NULL) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_thread_storage_destroy( + YR_THREAD_STORAGE_KEY* storage) +{ + if (pthread_key_delete(*storage) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +int yr_thread_storage_set_value( + YR_THREAD_STORAGE_KEY* storage, + void* value) +{ + if (pthread_setspecific(*storage, value) != 0) + return ERROR_INTERNAL_FATAL_ERROR; + + return ERROR_SUCCESS; +} + + +void* yr_thread_storage_get_value( + YR_THREAD_STORAGE_KEY* storage) +{ + return pthread_getspecific(*storage); +} + +#endif diff --git a/yara-master/libyara/yara.pc.in b/yara-master/libyara/yara.pc.in new file mode 100644 index 0000000..0dced26 --- /dev/null +++ b/yara-master/libyara/yara.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libdir@ + +Name: yara +Description: YARA library +URL: https://virustotal.github.io/yara/ +Version: @PACKAGE_VERSION@ +Requires.private: @PC_REQUIRES_PRIVATE@ +Cflags: -I${includedir} +Libs: -L${libdir} -lyara +Libs.private: @PC_LIBS_PRIVATE@ @PTHREAD_LIBS@ diff --git a/yara-master/sample.file b/yara-master/sample.file new file mode 100644 index 0000000..d27e74d --- /dev/null +++ b/yara-master/sample.file @@ -0,0 +1 @@ +abbbb diff --git a/yara-master/sample.rules b/yara-master/sample.rules new file mode 100644 index 0000000..c84c000 --- /dev/null +++ b/yara-master/sample.rules @@ -0,0 +1,11 @@ + +rule UPX : Packer +{ + strings: + $a = {60 E8 00 00 00 00 58 83 E8 3D 50 8D B8} + + condition: + $a at entrypoint + +} + diff --git a/yara-master/tests/blob.h b/yara-master/tests/blob.h new file mode 100644 index 0000000..255eb08 --- /dev/null +++ b/yara-master/tests/blob.h @@ -0,0 +1,2751 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +uint8_t PE32_FILE[] = { + 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, +}; + +uint8_t ELF32_FILE[] = { + 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, +}; + +uint8_t ELF64_FILE[] = { + 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, +}; + + +uint8_t ELF32_NOSECTIONS[] = { + 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xa0, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x20, 0x00, 0x02, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08, + 0x00, 0x80, 0x04, 0x08, 0xac, 0x00, 0x00, 0x00, + 0xac, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x74, 0x80, 0x04, 0x08, + 0x74, 0x80, 0x04, 0x08, 0x24, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x47, 0x4e, 0x55, 0x00, 0x72, 0x5c, 0x33, 0xa6, + 0xcd, 0xed, 0x46, 0xf2, 0xc7, 0xa2, 0x8c, 0x1f, + 0xbd, 0x65, 0x7a, 0xd1, 0x9f, 0x0f, 0x51, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbb, 0x2a, 0x00, + 0x00, 0x00, 0xcd, 0x80, 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, 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 +}; + +uint8_t ELF32_SHAREDOBJ[] = { + 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xa0, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x20, 0x00, 0x05, 0x00, 0x28, 0x00, + 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, + 0xac, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xa8, 0x0f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, + 0xa8, 0x1f, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xa8, 0x0f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, + 0xa8, 0x1f, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xd4, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0xd4, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x52, 0xe5, 0x74, 0x64, + 0xa8, 0x0f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, + 0xa8, 0x1f, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x47, 0x4e, 0x55, 0x00, 0x6e, 0x96, 0x9b, 0xbc, + 0x8b, 0x0c, 0x9d, 0x95, 0x29, 0xfc, 0x07, 0x04, + 0x15, 0x95, 0xc5, 0xf0, 0xb9, 0xd5, 0xcd, 0xae, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x08, 0x44, 0x06, 0x29, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x42, 0x45, 0xd5, 0xec, 0xbb, 0xe3, 0x92, 0x7c, + 0x32, 0x62, 0xdb, 0xed, 0xd9, 0x71, 0x58, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x05, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, + 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, + 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x5f, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x00, 0x5f, 0x65, 0x6e, 0x64, + 0x00, 0x00, 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, 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, + 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, 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, 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, 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, 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, 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, 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, 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, + 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, 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, 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, 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, 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, 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, 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, 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, + 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, 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, 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, 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, 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, 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, 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, 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, + 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, 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, 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, + 0xf5, 0xfe, 0xff, 0x6f, 0xf8, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x0b, 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, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, + 0x61, 0x62, 0x00, 0x2e, 0x6e, 0x6f, 0x74, 0x65, + 0x2e, 0x67, 0x6e, 0x75, 0x2e, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x2d, 0x69, 0x64, 0x00, 0x2e, 0x67, + 0x6e, 0x75, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x00, + 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x79, 0x6d, 0x00, + 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x74, 0x72, 0x00, + 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x65, + 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, + 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, + 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, + 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xd4, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0x6f, 0x02, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x28, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x78, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x01, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xac, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xa8, 0x1f, 0x00, 0x00, 0xa8, 0x0f, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + + +unsigned char ELF32_MIPS_FILE[] = { + 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, + 0x06, 0x10, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x1f, 0x28, 0x00, 0x00, 0x10, + 0x07, 0x00, 0x34, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x28, 0x00, 0x23, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, 0x00, 0x34, 0x00, + 0x40, 0x00, 0x34, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, + 0x74, 0x00, 0x40, 0x01, 0x74, 0x00, 0x40, 0x01, 0x74, 0x00, 0x00, 0x00, 0x17, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x70, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x90, 0x00, 0x40, 0x01, 0x90, 0x00, 0x40, + 0x01, 0x90, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa8, + 0x00, 0x40, 0x01, 0xa8, 0x00, 0x40, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x5c, 0x00, 0x00, 0x09, 0x5c, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0xec, 0x00, + 0x41, 0x0f, 0xec, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x40, 0x01, 0xc0, 0x00, 0x40, 0x01, 0xc0, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x64, 0x74, 0xe5, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x64, 0x74, 0xe5, 0x52, + 0x00, 0x00, 0x0f, 0xec, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x41, 0x0f, 0xec, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 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, 0x04, 0x2f, 0x6c, 0x69, 0x62, 0x2f, + 0x6c, 0x64, 0x2d, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x6d, 0x69, 0x70, 0x73, 0x2e, + 0x73, 0x6f, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0xf6, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x97, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x0d, + 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x40, 0x02, 0x80, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x40, 0x04, 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, + 0x03, 0x24, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x10, 0x70, 0x00, 0x00, 0x16, 0x00, 0x41, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x41, 0x10, 0x10, 0x70, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x70, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x06, 0x00, 0x40, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x11, + 0x00, 0x00, 0x00, 0x16, 0x70, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x70, + 0x00, 0x00, 0x13, 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, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 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, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 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, + 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0xf5, 0x00, 0x40, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xba, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x40, 0x06, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xfd, + 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, 0x12, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0xb0, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x40, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x12, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x40, 0x09, 0x10, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x41, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x41, 0x10, 0x4c, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0d, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x5f, + 0x5f, 0x6c, 0x69, 0x62, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, + 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x64, 0x65, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x69, + 0x6e, 0x66, 0x6f, 0x00, 0x5f, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, + 0x5f, 0x4a, 0x76, 0x5f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x00, 0x6c, 0x69, 0x62, 0x63, 0x2e, 0x73, + 0x6f, 0x00, 0x5f, 0x44, 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x5f, 0x4c, 0x49, + 0x4e, 0x4b, 0x49, 0x4e, 0x47, 0x00, 0x5f, 0x5f, 0x52, 0x4c, 0x44, 0x5f, 0x4d, + 0x41, 0x50, 0x00, 0x5f, 0x66, 0x74, 0x65, 0x78, 0x74, 0x00, 0x5f, 0x66, 0x64, + 0x61, 0x74, 0x61, 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x5f, + 0x62, 0x73, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x66, 0x62, + 0x73, 0x73, 0x00, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x67, 0x6e, 0x75, + 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x67, 0x70, 0x00, 0x5f, 0x5f, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x63, + 0x00, 0x00, 0x00, 0x27, 0xbd, 0xff, 0xe0, 0xaf, 0xbc, 0x00, 0x18, 0xaf, 0xbf, + 0x00, 0x1c, 0x04, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, + 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x99, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x39, 0x08, 0x0c, 0x04, 0x11, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x8f, + 0xbc, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x99, 0x80, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x27, 0x39, 0x08, 0x90, 0x04, 0x11, 0x00, 0xab, + 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x18, 0x8f, 0xbf, 0x00, 0x1c, 0x03, + 0xe0, 0x00, 0x08, 0x27, 0xbd, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xe0, 0x00, 0x08, 0x24, 0x02, 0x00, 0x2a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, 0x00, 0x04, 0x00, 0x00, 0xf0, 0x21, + 0xff, 0xfe, 0x76, 0x18, 0xff, 0xfe, 0x76, 0x50, 0xff, 0xfe, 0x71, 0xc0, 0x8f, + 0xfc, 0x00, 0x00, 0x03, 0xfc, 0xe0, 0x23, 0x03, 0xa0, 0x20, 0x21, 0x8f, 0xe5, + 0x00, 0x08, 0x00, 0xbc, 0x28, 0x21, 0x8f, 0xf9, 0x00, 0x04, 0x03, 0x3c, 0xc8, + 0x21, 0x24, 0x01, 0xff, 0xf8, 0x03, 0xa1, 0xe8, 0x24, 0x03, 0x20, 0xf8, 0x09, + 0x27, 0xbd, 0xff, 0xf0, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, + 0x82, 0x80, 0x18, 0x27, 0xbd, 0xff, 0xd8, 0x8c, 0x85, 0x00, 0x00, 0x24, 0x86, + 0x00, 0x04, 0x8f, 0x87, 0x80, 0x1c, 0x8f, 0x84, 0x80, 0x20, 0x8f, 0x99, 0x80, + 0x38, 0xaf, 0xbf, 0x00, 0x24, 0xaf, 0xbc, 0x00, 0x18, 0xaf, 0xa0, 0x00, 0x14, + 0x03, 0x20, 0xf8, 0x09, 0xaf, 0xa2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x41, 0x3c, 0x02, 0x00, 0x41, 0x24, 0x84, + 0x10, 0x04, 0x24, 0x42, 0x10, 0x07, 0x00, 0x44, 0x10, 0x23, 0x2c, 0x42, 0x00, + 0x07, 0x14, 0x40, 0x00, 0x08, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, + 0x8f, 0x99, 0x80, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x41, 0x3c, 0x02, 0x00, + 0x41, 0x24, 0x84, 0x10, 0x04, 0x24, 0x42, 0x10, 0x04, 0x00, 0x44, 0x10, 0x23, + 0x00, 0x02, 0x10, 0x83, 0x00, 0x02, 0x2f, 0xc2, 0x00, 0xa2, 0x28, 0x21, 0x00, + 0x05, 0x28, 0x43, 0x10, 0xa0, 0x00, 0x08, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, + 0x90, 0x00, 0x8f, 0x99, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x27, 0xbd, 0xff, 0xd0, 0xaf, + 0xb3, 0x00, 0x28, 0x3c, 0x13, 0x00, 0x41, 0x3c, 0x1c, 0x00, 0x42, 0x92, 0x62, + 0x10, 0x50, 0x27, 0x9c, 0x90, 0x00, 0xaf, 0xbf, 0x00, 0x2c, 0xaf, 0xb2, 0x00, + 0x24, 0xaf, 0xb1, 0x00, 0x20, 0xaf, 0xb0, 0x00, 0x1c, 0x14, 0x40, 0x00, 0x28, + 0xaf, 0xbc, 0x00, 0x10, 0x3c, 0x11, 0x00, 0x41, 0x3c, 0x02, 0x00, 0x41, 0x24, + 0x42, 0x0f, 0xf8, 0x26, 0x31, 0x0f, 0xf4, 0x00, 0x51, 0x88, 0x23, 0x3c, 0x10, + 0x00, 0x41, 0x8e, 0x02, 0x10, 0x54, 0x00, 0x11, 0x88, 0x83, 0x26, 0x31, 0xff, + 0xff, 0x3c, 0x04, 0x00, 0x41, 0x00, 0x51, 0x18, 0x2b, 0x24, 0x92, 0x0f, 0xf4, + 0x10, 0x60, 0x00, 0x0c, 0x24, 0x42, 0x00, 0x01, 0x00, 0x02, 0x18, 0x80, 0x02, + 0x43, 0x18, 0x21, 0x8c, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, + 0xf8, 0x09, 0xae, 0x02, 0x10, 0x54, 0x8e, 0x02, 0x10, 0x54, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x51, 0x18, 0x2b, 0x14, 0x60, 0xff, 0xf6, 0x24, 0x42, 0x00, 0x01, + 0x0c, 0x10, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x8f, 0x82, 0x80, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, + 0x00, 0x06, 0x24, 0x02, 0x00, 0x01, 0x8f, 0x99, 0x80, 0x44, 0x3c, 0x04, 0x00, + 0x40, 0x03, 0x20, 0xf8, 0x09, 0x24, 0x84, 0x09, 0x58, 0x24, 0x02, 0x00, 0x01, + 0xa2, 0x62, 0x10, 0x50, 0x8f, 0xbf, 0x00, 0x2c, 0x8f, 0xb3, 0x00, 0x28, 0x8f, + 0xb2, 0x00, 0x24, 0x8f, 0xb1, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x1c, 0x03, 0xe0, + 0x00, 0x08, 0x27, 0xbd, 0x00, 0x30, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, + 0x00, 0x8f, 0x82, 0x80, 0x30, 0x27, 0xbd, 0xff, 0xe0, 0xaf, 0xbf, 0x00, 0x1c, + 0x10, 0x40, 0x00, 0x08, 0xaf, 0xbc, 0x00, 0x10, 0x8f, 0x99, 0x80, 0x30, 0x3c, + 0x05, 0x00, 0x41, 0x3c, 0x04, 0x00, 0x40, 0x24, 0xa5, 0x10, 0x58, 0x03, 0x20, + 0xf8, 0x09, 0x24, 0x84, 0x09, 0x58, 0x8f, 0xbc, 0x00, 0x10, 0x3c, 0x02, 0x00, + 0x41, 0x24, 0x44, 0x0f, 0xfc, 0x8c, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbf, 0x00, 0x1c, 0x08, + 0x10, 0x01, 0xb5, 0x27, 0xbd, 0x00, 0x20, 0x8f, 0x99, 0x80, 0x34, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x20, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xf8, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x10, 0x10, 0x00, 0xff, 0xf5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x41, 0x8c, + 0x59, 0x0f, 0xec, 0x24, 0x02, 0xff, 0xff, 0x13, 0x22, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x27, 0xbd, 0xff, 0xd8, 0xaf, 0xb0, 0x00, 0x1c, 0x3c, 0x10, 0x00, + 0x41, 0xaf, 0xb1, 0x00, 0x20, 0xaf, 0xbf, 0x00, 0x24, 0x26, 0x10, 0x0f, 0xec, + 0x24, 0x11, 0xff, 0xff, 0x03, 0x20, 0xf8, 0x09, 0x26, 0x10, 0xff, 0xfc, 0x8e, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x31, 0xff, 0xfb, 0x00, 0x00, + 0x00, 0x00, 0x8f, 0xbf, 0x00, 0x24, 0x8f, 0xb1, 0x00, 0x20, 0x8f, 0xb0, 0x00, + 0x1c, 0x27, 0xbd, 0x00, 0x28, 0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x99, 0x80, 0x10, 0x03, 0xe0, 0x78, 0x21, 0x03, 0x20, 0xf8, 0x09, 0x24, + 0x18, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xbd, 0xff, 0xe0, 0xaf, 0xbc, 0x00, + 0x18, 0xaf, 0xbf, 0x00, 0x1c, 0x04, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x99, 0x80, 0x24, 0x00, + 0x00, 0x00, 0x00, 0x27, 0x39, 0x07, 0x24, 0x04, 0x11, 0xff, 0x7a, 0x00, 0x00, + 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, + 0x18, 0x8f, 0xbf, 0x00, 0x1c, 0x03, 0xe0, 0x00, 0x08, 0x27, 0xbd, 0x00, 0x20, + 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 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, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x09, 0x10, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x40, 0x06, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, + 0x43, 0x43, 0x3a, 0x20, 0x28, 0x47, 0x4e, 0x55, 0x29, 0x20, 0x35, 0x2e, 0x33, + 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x80, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, + 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, + 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x02, 0x00, 0x00, 0x00, 0xa3, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x40, 0x09, 0x10, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x02, 0x00, 0x00, 0x01, 0x13, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x05, 0xe8, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x09, + 0x48, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x9f, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, + 0x00, 0x00, 0x0e, 0x0c, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x01, 0x0d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, + 0x01, 0x9c, 0x00, 0x00, 0x00, 0x7b, 0x03, 0x70, 0x00, 0x01, 0x0d, 0x00, 0x00, + 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x01, 0x0f, + 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x2e, 0x04, 0x00, 0x00, 0x01, 0x49, + 0x01, 0x10, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x4d, 0x05, 0x00, 0x40, + 0x06, 0x88, 0x06, 0x01, 0x56, 0x05, 0xf3, 0x01, 0x54, 0x23, 0x04, 0x06, 0x02, + 0x8d, 0x14, 0x01, 0x30, 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x81, 0x08, + 0x04, 0x05, 0x00, 0x00, 0x00, 0xf4, 0x09, 0x04, 0x05, 0x69, 0x6e, 0x74, 0x00, + 0x07, 0x04, 0x00, 0x00, 0x00, 0x95, 0x07, 0x04, 0x00, 0x00, 0x00, 0x9b, 0x08, + 0x01, 0x06, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x83, 0x04, 0x01, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, + 0x10, 0x63, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x70, 0x73, 0x2f, 0x63, 0x72, 0x74, + 0x69, 0x2e, 0x73, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x61, 0x6c, 0x62, + 0x69, 0x6e, 0x6f, 0x6c, 0x6f, 0x62, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x44, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, + 0x63, 0x72, 0x6f, 0x73, 0x73, 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, + 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x36, 0x00, 0x47, + 0x4e, 0x55, 0x20, 0x41, 0x53, 0x20, 0x32, 0x2e, 0x32, 0x35, 0x2e, 0x31, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x95, 0x04, + 0x01, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x30, 0x63, 0x72, 0x74, 0x2f, + 0x6d, 0x69, 0x70, 0x73, 0x2f, 0x63, 0x72, 0x74, 0x6e, 0x2e, 0x73, 0x00, 0x2f, + 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x61, 0x6c, 0x62, 0x69, 0x6e, 0x6f, 0x6c, 0x6f, + 0x62, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, + 0x64, 0x73, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x63, 0x72, 0x6f, 0x73, 0x73, + 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, + 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x36, 0x00, 0x47, 0x4e, 0x55, 0x20, 0x41, 0x53, + 0x20, 0x32, 0x2e, 0x32, 0x35, 0x2e, 0x31, 0x00, 0x80, 0x01, 0x01, 0x11, 0x01, + 0x25, 0x0e, 0x13, 0x0b, 0x03, 0x0e, 0x1b, 0x0e, 0x55, 0x17, 0x11, 0x01, 0x10, + 0x17, 0x00, 0x00, 0x02, 0x2e, 0x01, 0x3f, 0x19, 0x03, 0x0e, 0x3a, 0x0b, 0x3b, + 0x0b, 0x27, 0x19, 0x87, 0x01, 0x19, 0x11, 0x01, 0x12, 0x06, 0x40, 0x18, 0x97, + 0x42, 0x19, 0x01, 0x13, 0x00, 0x00, 0x03, 0x05, 0x00, 0x03, 0x08, 0x3a, 0x0b, + 0x3b, 0x0b, 0x49, 0x13, 0x02, 0x17, 0x00, 0x00, 0x04, 0x34, 0x00, 0x03, 0x0e, + 0x3a, 0x0b, 0x3b, 0x0b, 0x49, 0x13, 0x02, 0x17, 0x00, 0x00, 0x05, 0x89, 0x82, + 0x01, 0x01, 0x11, 0x01, 0x00, 0x00, 0x06, 0x8a, 0x82, 0x01, 0x00, 0x02, 0x18, + 0x91, 0x42, 0x18, 0x00, 0x00, 0x07, 0x0f, 0x00, 0x0b, 0x0b, 0x49, 0x13, 0x00, + 0x00, 0x08, 0x24, 0x00, 0x0b, 0x0b, 0x3e, 0x0b, 0x03, 0x0e, 0x00, 0x00, 0x09, + 0x24, 0x00, 0x0b, 0x0b, 0x3e, 0x0b, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x11, + 0x00, 0x10, 0x06, 0x55, 0x06, 0x03, 0x08, 0x1b, 0x08, 0x25, 0x08, 0x13, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x10, 0x06, 0x55, 0x06, 0x03, 0x08, 0x1b, + 0x08, 0x25, 0x08, 0x13, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x21, 0x01, 0x01, 0xfb, 0x0e, 0x0d, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x63, 0x72, 0x74, 0x00, + 0x00, 0x63, 0x72, 0x74, 0x31, 0x2e, 0x63, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x02, 0x00, 0x40, 0x06, 0x50, 0x03, 0x0d, 0x01, 0x85, 0x47, 0x4d, 0x08, + 0x39, 0x4a, 0x4d, 0x02, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x26, 0x01, 0x01, 0xfb, 0x0e, 0x0d, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x63, 0x72, 0x74, 0x2f, + 0x6d, 0x69, 0x70, 0x73, 0x00, 0x00, 0x63, 0x72, 0x74, 0x69, 0x2e, 0x73, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x40, 0x05, 0x8c, 0x19, 0x4b, + 0x4b, 0x02, 0x04, 0x00, 0x01, 0x01, 0x00, 0x05, 0x02, 0x00, 0x40, 0x09, 0x10, + 0x03, 0x10, 0x01, 0x4b, 0x4b, 0x02, 0x04, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0x01, 0x01, 0xfb, 0x0e, 0x0d, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x63, 0x72, + 0x74, 0x2f, 0x6d, 0x69, 0x70, 0x73, 0x00, 0x00, 0x63, 0x72, 0x74, 0x6e, 0x2e, + 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x40, 0x05, 0xe8, + 0x15, 0x4b, 0x4b, 0x4b, 0x02, 0x04, 0x00, 0x01, 0x01, 0x00, 0x05, 0x02, 0x00, + 0x40, 0x09, 0x48, 0x03, 0x09, 0x01, 0x4b, 0x4b, 0x4b, 0x02, 0x04, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x01, 0x7c, 0x1f, 0x0d, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, 0x50, 0x0e, 0x28, + 0x58, 0x9f, 0x01, 0x00, 0x00, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x63, + 0x00, 0x61, 0x72, 0x67, 0x63, 0x00, 0x47, 0x4e, 0x55, 0x20, 0x43, 0x39, 0x39, + 0x20, 0x35, 0x2e, 0x33, 0x2e, 0x30, 0x20, 0x2d, 0x6d, 0x65, 0x62, 0x20, 0x2d, + 0x6d, 0x6c, 0x6c, 0x73, 0x63, 0x20, 0x2d, 0x6d, 0x6e, 0x6f, 0x2d, 0x73, 0x68, + 0x61, 0x72, 0x65, 0x64, 0x20, 0x2d, 0x6d, 0x61, 0x62, 0x69, 0x3d, 0x33, 0x32, + 0x20, 0x2d, 0x67, 0x20, 0x2d, 0x4f, 0x73, 0x20, 0x2d, 0x73, 0x74, 0x64, 0x3d, + 0x63, 0x39, 0x39, 0x20, 0x2d, 0x66, 0x66, 0x72, 0x65, 0x65, 0x73, 0x74, 0x61, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x2d, 0x66, 0x65, 0x78, 0x63, 0x65, 0x73, + 0x73, 0x2d, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x73, + 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x2d, 0x66, 0x72, 0x6f, 0x75, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6d, 0x61, 0x74, 0x68, 0x20, 0x2d, 0x66, + 0x6e, 0x6f, 0x2d, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x2d, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x73, 0x20, 0x2d, 0x66, 0x6e, 0x6f, 0x2d, 0x61, 0x73, 0x79, 0x6e, + 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x75, 0x73, 0x2d, 0x75, 0x6e, 0x77, 0x69, + 0x6e, 0x64, 0x2d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x20, 0x2d, 0x66, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x73, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x2d, 0x66, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x73, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x2d, 0x66, 0x6e, 0x6f, 0x2d, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x74, 0x00, 0x63, 0x72, + 0x74, 0x2f, 0x63, 0x72, 0x74, 0x31, 0x2e, 0x63, 0x00, 0x63, 0x68, 0x61, 0x72, + 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x61, 0x6c, 0x62, 0x69, 0x6e, 0x6f, + 0x6c, 0x6f, 0x62, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, + 0x6f, 0x61, 0x64, 0x73, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x63, 0x72, 0x6f, + 0x73, 0x73, 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x6d, 0x75, 0x73, + 0x6c, 0x2d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x36, 0x00, 0x61, 0x72, 0x67, 0x76, + 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x40, 0x06, 0x70, 0x00, 0x01, 0x54, 0x00, + 0x40, 0x06, 0x70, 0x00, 0x40, 0x06, 0x87, 0x00, 0x03, 0x76, 0x7c, 0x9f, 0x00, + 0x40, 0x06, 0x87, 0x00, 0x40, 0x06, 0x88, 0x00, 0x04, 0xf3, 0x01, 0x54, 0x9f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, + 0x40, 0x06, 0x70, 0x00, 0x02, 0x74, 0x00, 0x00, 0x40, 0x06, 0x70, 0x00, 0x40, + 0x06, 0x87, 0x00, 0x01, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x06, 0x50, 0x00, 0x40, 0x06, 0x68, 0x00, 0x03, 0x74, 0x04, 0x9f, + 0x00, 0x40, 0x06, 0x68, 0x00, 0x40, 0x06, 0x87, 0x00, 0x01, 0x56, 0x00, 0x40, + 0x06, 0x87, 0x00, 0x40, 0x06, 0x88, 0x00, 0x06, 0xf3, 0x01, 0x54, 0x23, 0x04, + 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x40, 0x06, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x05, 0x8c, 0x00, 0x40, 0x05, 0x98, 0x00, 0x40, 0x09, 0x10, 0x00, 0x40, + 0x09, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xe8, 0x00, 0x40, 0x05, 0xf8, + 0x00, 0x40, 0x09, 0x48, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x0f, 0x67, 0x6e, 0x75, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x07, 0x04, 0x01, 0x00, 0x2e, 0x73, 0x79, 0x6d, 0x74, 0x61, + 0x62, 0x00, 0x2e, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x68, + 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x70, 0x00, 0x2e, 0x4d, 0x49, 0x50, 0x53, 0x2e, 0x61, 0x62, 0x69, 0x66, 0x6c, + 0x61, 0x67, 0x73, 0x00, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x6e, 0x66, 0x6f, 0x00, + 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x00, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x79, 0x6d, 0x00, 0x2e, 0x64, 0x79, + 0x6e, 0x73, 0x74, 0x72, 0x00, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x2e, 0x74, + 0x65, 0x78, 0x74, 0x00, 0x2e, 0x4d, 0x49, 0x50, 0x53, 0x2e, 0x73, 0x74, 0x75, + 0x62, 0x73, 0x00, 0x2e, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x2e, 0x65, 0x68, 0x5f, + 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x2e, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, + 0x2e, 0x64, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x2e, 0x6a, 0x63, 0x72, 0x00, 0x2e, + 0x72, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x70, 0x00, 0x2e, 0x67, 0x6f, 0x74, 0x00, + 0x2e, 0x73, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x62, 0x73, 0x73, 0x00, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2e, 0x70, 0x64, 0x72, 0x00, + 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x65, + 0x73, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, + 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x61, 0x62, 0x62, 0x72, 0x65, + 0x76, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6c, 0x69, 0x6e, 0x65, + 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x73, 0x74, 0x72, 0x00, 0x2e, + 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6c, 0x6f, 0x63, 0x00, 0x2e, 0x64, 0x65, + 0x62, 0x75, 0x67, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x2e, 0x67, + 0x6e, 0x75, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x00, 0x2e, 0x6d, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, 0x61, 0x62, 0x69, 0x33, + 0x32, 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, 0x01, 0x74, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x03, 0x24, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xec, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x41, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, + 0x10, 0x48, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x41, 0x10, 0x50, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x13, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xf1, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0xff, 0xf1, 0x00, 0x00, 0x00, 0x17, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x25, 0x00, 0x41, 0x0f, + 0xf4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x33, + 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x46, 0x00, 0x41, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x0f, 0x00, 0x00, 0x00, 0x53, 0x00, 0x40, 0x06, 0x90, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x68, 0x00, 0x40, 0x06, 0xd4, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x7b, 0x00, + 0x40, 0x07, 0x24, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x41, 0x10, 0x50, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x41, 0x10, 0x54, 0x00, 0x00, 0x00, 0x04, + 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xae, 0x00, 0x40, 0x08, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xba, 0x00, 0x41, + 0x10, 0x58, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xf1, + 0x00, 0x00, 0x00, 0xc6, 0x00, 0x41, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x41, 0x0f, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xed, + 0x00, 0x40, 0x08, 0x90, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0xff, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x40, 0x08, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x17, 0x00, + 0x40, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x01, 0x20, 0x00, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xf1, 0x00, 0x00, 0x01, 0x24, 0x00, 0x41, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x30, 0x00, 0x41, 0x0f, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x01, 0x3d, 0x00, 0x41, + 0x10, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x01, + 0x4a, 0x00, 0x41, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, + 0x00, 0x00, 0x01, 0x60, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x76, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x01, 0x87, + 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x01, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xa5, 0x00, 0x40, 0x06, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc7, 0x00, + 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x01, 0xce, 0x00, 0x40, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, + 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0xde, 0x00, 0x41, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x04, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, + 0x00, 0x00, 0x02, 0x10, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08, 0x12, + 0x02, 0x00, 0x09, 0x00, 0x00, 0x02, 0x15, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, + 0x00, 0x08, 0x12, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x02, 0x1b, 0x00, 0x41, 0x10, + 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x02, 0x22, + 0x00, 0x41, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, + 0x00, 0x02, 0x27, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x4d, 0x00, 0x41, 0x10, 0x4c, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x02, 0x53, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x63, + 0x72, 0x74, 0x2f, 0x63, 0x72, 0x74, 0x31, 0x2e, 0x63, 0x00, 0x63, 0x72, 0x74, + 0x73, 0x74, 0x75, 0x66, 0x66, 0x2e, 0x63, 0x00, 0x5f, 0x5f, 0x43, 0x54, 0x4f, + 0x52, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x44, 0x54, + 0x4f, 0x52, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x45, + 0x48, 0x5f, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x4a, 0x43, 0x52, 0x5f, 0x4c, 0x49, 0x53, 0x54, + 0x5f, 0x5f, 0x00, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x5f, 0x74, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x73, 0x00, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x74, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, + 0x6e, 0x65, 0x73, 0x00, 0x5f, 0x5f, 0x64, 0x6f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x5f, 0x64, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x61, 0x75, 0x78, 0x00, + 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x2e, 0x33, 0x35, 0x31, + 0x35, 0x00, 0x64, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x78, 0x2e, 0x33, 0x35, + 0x31, 0x37, 0x00, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x6d, + 0x79, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x33, 0x35, 0x32, 0x37, + 0x00, 0x5f, 0x5f, 0x43, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, + 0x00, 0x5f, 0x5f, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x5f, + 0x5f, 0x00, 0x5f, 0x5f, 0x4a, 0x43, 0x52, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, + 0x00, 0x5f, 0x5f, 0x64, 0x6f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, + 0x63, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x61, 0x75, 0x78, 0x00, 0x6d, 0x61, 0x69, + 0x6e, 0x2e, 0x63, 0x00, 0x5f, 0x4d, 0x49, 0x50, 0x53, 0x5f, 0x53, 0x54, 0x55, + 0x42, 0x53, 0x5f, 0x00, 0x5f, 0x44, 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x00, + 0x5f, 0x67, 0x70, 0x00, 0x5f, 0x5f, 0x54, 0x4d, 0x43, 0x5f, 0x45, 0x4e, 0x44, + 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x44, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x44, + 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x64, 0x73, 0x6f, 0x5f, 0x68, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x00, 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x5f, 0x4f, 0x46, + 0x46, 0x53, 0x45, 0x54, 0x5f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x00, 0x5f, + 0x66, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x5f, 0x67, 0x6e, 0x75, 0x5f, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x67, 0x70, 0x00, 0x5f, 0x44, 0x59, 0x4e, 0x41, + 0x4d, 0x49, 0x43, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x49, 0x4e, 0x47, 0x00, 0x5f, + 0x69, 0x6e, 0x69, 0x74, 0x00, 0x5f, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x00, 0x5f, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x49, + 0x54, 0x4d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, + 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x66, + 0x74, 0x65, 0x78, 0x74, 0x00, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x63, 0x00, 0x5f, 0x5f, 0x52, 0x4c, 0x44, + 0x5f, 0x4d, 0x41, 0x50, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x64, 0x65, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, + 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x5f, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x66, + 0x69, 0x6e, 0x69, 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x65, + 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x6c, 0x69, 0x62, 0x63, 0x5f, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x4a, 0x76, 0x5f, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, + 0x73, 0x00, 0x5f, 0x66, 0x62, 0x73, 0x73, 0x00, 0x5f, 0x5f, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x69, + 0x6e, 0x66, 0x6f, 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, 0x1b, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, 0x74, 0x00, 0x00, + 0x01, 0x74, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, + 0x70, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, 0x90, 0x00, + 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x32, 0x70, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, 0xa8, + 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x3b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, + 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, + 0x02, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x40, 0x03, 0x24, 0x00, 0x00, 0x03, 0x24, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x40, 0x04, 0x84, 0x00, 0x00, 0x04, 0x84, 0x00, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x6c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x08, 0xf0, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x09, 0x10, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x09, 0x58, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x00, 0x0f, + 0xec, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x0f, 0xf4, 0x00, 0x00, + 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x0f, 0xfc, 0x00, + 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x95, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x10, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9e, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x41, 0x10, + 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x41, + 0x10, 0x48, 0x00, 0x00, 0x10, 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x41, 0x10, 0x50, 0x00, 0x00, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x70, 0x00, 0x00, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x10, 0x00, 0x00, + 0x01, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x70, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x93, 0x00, + 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x70, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x3a, + 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x70, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, + 0x20, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x70, + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x48, 0x00, 0x00, 0x01, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0a, + 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x15, 0x96, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x15, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x16, 0x18, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x23, 0x6f, 0xff, 0xff, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0x68, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x78, 0x00, 0x00, 0x01, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xbc, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xbc, 0x00, 0x00, 0x02, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00 +}; + + +unsigned char ELF_x64_FILE[] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x07, 0x00, 0x40, 0x00, + 0x16, 0x00, 0x13, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x78, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xe5, 0x74, 0x64, + 0x06, 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, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x52, 0xe5, 0x74, 0x64, 0x04, 0x00, 0x00, 0x00, + 0x78, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6d, 0x75, 0x73, 0x6c, + 0x2d, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x2e, 0x73, 0x6f, 0x2e, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 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, + 0x33, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0xd8, 0x03, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x06, 0x04, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, 0x28, 0x10, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x09, 0x00, 0xf6, 0x04, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x28, 0x10, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, 0x30, 0x10, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x6c, 0x69, 0x62, 0x63, 0x2e, 0x73, 0x6f, 0x00, 0x5f, 0x5f, 0x6c, + 0x69, 0x62, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x61, + 0x69, 0x6e, 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x5f, + 0x62, 0x73, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x65, + 0x6e, 0x64, 0x00, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x5f, 0x49, 0x54, + 0x4d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, + 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, + 0x49, 0x54, 0x4d, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x00, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x5f, 0x4a, 0x76, + 0x5f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x58, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x22, 0x0c, + 0x20, 0x00, 0xff, 0x25, 0x24, 0x0c, 0x20, 0x00, 0x0f, 0x1f, 0x40, 0x00, + 0xff, 0x25, 0x22, 0x0c, 0x20, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0xe9, + 0xe0, 0xff, 0xff, 0xff, 0xb8, 0x2a, 0x00, 0x00, 0x00, 0xc3, 0x48, 0x31, + 0xed, 0x49, 0x89, 0xd1, 0x5e, 0x48, 0x89, 0xe2, 0x48, 0x83, 0xe4, 0xf0, + 0x49, 0xc7, 0xc0, 0xf6, 0x04, 0x40, 0x00, 0x48, 0xc7, 0xc1, 0xd8, 0x03, + 0x40, 0x00, 0x48, 0xc7, 0xc7, 0x00, 0x04, 0x40, 0x00, 0xe8, 0xc2, 0xff, + 0xff, 0xff, 0xeb, 0xfe, 0xb8, 0x2f, 0x10, 0x60, 0x00, 0x55, 0x48, 0x2d, + 0x28, 0x10, 0x60, 0x00, 0x48, 0x83, 0xf8, 0x0e, 0x48, 0x89, 0xe5, 0x76, + 0x1b, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x11, 0x5d, + 0xbf, 0x28, 0x10, 0x60, 0x00, 0xff, 0xe0, 0x66, 0x0f, 0x1f, 0x84, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5d, 0xc3, 0x0f, 0x1f, 0x40, 0x00, 0x66, 0x2e, + 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x28, 0x10, 0x60, + 0x00, 0x55, 0x48, 0x81, 0xee, 0x28, 0x10, 0x60, 0x00, 0x48, 0xc1, 0xfe, + 0x03, 0x48, 0x89, 0xe5, 0x48, 0x89, 0xf0, 0x48, 0xc1, 0xe8, 0x3f, 0x48, + 0x01, 0xc6, 0x48, 0xd1, 0xfe, 0x74, 0x15, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x85, 0xc0, 0x74, 0x0b, 0x5d, 0xbf, 0x28, 0x10, 0x60, 0x00, 0xff, + 0xe0, 0x0f, 0x1f, 0x00, 0x5d, 0xc3, 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, + 0x80, 0x3d, 0x71, 0x0b, 0x20, 0x00, 0x00, 0x75, 0x11, 0x55, 0x48, 0x89, + 0xe5, 0xe8, 0x6e, 0xff, 0xff, 0xff, 0x5d, 0xc6, 0x05, 0x5e, 0x0b, 0x20, + 0x00, 0x01, 0xf3, 0xc3, 0x0f, 0x1f, 0x40, 0x00, 0xbf, 0x88, 0x0e, 0x60, + 0x00, 0x48, 0x83, 0x3f, 0x00, 0x75, 0x05, 0xeb, 0x93, 0x0f, 0x1f, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0xf1, 0x55, 0x48, + 0x89, 0xe5, 0xff, 0xd0, 0x5d, 0xe9, 0x7a, 0xff, 0xff, 0xff, 0x50, 0x58, + 0xc3, 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, + 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, + 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, 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, 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, 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, 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, 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, 0xd0, 0x04, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x03, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x40, 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, 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf6, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x43, 0x43, 0x3a, + 0x20, 0x28, 0x55, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x20, 0x35, 0x2e, 0x34, + 0x2e, 0x30, 0x2d, 0x36, 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x31, 0x7e, + 0x31, 0x36, 0x2e, 0x30, 0x34, 0x2e, 0x34, 0x29, 0x20, 0x35, 0x2e, 0x34, + 0x2e, 0x30, 0x20, 0x32, 0x30, 0x31, 0x36, 0x30, 0x36, 0x30, 0x39, 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, 0x03, 0x00, 0x01, 0x00, + 0xc8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, + 0xe8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x28, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x30, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, + 0xc0, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, + 0xd8, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x00, + 0xe0, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, + 0x00, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x09, 0x00, + 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0a, 0x00, + 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0b, 0x00, + 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00, + 0x80, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0d, 0x00, + 0x88, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, + 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0f, 0x00, + 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, + 0x20, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x11, 0x00, + 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x12, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, + 0x88, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, + 0x30, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, + 0x70, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, + 0xb0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, + 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, + 0x80, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, + 0xd0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, + 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, + 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, + 0x88, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, + 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, + 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, + 0x20, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, + 0x00, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, + 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, + 0xd8, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, + 0x06, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, + 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x10, 0x00, 0x09, 0x00, + 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, + 0x30, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x72, 0x74, 0x73, 0x74, 0x75, 0x66, + 0x66, 0x2e, 0x63, 0x00, 0x5f, 0x5f, 0x4a, 0x43, 0x52, 0x5f, 0x4c, 0x49, + 0x53, 0x54, 0x5f, 0x5f, 0x00, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x5f, 0x74, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, + 0x73, 0x00, 0x5f, 0x5f, 0x64, 0x6f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x5f, 0x64, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x61, 0x75, 0x78, 0x00, + 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x2e, 0x37, 0x35, + 0x38, 0x35, 0x00, 0x5f, 0x5f, 0x64, 0x6f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x5f, 0x64, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x61, 0x75, 0x78, + 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x00, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, + 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x00, 0x5f, 0x5f, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x5f, 0x69, 0x6e, 0x69, 0x74, + 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x63, 0x00, 0x5f, 0x5f, 0x46, 0x52, + 0x41, 0x4d, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, + 0x4a, 0x43, 0x52, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x44, + 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x00, 0x5f, 0x5f, 0x54, 0x4d, 0x43, + 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x64, 0x73, 0x6f, + 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x5f, 0x47, 0x4c, 0x4f, + 0x42, 0x41, 0x4c, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x54, + 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x00, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00, + 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, + 0x65, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x5f, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x00, + 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x65, 0x6e, 0x64, 0x00, + 0x5f, 0x5f, 0x6c, 0x69, 0x62, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x4a, 0x76, 0x5f, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, + 0x73, 0x00, 0x00, 0x2e, 0x73, 0x79, 0x6d, 0x74, 0x61, 0x62, 0x00, 0x2e, + 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, + 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, + 0x00, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, + 0x79, 0x6d, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x74, 0x72, 0x00, 0x2e, + 0x72, 0x65, 0x6c, 0x61, 0x2e, 0x70, 0x6c, 0x74, 0x00, 0x2e, 0x69, 0x6e, + 0x69, 0x74, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x66, 0x69, + 0x6e, 0x69, 0x00, 0x2e, 0x65, 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x00, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x00, 0x2e, 0x66, 0x69, 0x6e, 0x69, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x00, 0x2e, 0x6a, 0x63, 0x72, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, + 0x69, 0x63, 0x00, 0x2e, 0x67, 0x6f, 0x74, 0x2e, 0x70, 0x6c, 0x74, 0x00, + 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x62, 0x73, 0x73, 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, + 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 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, 0x23, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 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, 0x39, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd8, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 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, + 0x3e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf6, 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, 0x4f, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 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, + 0x55, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x88, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 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, 0x99, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5e, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 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, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 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 +}; + + +uint8_t MACHO_X86_FILE[] = { + 0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x24, 0x04, 0x00, 0x00, + 0x85, 0x00, 0x20, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x50, 0x41, + 0x47, 0x45, 0x5a, 0x45, 0x52, 0x4f, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x8c, 0x01, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, + 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x1e, 0x00, 0x00, + 0xa6, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, + 0x5f, 0x73, 0x74, 0x75, 0x62, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x1f, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x36, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x05, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x73, 0x74, + 0x75, 0x62, 0x5f, 0x68, 0x65, 0x6c, 0x70, 0x65, + 0x72, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x1f, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x44, 0x0f, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x1f, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x64, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x75, 0x6e, + 0x77, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x66, + 0x6f, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xac, 0x1f, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x6e, 0x6c, 0x5f, 0x73, 0x79, 0x6d, + 0x62, 0x6f, 0x6c, 0x5f, 0x70, 0x74, 0x72, 0x00, + 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x6c, 0x61, + 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, + 0x70, 0x74, 0x72, 0x00, 0x5f, 0x5f, 0x44, 0x41, + 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, + 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x20, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x20, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x44, 0x20, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x88, 0x20, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0xdc, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 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, + 0xc4, 0x20, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x2f, 0x75, 0x73, 0x72, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x64, 0x79, 0x6c, + 0x64, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x5f, 0xb5, 0x95, 0x0f, + 0x40, 0x25, 0x3d, 0x4f, 0xa8, 0xfb, 0x96, 0x48, + 0xc1, 0x74, 0x07, 0x90, 0x24, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a, 0x00, + 0x00, 0x0a, 0x0a, 0x00, 0x2a, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x80, + 0x18, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x04, + 0x00, 0x00, 0x01, 0x00, 0x2f, 0x75, 0x73, 0x72, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x69, 0x62, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, + 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x70, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x74, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x74, 0x20, 0x00, 0x00, 0x14, 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 +}; + + +uint8_t MACHO_PPC_FILE[] = { + 0xfe, 0xed, 0xfa, 0xce, 0x00, 0x00, 0x00, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x05, 0xcc, + 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x38, 0x5f, 0x5f, 0x50, 0x41, + 0x47, 0x45, 0x5a, 0x45, 0x52, 0x4f, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x02, 0x14, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, + 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb8, + 0x00, 0x00, 0xb8, 0x38, 0x00, 0x00, 0x0e, 0xb8, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x70, 0x69, 0x63, 0x73, 0x79, 0x6d, + 0x62, 0x6f, 0x6c, 0x5f, 0x73, 0x74, 0x75, 0x62, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd6, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xf0, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x5f, 0x5f, 0x73, 0x79, + 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x73, 0x74, 0x75, + 0x62, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf0, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, + 0x5f, 0x5f, 0x70, 0x69, 0x63, 0x73, 0x79, 0x6d, + 0x62, 0x6f, 0x6c, 0x73, 0x74, 0x75, 0x62, 0x31, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd6, 0xf0, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0xc6, 0xf0, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x5f, 0x5f, 0x63, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, + 0x00, 0x00, 0x1e, 0x88, 0x00, 0x00, 0xd0, 0xf0, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x78, 0x00, 0x00, 0x00, 0x50, + 0x00, 0x00, 0xef, 0x78, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x65, 0x68, + 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc8, + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0xef, 0xc8, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xd0, + 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x54, + 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x6c, 0x61, + 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, + 0x70, 0x74, 0x72, 0x00, 0x5f, 0x5f, 0x44, 0x41, + 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x54, + 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0xf2, 0x54, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x6e, 0x6c, 0x5f, 0x73, 0x79, 0x6d, + 0x62, 0x6f, 0x6c, 0x5f, 0x70, 0x74, 0x72, 0x00, + 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x03, 0x94, 0x00, 0x00, 0x00, 0x7c, + 0x00, 0x00, 0xf3, 0x94, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x64, 0x79, + 0x6c, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x44, 0x41, + 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x10, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xf4, 0x10, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x04, 0x2c, 0x00, 0x00, 0x04, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x44, 0x41, + 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x40, + 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, + 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, + 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb3, 0xd0, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x0c, 0x2f, 0x75, 0x73, 0x72, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x64, 0x79, 0x6c, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x18, + 0x42, 0x3a, 0x3b, 0x7c, 0x00, 0x47, 0x01, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x2f, 0x75, 0x73, 0x72, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x69, 0x62, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, + 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x3f, + 0x00, 0x01, 0x73, 0x48, 0x00, 0x00, 0x40, 0x88, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7a, + 0x00, 0x00, 0x08, 0x7a, 0x00, 0x00, 0x00, 0x6f, + 0x00, 0x00, 0x08, 0xe9, 0x00, 0x00, 0x00, 0x56, + 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, 0x01, 0x70, 0x4c, 0x00, 0x00, 0x00, 0xbf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x01, 0x6e, 0xf4, 0x00, 0x00, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb0, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x1e, 0xb8, 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, 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, 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, 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 +}; + + +uint8_t MACHO_X86_OBJECT_FILE[] = { + 0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, + 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x48, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x54, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 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, + 0x55, 0x89, 0xe5, 0x83, 0xec, 0x0c, 0x8b, 0x45, + 0x08, 0x89, 0x45, 0xfc, 0xc7, 0x45, 0xf4, 0x01, + 0x00, 0x00, 0x00, 0xc7, 0x45, 0xf8, 0x01, 0x00, + 0x00, 0x00, 0x8b, 0x45, 0xf8, 0x3b, 0x45, 0xfc, + 0x0f, 0x8f, 0x1a, 0x00, 0x00, 0x00, 0x8b, 0x45, + 0xf4, 0x0f, 0xaf, 0x45, 0xf8, 0x89, 0x45, 0xf4, + 0x8b, 0x45, 0xf8, 0x05, 0x01, 0x00, 0x00, 0x00, + 0x89, 0x45, 0xf8, 0xe9, 0xda, 0xff, 0xff, 0xff, + 0x8b, 0x45, 0xf4, 0x83, 0xc4, 0x0c, 0x5d, 0xc3, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x5a, + 0x39, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x00 +}; + + +uint8_t MACHO_X86_64_DYLIB_FILE[] = { + 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, + 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, + 0x85, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 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, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x0f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x98, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x98, 0x0f, 0x00, 0x00, 0x02, 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, + 0x5f, 0x5f, 0x65, 0x68, 0x5f, 0x66, 0x72, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x0f, 0x00, 0x00, 0x03, 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, + 0x19, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, + 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x61, 0x63, 0x74, 0x5f, 0x78, 0x38, 0x36, + 0x5f, 0x36, 0x34, 0x2e, 0x64, 0x79, 0x6c, 0x69, + 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x80, 0x30, 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, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x38, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x58, 0x10, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 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, + 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x8c, 0x90, 0x46, 0x12, 0x62, 0x53, 0x3f, 0xa1, + 0xb8, 0xd2, 0xd5, 0x82, 0x98, 0x48, 0xa8, 0xfc, + 0x24, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x0a, 0x00, 0x00, 0x0a, 0x0a, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xbd, 0x04, 0x00, 0x00, 0x01, 0x00, + 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, + 0x2f, 0x6c, 0x69, 0x62, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x2e, 0x42, 0x2e, 0x64, 0x79, 0x6c, + 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x20, 0x10, 0x00, 0x00, 0x18, 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 +}; + +uint8_t DEX_FILE[] = { + 0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00, + 0x2F, 0x60, 0x9C, 0x3F, 0x1B, 0x04, 0xEF, 0x0F, + 0x8C, 0xF7, 0x2C, 0x57, 0xB0, 0xF3, 0x2C, 0xE7, + 0xF1, 0xBB, 0xDA, 0xEF, 0x12, 0x00, 0x07, 0x82, + 0x90, 0x02, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, + 0x8C, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0x48, 0x01, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, + 0x5A, 0x01, 0x00, 0x00, 0x5D, 0x01, 0x00, 0x00, + 0x84, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, + 0xAC, 0x01, 0x00, 0x00, 0xAF, 0x01, 0x00, 0x00, + 0xBE, 0x01, 0x00, 0x00, 0xD4, 0x01, 0x00, 0x00, + 0xDA, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xE5, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x31, 0x4B, 0x31, 0x35, 0xC2, 0x4D, 0x44, 0x64, + 0x68, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xE1, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x70, 0x10, 0x02, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x08, 0x3C, 0x63, 0x6C, 0x69, 0x6E, 0x69, 0x74, + 0x3E, 0x00, 0x06, 0x3C, 0x69, 0x6E, 0x69, 0x74, + 0x3E, 0x00, 0x01, 0x4A, 0x00, 0x25, 0x4C, 0x63, + 0x6F, 0x6D, 0x2F, 0x61, 0x6E, 0x64, 0x72, 0x6F, + 0x69, 0x64, 0x2F, 0x74, 0x6F, 0x6F, 0x6C, 0x73, + 0x2F, 0x69, 0x72, 0x2F, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2F, 0x41, 0x70, 0x70, 0x49, 0x6E, + 0x66, 0x6F, 0x3B, 0x00, 0x12, 0x4C, 0x6A, 0x61, + 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, + 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x3B, 0x00, + 0x12, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, + 0x61, 0x6E, 0x67, 0x2F, 0x53, 0x74, 0x72, 0x69, + 0x6E, 0x67, 0x3B, 0x00, 0x01, 0x56, 0x00, 0x0D, + 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x49, 0x64, 0x00, 0x14, 0x63, + 0x6F, 0x6D, 0x2E, 0x67, 0x6F, 0x6F, 0x67, 0x6C, + 0x65, 0x2E, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x79, + 0x61, 0x72, 0x61, 0x00, 0x04, 0x74, 0x68, 0x69, + 0x73, 0x00, 0x05, 0x74, 0x6F, 0x6B, 0x65, 0x6E, + 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, + 0x00, 0x00, 0x09, 0x01, 0x09, 0x00, 0x88, 0x80, + 0x04, 0x84, 0x02, 0x01, 0x81, 0x80, 0x04, 0xB0, + 0x02, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xBC, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xE4, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0x02, 0x20, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x48, 0x01, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xE1, 0x01, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xE5, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00 +}; \ No newline at end of file diff --git a/yara-master/tests/data/baz.yar b/yara-master/tests/data/baz.yar new file mode 100644 index 0000000..25a89aa --- /dev/null +++ b/yara-master/tests/data/baz.yar @@ -0,0 +1 @@ +rule baz { condition: true } diff --git a/yara-master/tests/data/foo.yar b/yara-master/tests/data/foo.yar new file mode 100644 index 0000000..507213c --- /dev/null +++ b/yara-master/tests/data/foo.yar @@ -0,0 +1,3 @@ +include "include/bar.yar" + +rule foo { condition: bar } diff --git a/yara-master/tests/data/include/bar.yar b/yara-master/tests/data/include/bar.yar new file mode 100644 index 0000000..b5db2ab --- /dev/null +++ b/yara-master/tests/data/include/bar.yar @@ -0,0 +1,3 @@ +include "../baz.yar" + +rule bar { condition: baz } diff --git a/yara-master/tests/data/tiny b/yara-master/tests/data/tiny new file mode 100644 index 0000000..0513854 Binary files /dev/null and b/yara-master/tests/data/tiny differ diff --git a/yara-master/tests/data/tiny-idata-51ff b/yara-master/tests/data/tiny-idata-51ff new file mode 100644 index 0000000..f2fed16 Binary files /dev/null and b/yara-master/tests/data/tiny-idata-51ff differ diff --git a/yara-master/tests/data/tiny-idata-5200 b/yara-master/tests/data/tiny-idata-5200 new file mode 100644 index 0000000..9547e7e Binary files /dev/null and b/yara-master/tests/data/tiny-idata-5200 differ diff --git a/yara-master/tests/data/tiny-overlay b/yara-master/tests/data/tiny-overlay new file mode 100644 index 0000000..25fc362 Binary files /dev/null and b/yara-master/tests/data/tiny-overlay differ diff --git a/yara-master/tests/data/tiny-universal b/yara-master/tests/data/tiny-universal new file mode 100644 index 0000000..b308437 Binary files /dev/null and b/yara-master/tests/data/tiny-universal differ diff --git a/yara-master/tests/data/tiny.notes b/yara-master/tests/data/tiny.notes new file mode 100644 index 0000000..d2c0e68 --- /dev/null +++ b/yara-master/tests/data/tiny.notes @@ -0,0 +1,22 @@ +tiny.exe was compiled from a simple oneliner, + + int main() { return 42; } + + $ i686-w64-mingw32-gcc -s -Wl,--file-alignment=4096 -o tiny.exe tiny.c + +To demonstrate issue #429, two patched executables have been generated +where the PointerToRawData for the .idata section (offset 0x22c) was +changed from 0x5000 to 0x51ff (tiny-idata-51ff.exe) and 0x5200 +(tiny-idata-5200.exe), respectively. While tiny-idata-51ff.exe can be +executed in Windows XP, tiny-idata-5200.exe can not. + + + +Compiler version used to produce tiny.exe: + +$ i686-w64-mingw32-gcc --version +i686-w64-mingw32-gcc (GCC) 5.3.1 20160205 +Copyright (C) 2015 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + diff --git a/yara-master/tests/data/xor.out b/yara-master/tests/data/xor.out new file mode 100644 index 0000000..8ff15e4 Binary files /dev/null and b/yara-master/tests/data/xor.out differ diff --git a/yara-master/tests/data/xornocase.out b/yara-master/tests/data/xornocase.out new file mode 100644 index 0000000..a34d65b Binary files /dev/null and b/yara-master/tests/data/xornocase.out differ diff --git a/yara-master/tests/data/xorwide.out b/yara-master/tests/data/xorwide.out new file mode 100644 index 0000000..92860a1 Binary files /dev/null and b/yara-master/tests/data/xorwide.out differ diff --git a/yara-master/tests/oss-fuzz/dex_fuzzer.cc b/yara-master/tests/oss-fuzz/dex_fuzzer.cc new file mode 100644 index 0000000..db8506e --- /dev/null +++ b/yara-master/tests/oss-fuzz/dex_fuzzer.cc @@ -0,0 +1,53 @@ +#include +#include + +#include + + +YR_RULES* rules = NULL; + + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + YR_COMPILER* compiler; + + if (yr_initialize() != ERROR_SUCCESS) + return 0; + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + return 0; + + if (yr_compiler_add_string(compiler, "import \"dex\"", NULL) != 0) + return 0; + + if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS) + return 0; + + yr_compiler_destroy(compiler); + + return 0; +} + + +int callback(int message, void* message_data, void* user_data) +{ + return CALLBACK_CONTINUE; +} + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (rules == NULL) + return 1; + + yr_rules_scan_mem( + rules, + data, + size, + SCAN_FLAGS_NO_TRYCATCH, + callback, + NULL, + 0); + + return 0; +} \ No newline at end of file diff --git a/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/1cf540db2f048bb21bd89379a57279b9ff4c308558715a3baee666a47393d86e b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/1cf540db2f048bb21bd89379a57279b9ff4c308558715a3baee666a47393d86e new file mode 100644 index 0000000..c5080f8 Binary files /dev/null and b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/1cf540db2f048bb21bd89379a57279b9ff4c308558715a3baee666a47393d86e differ diff --git a/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/25ef27f9543444652f0c68fe412d3da627a1d2a590b0a2b30e47466c1e962136 b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/25ef27f9543444652f0c68fe412d3da627a1d2a590b0a2b30e47466c1e962136 new file mode 100644 index 0000000..7ca3cb7 Binary files /dev/null and b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/25ef27f9543444652f0c68fe412d3da627a1d2a590b0a2b30e47466c1e962136 differ diff --git a/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/27fb31059503773723597edb875c937af971a6c15f91aac8c03c1fbdfa9e918c b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/27fb31059503773723597edb875c937af971a6c15f91aac8c03c1fbdfa9e918c new file mode 100644 index 0000000..528eef2 Binary files /dev/null and b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/27fb31059503773723597edb875c937af971a6c15f91aac8c03c1fbdfa9e918c differ diff --git a/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/3ba9c082050f62e725c87ce4cf9f592fe9f177faf3a0c879f8fbe87312ca4b2c b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/3ba9c082050f62e725c87ce4cf9f592fe9f177faf3a0c879f8fbe87312ca4b2c new file mode 100644 index 0000000..50e9e40 Binary files /dev/null and b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/3ba9c082050f62e725c87ce4cf9f592fe9f177faf3a0c879f8fbe87312ca4b2c differ diff --git a/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/b1203d95c56f02e7e6dbea714275cc05b47ac2510958b85f436571b801af44e7 b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/b1203d95c56f02e7e6dbea714275cc05b47ac2510958b85f436571b801af44e7 new file mode 100644 index 0000000..8eedb6f Binary files /dev/null and b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/b1203d95c56f02e7e6dbea714275cc05b47ac2510958b85f436571b801af44e7 differ diff --git a/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/b343d1058063e6e4b652ccf0589f93d0dbb6b092960e4aebc3c3c58894831359 b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/b343d1058063e6e4b652ccf0589f93d0dbb6b092960e4aebc3c3c58894831359 new file mode 100644 index 0000000..81c63f1 Binary files /dev/null and b/yara-master/tests/oss-fuzz/dex_fuzzer_corpus/b343d1058063e6e4b652ccf0589f93d0dbb6b092960e4aebc3c3c58894831359 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer.cc b/yara-master/tests/oss-fuzz/elf_fuzzer.cc new file mode 100644 index 0000000..f79c625 --- /dev/null +++ b/yara-master/tests/oss-fuzz/elf_fuzzer.cc @@ -0,0 +1,82 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#include + + +YR_RULES* rules = NULL; + + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + YR_COMPILER* compiler; + + if (yr_initialize() != ERROR_SUCCESS) + return 0; + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + return 0; + + if (yr_compiler_add_string(compiler, "import \"elf\"", NULL) != 0) + return 0; + + if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS) + return 0; + + yr_compiler_destroy(compiler); + + return 0; +} + + +int callback(int message, void* message_data, void* user_data) +{ + return CALLBACK_CONTINUE; +} + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (rules == NULL) + return 1; + + yr_rules_scan_mem( + rules, + data, + size, + SCAN_FLAGS_NO_TRYCATCH, + callback, + NULL, + 0); + + return 0; +} \ No newline at end of file diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-03bca75466ee42801a8bff280de04afc3d1a3637 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-03bca75466ee42801a8bff280de04afc3d1a3637 new file mode 100644 index 0000000..22e05fc Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-03bca75466ee42801a8bff280de04afc3d1a3637 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-086300bbce1c6537573057336a343a82d483e2c0 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-086300bbce1c6537573057336a343a82d483e2c0 new file mode 100644 index 0000000..a375741 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-086300bbce1c6537573057336a343a82d483e2c0 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-2cafe4de66d87a83d83aaf65d8e4cea48f2c1144 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-2cafe4de66d87a83d83aaf65d8e4cea48f2c1144 new file mode 100644 index 0000000..92f5fd4 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-2cafe4de66d87a83d83aaf65d8e4cea48f2c1144 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-370485c5b087f780a2447a03d775f7188e323d31 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-370485c5b087f780a2447a03d775f7188e323d31 new file mode 100644 index 0000000..3ad53da Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-370485c5b087f780a2447a03d775f7188e323d31 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-49bb55d669fda0683f945b89396a6bd458caf2d8 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-49bb55d669fda0683f945b89396a6bd458caf2d8 new file mode 100644 index 0000000..7faaf87 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-49bb55d669fda0683f945b89396a6bd458caf2d8 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-49d00b6b033eaeb07cd39809dbc1d7ba2df196ec b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-49d00b6b033eaeb07cd39809dbc1d7ba2df196ec new file mode 100644 index 0000000..27b1057 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-49d00b6b033eaeb07cd39809dbc1d7ba2df196ec differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-723296cdc1c0dba83ea767d69286429e608c46c3 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-723296cdc1c0dba83ea767d69286429e608c46c3 new file mode 100644 index 0000000..667451e Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-723296cdc1c0dba83ea767d69286429e608c46c3 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-7dc27920ae1cb85333e7f2735a45014488134673 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-7dc27920ae1cb85333e7f2735a45014488134673 new file mode 100644 index 0000000..4fc2221 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-7dc27920ae1cb85333e7f2735a45014488134673 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-7e945ce5f43f515ea078c558a2e3205089d414e5 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-7e945ce5f43f515ea078c558a2e3205089d414e5 new file mode 100644 index 0000000..0dcaf2e Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-7e945ce5f43f515ea078c558a2e3205089d414e5 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-a809561e75b94bd5d4d8cf7488d9e2663fc1ccdc b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-a809561e75b94bd5d4d8cf7488d9e2663fc1ccdc new file mode 100644 index 0000000..b49139d Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-a809561e75b94bd5d4d8cf7488d9e2663fc1ccdc differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-a8715a38a94161c9509309f5dbb5a7936aba8376 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-a8715a38a94161c9509309f5dbb5a7936aba8376 new file mode 100644 index 0000000..95cfb85 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-a8715a38a94161c9509309f5dbb5a7936aba8376 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-aee928239444a7b039500d4499035e6d30cb89da b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-aee928239444a7b039500d4499035e6d30cb89da new file mode 100644 index 0000000..c43b312 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-aee928239444a7b039500d4499035e6d30cb89da differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c4002396c52065d21fe1c1f05f8937aab8d59c18 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c4002396c52065d21fe1c1f05f8937aab8d59c18 new file mode 100644 index 0000000..dedcdf3 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c4002396c52065d21fe1c1f05f8937aab8d59c18 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c610b3036f195ad7fb05248a530278aad37b438d b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c610b3036f195ad7fb05248a530278aad37b438d new file mode 100644 index 0000000..db41bf5 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c610b3036f195ad7fb05248a530278aad37b438d differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c6569e6e28f0a18bb2f3bf49c982333a359bed67 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c6569e6e28f0a18bb2f3bf49c982333a359bed67 new file mode 100644 index 0000000..b8819df Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-c6569e6e28f0a18bb2f3bf49c982333a359bed67 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-cc6844f44825a785de1b079c88f728e1c0f779fb b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-cc6844f44825a785de1b079c88f728e1c0f779fb new file mode 100644 index 0000000..d070f88 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-cc6844f44825a785de1b079c88f728e1c0f779fb differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-f1fd008da535b110853885221ebfaac3f262a1c1e280f10929f7b353c44996c8 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-f1fd008da535b110853885221ebfaac3f262a1c1e280f10929f7b353c44996c8 new file mode 100644 index 0000000..72cde9a Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/crash-f1fd008da535b110853885221ebfaac3f262a1c1e280f10929f7b353c44996c8 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-6bf54fca69bb5029676d747b12c74b597dd8c5939343ea8f2cbfea9e666dd6b1 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-6bf54fca69bb5029676d747b12c74b597dd8c5939343ea8f2cbfea9e666dd6b1 new file mode 100644 index 0000000..28412cf Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-6bf54fca69bb5029676d747b12c74b597dd8c5939343ea8f2cbfea9e666dd6b1 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-789fc6da83de39c3ff394a950b0831f6fe5b63a85a46aaa236048b5c1dcf0e59 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-789fc6da83de39c3ff394a950b0831f6fe5b63a85a46aaa236048b5c1dcf0e59 new file mode 100644 index 0000000..31c62f5 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-789fc6da83de39c3ff394a950b0831f6fe5b63a85a46aaa236048b5c1dcf0e59 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-939e9cd87b0d80834210fbf54edc66341aebf416d7509f6633f1d49766978b22 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-939e9cd87b0d80834210fbf54edc66341aebf416d7509f6633f1d49766978b22 new file mode 100644 index 0000000..bb32bb9 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-939e9cd87b0d80834210fbf54edc66341aebf416d7509f6633f1d49766978b22 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-93a9fd1909dd49fc2a9b654333504f249cdac58126d3cfc4728577e78cb3eb89 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-93a9fd1909dd49fc2a9b654333504f249cdac58126d3cfc4728577e78cb3eb89 new file mode 100644 index 0000000..ad53b0b Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-93a9fd1909dd49fc2a9b654333504f249cdac58126d3cfc4728577e78cb3eb89 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-b5b03a1f305b2cc1c158e01fee6c08c65145325d4e073f04d969329577077862 b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-b5b03a1f305b2cc1c158e01fee6c08c65145325d4e073f04d969329577077862 new file mode 100644 index 0000000..29b31f7 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-b5b03a1f305b2cc1c158e01fee6c08c65145325d4e073f04d969329577077862 differ diff --git a/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-fa8bbacb5a12f057a0ed3999c37d78b4991e6b201bda4dc9a75a7c7970c7690d b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-fa8bbacb5a12f057a0ed3999c37d78b4991e6b201bda4dc9a75a7c7970c7690d new file mode 100644 index 0000000..83f9903 Binary files /dev/null and b/yara-master/tests/oss-fuzz/elf_fuzzer_corpus/poc-fa8bbacb5a12f057a0ed3999c37d78b4991e6b201bda4dc9a75a7c7970c7690d differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer.cc b/yara-master/tests/oss-fuzz/macho_fuzzer.cc new file mode 100644 index 0000000..df93a2c --- /dev/null +++ b/yara-master/tests/oss-fuzz/macho_fuzzer.cc @@ -0,0 +1,87 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#include + +const char* RULES = \ + "import \"macho\"" + "rule test {" + " condition:" + " macho.segments[1].sections[0].segname == \"__TEXT\"" + "}"; + +YR_RULES* rules = NULL; + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + YR_COMPILER* compiler; + + if (yr_initialize() != ERROR_SUCCESS) + return 0; + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + return 0; + + if (yr_compiler_add_string(compiler, RULES, NULL) != 0) + return 0; + + if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS) + return 0; + + yr_compiler_destroy(compiler); + + return 0; +} + + +int callback(int message, void* message_data, void* user_data) +{ + return CALLBACK_CONTINUE; +} + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (rules == NULL) + return 1; + + yr_rules_scan_mem( + rules, + data, + size, + SCAN_FLAGS_NO_TRYCATCH, + callback, + NULL, + 0); + + return 0; +} diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/1443c3cfb47c5eb41022a7063c24ab1bc9e45bfc31e98d5e6d3aa8377599b983 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/1443c3cfb47c5eb41022a7063c24ab1bc9e45bfc31e98d5e6d3aa8377599b983 new file mode 100644 index 0000000..a6a9874 Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/1443c3cfb47c5eb41022a7063c24ab1bc9e45bfc31e98d5e6d3aa8377599b983 differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/589f7b0e30d885ed91229646e58ccc7615007d2fab06451fef8785c6126adba7 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/589f7b0e30d885ed91229646e58ccc7615007d2fab06451fef8785c6126adba7 new file mode 100644 index 0000000..90a45e7 Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/589f7b0e30d885ed91229646e58ccc7615007d2fab06451fef8785c6126adba7 differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/5eefacbe52990526e4953802249447dd8c0a4b537459ca41e005a7173ca46138 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/5eefacbe52990526e4953802249447dd8c0a4b537459ca41e005a7173ca46138 new file mode 100644 index 0000000..438dbbf Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/5eefacbe52990526e4953802249447dd8c0a4b537459ca41e005a7173ca46138 differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/6164a837fd33574f37464a765ab461fff94b52e659b114fb6109f2635678c564 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/6164a837fd33574f37464a765ab461fff94b52e659b114fb6109f2635678c564 new file mode 100644 index 0000000..0de5947 Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/6164a837fd33574f37464a765ab461fff94b52e659b114fb6109f2635678c564 differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/66528aeb35dd705cc26a7daf4b8eda684f620efebfa0740fab84043e371ed566 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/66528aeb35dd705cc26a7daf4b8eda684f620efebfa0740fab84043e371ed566 new file mode 100644 index 0000000..23ad01c Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/66528aeb35dd705cc26a7daf4b8eda684f620efebfa0740fab84043e371ed566 differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/6af5d157184d9144f86668f83e81760898df5db3c9e209596eb5fd9a91a7eeba b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/6af5d157184d9144f86668f83e81760898df5db3c9e209596eb5fd9a91a7eeba new file mode 100644 index 0000000..aedcc77 Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/6af5d157184d9144f86668f83e81760898df5db3c9e209596eb5fd9a91a7eeba differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/797d1d450421b771482c0cc03f472e4eccbc9e4f544b6c12c1d4f070dec3c381 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/797d1d450421b771482c0cc03f472e4eccbc9e4f544b6c12c1d4f070dec3c381 new file mode 100644 index 0000000..04ce88d Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/797d1d450421b771482c0cc03f472e4eccbc9e4f544b6c12c1d4f070dec3c381 differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/85494d8cb5753f1ad09be39428135feb35eb4ef44f39d6e1e75e2ad30d93e158 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/85494d8cb5753f1ad09be39428135feb35eb4ef44f39d6e1e75e2ad30d93e158 new file mode 100644 index 0000000..31e6fdd Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/85494d8cb5753f1ad09be39428135feb35eb4ef44f39d6e1e75e2ad30d93e158 differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/b225048e85b14f08a43dd4752b9bb4b20840f5a8726eac0ff765d45c9e619828 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/b225048e85b14f08a43dd4752b9bb4b20840f5a8726eac0ff765d45c9e619828 new file mode 100644 index 0000000..5835379 Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/b225048e85b14f08a43dd4752b9bb4b20840f5a8726eac0ff765d45c9e619828 differ diff --git a/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/fda81421d7403180923717a94e77aade8c9286d5b8de3ae0e2812343b666c6a7 b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/fda81421d7403180923717a94e77aade8c9286d5b8de3ae0e2812343b666c6a7 new file mode 100644 index 0000000..c1357be Binary files /dev/null and b/yara-master/tests/oss-fuzz/macho_fuzzer_corpus/fda81421d7403180923717a94e77aade8c9286d5b8de3ae0e2812343b666c6a7 differ diff --git a/yara-master/tests/oss-fuzz/pe_fuzzer.cc b/yara-master/tests/oss-fuzz/pe_fuzzer.cc new file mode 100644 index 0000000..314a668 --- /dev/null +++ b/yara-master/tests/oss-fuzz/pe_fuzzer.cc @@ -0,0 +1,87 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#include + +const char* RULES = \ + "import \"pe\"" + "rule test {" + " condition:" + " pe.rva_to_offset(pe.sections[0].virtual_address) == pe.sections[0].raw_data_offset" + "}"; + +YR_RULES* rules = NULL; + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + YR_COMPILER* compiler; + + if (yr_initialize() != ERROR_SUCCESS) + return 0; + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + return 0; + + if (yr_compiler_add_string(compiler, RULES, NULL) != 0) + return 0; + + if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS) + return 0; + + yr_compiler_destroy(compiler); + + return 0; +} + + +int callback(int message, void* message_data, void* user_data) +{ + return CALLBACK_CONTINUE; +} + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (rules == NULL) + return 1; + + yr_rules_scan_mem( + rules, + data, + size, + SCAN_FLAGS_NO_TRYCATCH, + callback, + NULL, + 0); + + return 0; +} \ No newline at end of file diff --git a/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/00388b550a2603a9e219bcb48acaf8cc115653cb1ea84cb4bccceb1aabe755b6 b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/00388b550a2603a9e219bcb48acaf8cc115653cb1ea84cb4bccceb1aabe755b6 new file mode 100644 index 0000000..b796542 Binary files /dev/null and b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/00388b550a2603a9e219bcb48acaf8cc115653cb1ea84cb4bccceb1aabe755b6 differ diff --git a/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/12f50a7dbf0c42f61ae1c351b2a9f75e8edb3bb55e582619edc7ece4eb0a3094 b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/12f50a7dbf0c42f61ae1c351b2a9f75e8edb3bb55e582619edc7ece4eb0a3094 new file mode 100644 index 0000000..9961be2 Binary files /dev/null and b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/12f50a7dbf0c42f61ae1c351b2a9f75e8edb3bb55e582619edc7ece4eb0a3094 differ diff --git a/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/967af267b4124bada8f507cebf25f2192d146a4d63be71b45bfc03c5da7f21a7 b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/967af267b4124bada8f507cebf25f2192d146a4d63be71b45bfc03c5da7f21a7 new file mode 100644 index 0000000..5fdb3c6 Binary files /dev/null and b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/967af267b4124bada8f507cebf25f2192d146a4d63be71b45bfc03c5da7f21a7 differ diff --git a/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/99e98cb7096dee974e28fea0f76f1c30bc44fd5762cb12b2702910a28b28f95f b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/99e98cb7096dee974e28fea0f76f1c30bc44fd5762cb12b2702910a28b28f95f new file mode 100644 index 0000000..e94e5c3 Binary files /dev/null and b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/99e98cb7096dee974e28fea0f76f1c30bc44fd5762cb12b2702910a28b28f95f differ diff --git a/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/clusterfuzz-testcase-minimized-5211130361282560 b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/clusterfuzz-testcase-minimized-5211130361282560 new file mode 100644 index 0000000..a2452cc Binary files /dev/null and b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/clusterfuzz-testcase-minimized-5211130361282560 differ diff --git a/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/clusterfuzz-testcase-minimized-5839717883969536 b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/clusterfuzz-testcase-minimized-5839717883969536 new file mode 100644 index 0000000..7d0336a Binary files /dev/null and b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/clusterfuzz-testcase-minimized-5839717883969536 differ diff --git a/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/e5af0352010b1879ac1c63a69d3d9a02d577fa834165f855bd5ebee0f1105de1 b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/e5af0352010b1879ac1c63a69d3d9a02d577fa834165f855bd5ebee0f1105de1 new file mode 100644 index 0000000..99c5094 Binary files /dev/null and b/yara-master/tests/oss-fuzz/pe_fuzzer_corpus/e5af0352010b1879ac1c63a69d3d9a02d577fa834165f855bd5ebee0f1105de1 differ diff --git a/yara-master/tests/oss-fuzz/rules_fuzzer.cc b/yara-master/tests/oss-fuzz/rules_fuzzer.cc new file mode 100644 index 0000000..e5aca81 --- /dev/null +++ b/yara-master/tests/oss-fuzz/rules_fuzzer.cc @@ -0,0 +1,75 @@ +/* +Copyright (c) 2017. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include + +#include + + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + yr_initialize(); + return 0; +} + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + YR_RULES* rules; + YR_COMPILER* compiler; + + char* buffer = (char*) malloc(size + 1); + + if (!buffer) + return 1; + + strncpy(buffer, (const char *) data, size); + buffer[size] = 0; + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + { + free(buffer); + return 1; + } + + if (yr_compiler_add_string(compiler, (const char*) buffer, NULL) == 0) + { + if (yr_compiler_get_rules(compiler, &rules) == ERROR_SUCCESS) + yr_rules_destroy(rules); + else + return 1; + } + + yr_compiler_destroy(compiler); + free(buffer); + + return 0; +} diff --git a/yara-master/tests/oss-fuzz/rules_fuzzer.dict b/yara-master/tests/oss-fuzz/rules_fuzzer.dict new file mode 100644 index 0000000..6c8b83d --- /dev/null +++ b/yara-master/tests/oss-fuzz/rules_fuzzer.dict @@ -0,0 +1,42 @@ +# Lines starting with '#' and empty lines are ignored. + +"all" +"and" +"any" +"ascii" +"at" +"condition" +"contains" +"entrypoint" +"false" +"filesize" +"fullword" +"for" +"global" +"in" +"import" +"include" +"int8" +"int16" +"int32" +"int8be" +"int16be" +"int32be" +"matches" +"meta" +"nocase" +"not" +"or" +"of" +"private" +"rule" +"strings" +"them" +"true" +"uint8" +"uint16" +"uint32" +"uint8be" +"uint16be" +"uint32be" +"wide" \ No newline at end of file diff --git a/yara-master/tests/oss-fuzz/rules_fuzzer.options b/yara-master/tests/oss-fuzz/rules_fuzzer.options new file mode 100644 index 0000000..6659fa9 --- /dev/null +++ b/yara-master/tests/oss-fuzz/rules_fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 50000 diff --git a/yara-master/tests/oss-fuzz/rules_fuzzer_corpus/1 b/yara-master/tests/oss-fuzz/rules_fuzzer_corpus/1 new file mode 100644 index 0000000..4e240c7 --- /dev/null +++ b/yara-master/tests/oss-fuzz/rules_fuzzer_corpus/1 @@ -0,0 +1 @@ +rule test { condition: false } \ No newline at end of file diff --git a/yara-master/tests/oss-fuzz/rules_fuzzer_corpus/2 b/yara-master/tests/oss-fuzz/rules_fuzzer_corpus/2 new file mode 100644 index 0000000..cddd54f --- /dev/null +++ b/yara-master/tests/oss-fuzz/rules_fuzzer_corpus/2 @@ -0,0 +1,128 @@ +rule r1 { condition: true or false } + +rule r2 { condition: 0x1 and 0x2} + +rule r3 { condition: 2 > 1 } + +rule r4 { condition: 1.5 >= 1.0} + +rule r5 { condition: 0.5 <= 1} + +rule r6 { condition: "abc" == "abc"} + +rule r7 { condition: "ab" < "abc"} + +rule r8 { condition: (1 + 1) * 2 == (9 - 1) \ 2 } + +rule r9 { condition: 1.5 + 1.5 == 3} + +rule r10 { condition: -2.0-3.0 == -5} + +rule r11 { condition: ~0xAA ^ 0x5A & 0xFF == (~0xAA) ^ (0x5A & 0xFF) } + +rule r12 { strings: $a = "abc" wide nocase fullword condition: $a } + +rule r13 { + strings: + $a = "abcdef" + $b = "cdef" + $c = "ef" + condition: + all of them +} + +rule r14 { + strings: + $a = "abcdef" + $b = "cdef" + $c = "ef" + condition: + for all of ($*) : ($) +} + +rule r15 { + strings: + $a = { 64 01 00 00 60 01 } + condition: + $a +} + +rule r16 { + strings: + $a = { 64 01 [1-3] (60|61) 01 } + condition: + $a +} + +rule r17 { + strings: + $a = { 4D 5A [-] 6A 2A [-] 58 C3 } + condition: + $a +} + +rule r18 { + strings: + $a = { 4D 5A [300-] 6A 2A [-] 58 C3} + condition: + $a +} + +rule r19 { + strings: + $a = { 2e 7? (65 | ?? ) 78 } + condition: + $a +} + +rule r21 { + strings: + $a = /a.*efg/ + condition: + $a +} + +rule r22 { + strings: + $a = /abc[^D]/ nocase + condition: + $a +} + +rule r23 { + strings: + $a = /a[-]?c/ + condition: + $a +} + +rule r24 { + strings: + $a = /[0-9a-f]+/ + condition: + $a +} + +rule r25 { + strings: + $a = /[\\da-fA-F]+/ + condition: + $a +} + +rule r26 { + strings: + $a = /(bc+d$|ef*g.|h?i(j|k))/ + condition: + $a +} + +rule r27 { + condition: + "xxFoOxx" matches /fOo/i +} + +rule r28 { + condition: + uint32be(0) == 0xAABBCCDD +} diff --git a/yara-master/tests/test-alignment.c b/yara-master/tests/test-alignment.c new file mode 100644 index 0000000..1181f4f --- /dev/null +++ b/yara-master/tests/test-alignment.c @@ -0,0 +1,124 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#undef NDEBUG +#include + +int err = 0; + +#define CHECK_SIZE(expr,size) \ + do \ + { \ + printf("sizeof("#expr") = %zd ...", sizeof(expr)); \ + if (sizeof(expr) == size) \ + { \ + puts("ok"); \ + } \ + else \ + { \ + printf("expected %d\n", size); \ + err = 1; \ + } \ + } while (0); + +#define CHECK_OFFSET(expr,offset,subexpr) \ + do \ + { \ + printf("offsetof("#expr", "#subexpr") = %zd ...", \ + offsetof(expr, subexpr)); \ + if (offsetof(expr, subexpr) == offset) \ + { \ + puts("ok"); \ + } \ + else \ + { \ + printf("expected %d\n", offset); \ + } \ + } while (0) + + +int main (int argc, char **argv) +{ + CHECK_SIZE(YR_NAMESPACE, 4 * MAX_THREADS + 8); + CHECK_OFFSET(YR_NAMESPACE, 4 * MAX_THREADS, name); + + CHECK_SIZE(YR_META, 32); + CHECK_OFFSET(YR_META, 8, integer); + CHECK_OFFSET(YR_META, 16, identifier); + CHECK_OFFSET(YR_META, 24, string); + + CHECK_SIZE(YR_MATCHES, 24); + CHECK_OFFSET(YR_MATCHES, 8, head); + CHECK_OFFSET(YR_MATCHES, 16, tail); + + CHECK_SIZE(YR_STRING, 64 + 2 * 24 /* YR_MATCHES */ * MAX_THREADS); + CHECK_OFFSET(YR_STRING, 4, length); + CHECK_OFFSET(YR_STRING, 8, identifier); + CHECK_OFFSET(YR_STRING, 16, string); + CHECK_OFFSET(YR_STRING, 24, chained_to); + CHECK_OFFSET(YR_STRING, 32, rule); + CHECK_OFFSET(YR_STRING, 40, chain_gap_min); + CHECK_OFFSET(YR_STRING, 44, chain_gap_max); + CHECK_OFFSET(YR_STRING, 48, fixed_offset); + + CHECK_SIZE(YR_RULE, 16 + 4 * MAX_THREADS + 40); + CHECK_OFFSET(YR_RULE, 4, t_flags); + CHECK_OFFSET(YR_RULE, 8 + 4 * MAX_THREADS, identifier); + CHECK_OFFSET(YR_RULE, 8 + 4 * MAX_THREADS + 8, tags); + CHECK_OFFSET(YR_RULE, 8 + 4 * MAX_THREADS + 16, metas); + CHECK_OFFSET(YR_RULE, 8 + 4 * MAX_THREADS + 24, strings); + CHECK_OFFSET(YR_RULE, 8 + 4 * MAX_THREADS + 32, ns); + + CHECK_SIZE(YR_EXTERNAL_VARIABLE, 24); + CHECK_OFFSET(YR_EXTERNAL_VARIABLE, 8, value.i); + CHECK_OFFSET(YR_EXTERNAL_VARIABLE, 8, value.f); + CHECK_OFFSET(YR_EXTERNAL_VARIABLE, 8, value.s); + CHECK_OFFSET(YR_EXTERNAL_VARIABLE, 16, identifier); + + CHECK_SIZE(YR_AC_MATCH, 40); + CHECK_OFFSET(YR_AC_MATCH, 8, string); + CHECK_OFFSET(YR_AC_MATCH, 16, forward_code); + CHECK_OFFSET(YR_AC_MATCH, 24, backward_code); + CHECK_OFFSET(YR_AC_MATCH, 32, next); + + CHECK_SIZE(YARA_RULES_FILE_HEADER, 40); + CHECK_OFFSET(YARA_RULES_FILE_HEADER, 0, rules_list_head); + CHECK_OFFSET(YARA_RULES_FILE_HEADER, 8, externals_list_head); + CHECK_OFFSET(YARA_RULES_FILE_HEADER, 16, code_start); + CHECK_OFFSET(YARA_RULES_FILE_HEADER, 24, match_table); + CHECK_OFFSET(YARA_RULES_FILE_HEADER, 32, transition_table); + + CHECK_SIZE(SIZED_STRING, 12); + CHECK_OFFSET(SIZED_STRING, 4, flags); + CHECK_OFFSET(SIZED_STRING, 8, c_string); + + return err; +} diff --git a/yara-master/tests/test-api.c b/yara-master/tests/test-api.c new file mode 100644 index 0000000..487e927 --- /dev/null +++ b/yara-master/tests/test-api.c @@ -0,0 +1,560 @@ + +#include +#include "util.h" + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#else +#include +#endif +#include + +void test_disabled_rules() +{ + YR_RULES* rules; + YR_RULE* rule; + + int matches = 0; + char* buf = "foo bar"; + char* rules_str = " \ + rule disabled_rule {condition: true} \ + rule false_rule {condition: true and disabled_rule} \ + rule true_rule {condition: true or disabled_rule}"; + + + yr_initialize(); + + if (compile_rule(rules_str, &rules) != ERROR_SUCCESS) + { + perror("compile_rule"); + exit(EXIT_FAILURE); + } + + // diable any rule containing disable in its identifier + yr_rules_foreach(rules, rule) + { + if (strstr(rule->identifier, "disabled")) + yr_rule_disable(rule); + } + + yr_rules_scan_mem( + rules, (uint8_t *) buf, strlen(buf), 0, count_matches, &matches, 0); + + yr_rules_destroy(rules); + + // matches should be exactly one. + if (matches != 1) + { + fprintf(stderr, "test_disabled_rules failed\n"); + exit(EXIT_FAILURE); + } + + yr_finalize(); +} + + +const char* _include_callback( + const char* include_name, + const char* calling_rule_filename, + const char* calling_rule_namespace, + void* user_data) +{ +if (strcmp(include_name, "ok") == 0) + return "rule test {condition: true}"; +else + return NULL; +} + + +void test_include_callback() +{ + YR_COMPILER* compiler = NULL; + + yr_initialize(); + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + { + perror("yr_compiler_create"); + exit(EXIT_FAILURE); + } + + yr_compiler_set_include_callback(compiler, _include_callback, NULL, NULL); + + // This include produces no error. + if (yr_compiler_add_string(compiler, "include \"ok\"", NULL) != 0) + { + yr_compiler_destroy(compiler); + exit(EXIT_FAILURE); + } + + // This include one error. + if (yr_compiler_add_string(compiler, "include \"fail\"", NULL) != 1) + { + yr_compiler_destroy(compiler); + exit(EXIT_FAILURE); + } + + yr_compiler_destroy(compiler); + yr_finalize(); +} + + +void test_file_descriptor() +{ + YR_COMPILER* compiler = NULL; + YR_RULES* rules = NULL; + +#if defined(_WIN32) || defined(__CYGWIN__) + HANDLE fd = CreateFile("tests/data/baz.yar", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (fd == INVALID_HANDLE_VALUE) + { + fputs("CreateFile failed", stderr); + exit(1); + } +#else + int fd = open("tests/data/baz.yar", O_RDONLY); + if (fd < 0) + { + perror("open"); + exit(EXIT_FAILURE); + } +#endif + + yr_initialize(); + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + { + perror("yr_compiler_create"); + exit(EXIT_FAILURE); + } + + if (yr_compiler_add_fd(compiler, fd, NULL, NULL) != 0) { + perror("yr_compiler_add_fd"); + exit(EXIT_FAILURE); + } + +#if defined(_WIN32) || defined(__CYGWIN__) + CloseHandle(fd); +#else + close(fd); +#endif + + if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS) { + perror("yr_compiler_add_fd"); + exit(EXIT_FAILURE); + } + + if (compiler) + yr_compiler_destroy(compiler); + + if (rules) + yr_rules_destroy(rules); + + yr_finalize(); + + return; +} + +void test_max_string_per_rules() +{ + uint32_t new_max_strings_per_rule = 1; + uint32_t old_max_strings_per_rule; + + yr_initialize(); + + yr_get_configuration( + YR_CONFIG_MAX_STRINGS_PER_RULE, + (void*) &old_max_strings_per_rule); + + yr_set_configuration( + YR_CONFIG_MAX_STRINGS_PER_RULE, + (void*) &new_max_strings_per_rule); + + assert_error( + "rule test { \ + strings: \ + $ = \"uno\" \ + $ = \"dos\" \ + condition: \ + all of them }", + ERROR_TOO_MANY_STRINGS); + + new_max_strings_per_rule = 2; + + yr_set_configuration( + YR_CONFIG_MAX_STRINGS_PER_RULE, + (void*) &new_max_strings_per_rule); + + assert_error( + "rule test { \ + strings: \ + $ = \"uno\" \ + $ = \"dos\" \ + condition: \ + all of them }", + ERROR_SUCCESS); + + yr_set_configuration( + YR_CONFIG_MAX_STRINGS_PER_RULE, + (void*) &old_max_strings_per_rule); + + yr_finalize(); +} + + +int test_max_match_data_callback( + int message, + void* message_data, + void* user_data) +{ + if (message == CALLBACK_MSG_RULE_MATCHING) + { + YR_RULE* r = (YR_RULE*) message_data; + YR_STRING* s; + + yr_rule_strings_foreach(r, s) + { + YR_MATCH* m; + + yr_string_matches_foreach(s, m) + { + if (m->data_length > 0) + return CALLBACK_ERROR; + } + } + } + + return CALLBACK_CONTINUE; +} + +void test_max_match_data() +{ + YR_RULES* rules; + + uint32_t new_max_match_data = 0; + uint32_t old_max_match_data; + + char* rules_str = " \ + rule t { strings: $a = \"foobar\" condition: $a }"; + + yr_initialize(); + + yr_get_configuration( + YR_CONFIG_MAX_MATCH_DATA, + (void*) &old_max_match_data); + + yr_set_configuration( + YR_CONFIG_MAX_MATCH_DATA, + (void*) &new_max_match_data); + + if (compile_rule(rules_str, &rules) != ERROR_SUCCESS) + { + perror("compile_rule"); + exit(EXIT_FAILURE); + } + + int err = yr_rules_scan_mem( + rules, + (const uint8_t *) "foobar", + 6, + 0, + test_max_match_data_callback, + NULL, + 0); + + if (err != ERROR_SUCCESS) + { + fprintf(stderr, "test_max_match_data failed"); + exit(EXIT_FAILURE); + } + + yr_finalize(); +} + + +void test_save_load_rules() +{ + YR_COMPILER* compiler = NULL; + YR_RULES* rules = NULL; + + yr_initialize(); + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + { + perror("yr_compiler_create"); + exit(EXIT_FAILURE); + } + + if (yr_compiler_add_string(compiler, "rule test {condition: true}", NULL) != 0) + { + yr_compiler_destroy(compiler); + perror("yr_compiler_add_string"); + exit(EXIT_FAILURE); + } + + if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS) + { + yr_compiler_destroy(compiler); + perror("yr_compiler_add_fd"); + exit(EXIT_FAILURE); + } + + yr_compiler_destroy(compiler); + + if (yr_rules_save(rules, "test-rules.yarc") != ERROR_SUCCESS) + { + yr_rules_destroy(rules); + perror("yr_rules_save"); + exit(EXIT_FAILURE); + } + + yr_rules_destroy(rules); + + if (yr_rules_load("test-rules.yarc", &rules) != ERROR_SUCCESS) + { + perror("yr_rules_load"); + exit(EXIT_FAILURE); + } + + yr_rules_destroy(rules); + yr_finalize(); +} + + +void test_scanner() +{ + int matches = 0; + const char* buf = "dummy"; + const char* rules_str = "\ + rule test { \ + condition: bool_var and int_var == 1 and str_var == \"foo\" }"; + + YR_COMPILER* compiler = NULL; + YR_RULES* rules = NULL; + YR_SCANNER* scanner1 = NULL; + YR_SCANNER* scanner2 = NULL; + + int result; + + yr_initialize(); + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + { + perror("yr_compiler_create"); + exit(EXIT_FAILURE); + } + + // Define a few variables + yr_compiler_define_integer_variable(compiler, "int_var", 0); + yr_compiler_define_boolean_variable(compiler, "bool_var", 0); + yr_compiler_define_string_variable(compiler, "str_var", ""); + + // Compile a rule that use the variables in the condition. + if (yr_compiler_add_string(compiler, rules_str, NULL) != 0) + { + yr_compiler_destroy(compiler); + perror("yr_compiler_add_string"); + exit(EXIT_FAILURE); + } + + if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS) + { + yr_compiler_destroy(compiler); + perror("yr_compiler_get_rules"); + exit(EXIT_FAILURE); + } + + yr_compiler_destroy(compiler); + + // Create an scanner + if (yr_scanner_create(rules, &scanner1)!= ERROR_SUCCESS) + { + yr_rules_destroy(rules); + perror("yr_scanner_create"); + exit(EXIT_FAILURE); + } + + // Create another scanner + if (yr_scanner_create(rules, &scanner2)!= ERROR_SUCCESS) + { + yr_scanner_destroy(scanner1); + yr_rules_destroy(rules); + perror("yr_scanner_create"); + exit(EXIT_FAILURE); + } + + // Let's check the yr_scanner_scan_mem returns the appropriate error when + // called without specifying a callback. + result = yr_scanner_scan_mem(scanner1, (uint8_t *) buf, strlen(buf)); + + if (result != ERROR_CALLBACK_REQUIRED) + { + yr_scanner_destroy(scanner1); + yr_scanner_destroy(scanner2); + yr_rules_destroy(rules); + printf("expecting ERROR_CALLBACK_REQUIRED (%d), got: %d\n", + ERROR_CALLBACK_REQUIRED, result); + exit(EXIT_FAILURE); + } + + // Set the callback and a some the correct values for the rule to match. + yr_scanner_set_callback(scanner1, count_matches, &matches); + yr_scanner_define_integer_variable(scanner1, "int_var", 1); + yr_scanner_define_boolean_variable(scanner1, "bool_var", 1); + yr_scanner_define_string_variable(scanner1, "str_var", "foo"); + + // Set some other values for the second scanner to make sure it doesn't + // interfere with the first one. + yr_scanner_define_integer_variable(scanner2, "int_var", 2); + yr_scanner_define_boolean_variable(scanner2, "bool_var", 0); + yr_scanner_define_string_variable(scanner2, "str_var", "bar"); + + result = yr_scanner_scan_mem(scanner1, (uint8_t *) buf, strlen(buf)); + + if (result != ERROR_SUCCESS) + { + yr_scanner_destroy(scanner1); + yr_scanner_destroy(scanner2); + yr_rules_destroy(rules); + printf("expecting ERROR_SUCCESS (%d), got: %d\n", + ERROR_SUCCESS, result); + exit(EXIT_FAILURE); + } + + if (matches != 1) + { + yr_scanner_destroy(scanner1); + yr_scanner_destroy(scanner2); + yr_rules_destroy(rules); + exit(EXIT_FAILURE); + } + + yr_scanner_destroy(scanner1); + yr_scanner_destroy(scanner2); + yr_rules_destroy(rules); + yr_finalize(); +} + +// Test case for https://github.com/VirusTotal/yara/issues/834. Use the same +// scanner for scanning multiple files with a rule that imports the "tests" +// module. If the unload_module function is called twice an assertion is +// triggered by the module. +void test_issue_834() +{ + const char* buf = "dummy"; + const char* rules_str = "import \"tests\" rule test { condition: true }"; + + YR_COMPILER* compiler = NULL; + YR_RULES* rules = NULL; + YR_SCANNER* scanner = NULL; + + yr_initialize(); + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + { + perror("yr_compiler_create"); + exit(EXIT_FAILURE); + } + + if (yr_compiler_add_string(compiler, rules_str, NULL) != 0) + { + yr_compiler_destroy(compiler); + perror("yr_compiler_add_string"); + exit(EXIT_FAILURE); + } + + if (yr_compiler_get_rules(compiler, &rules) != ERROR_SUCCESS) + { + yr_compiler_destroy(compiler); + perror("yr_compiler_get_rules"); + exit(EXIT_FAILURE); + } + + yr_compiler_destroy(compiler); + + if (yr_scanner_create(rules, &scanner)!= ERROR_SUCCESS) + { + yr_rules_destroy(rules); + perror("yr_scanner_create"); + exit(EXIT_FAILURE); + } + + yr_scanner_set_callback(scanner, do_nothing, NULL); + + // Call yr_scanner_scan_mem twice. + yr_scanner_scan_mem(scanner, (uint8_t *) buf, strlen(buf)); + yr_scanner_scan_mem(scanner, (uint8_t *) buf, strlen(buf)); + + yr_scanner_destroy(scanner); + yr_rules_destroy(rules); + yr_finalize(); +} + + +void ast_callback( + const YR_RULE* rule, + const char* string_identifier, + const RE_AST* re_ast, + void* user_data) +{ + if (strcmp(rule->identifier, "test") == 0 && + strcmp(string_identifier, "$foo") == 0) + { + *((int*) user_data) = 1; + } +} + +void test_ast_callback() +{ + const char* rules_str = "\ + rule test { \ + strings: $foo = /a.*b/ \ + condition: $foo }"; + + YR_COMPILER* compiler = NULL; + + yr_initialize(); + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + { + perror("yr_compiler_create"); + exit(EXIT_FAILURE); + } + + int ok = 0; + + yr_compiler_set_re_ast_callback( + compiler, + ast_callback, + &ok); + + // Compile a rule that use the variables in the condition. + if (yr_compiler_add_string(compiler, rules_str, NULL) != 0) + { + yr_compiler_destroy(compiler); + perror("yr_compiler_add_string"); + exit(EXIT_FAILURE); + } + + if (!ok) + { + printf("ast callback failed\n"); + exit(EXIT_FAILURE); + } + + yr_compiler_destroy(compiler); + yr_finalize(); +} + +int main(int argc, char** argv) +{ + test_disabled_rules(); + test_file_descriptor(); + test_max_string_per_rules(); + test_max_match_data(); + test_include_callback(); + test_save_load_rules(); + test_scanner(); + test_ast_callback(); + test_issue_834(); +} diff --git a/yara-master/tests/test-dex.c b/yara-master/tests/test-dex.c new file mode 100644 index 0000000..012375a --- /dev/null +++ b/yara-master/tests/test-dex.c @@ -0,0 +1,107 @@ +#include +#include "util.h" +#include "blob.h" + +int main(int argc, char** argv) +{ + yr_initialize(); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.header.magic == \ + dex.DEX_FILE_MAGIC_035 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.header.checksum == \ + 0x3F9C602F }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.header.data_size == \ + 0x18C }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.string_ids[0].value ==\ + \"\" }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.string_ids[8].value == \ + \"com.google.helloyara\" }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.type_ids[0].descriptor_idx == \ + 0x2 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.proto_ids[0].shorty_idx == \ + 0x6 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.field_ids[0].class_idx == \ + 0x1 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.method_ids[0].class_idx == \ + 0x1 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.class_defs[0].class_idx == \ + 0x1 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.number_of_fields == 2 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.field[0].class_name == \ + \"Lcom/android/tools/ir/server/AppInfo;\" }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.field[0].name == \ + \"applicationId\" }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.number_of_methods == 2 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.method[0].class_name == \ + \"Lcom/android/tools/ir/server/AppInfo;\" }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.method[0].proto == \"V\" }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.method[0].name == \ + \"\" }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.method[1].name == \ + \"\" }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: dex.map_list.size == 12 }", + DEX_FILE); + + assert_true_rule_blob( + "import \"dex\" rule test { condition: \ + dex.map_list.map_item[0].type == dex.TYPE_HEADER_ITEM \ + }", + DEX_FILE); + + yr_finalize(); +} diff --git a/yara-master/tests/test-elf.c b/yara-master/tests/test-elf.c new file mode 100644 index 0000000..b8a18ae --- /dev/null +++ b/yara-master/tests/test-elf.c @@ -0,0 +1,234 @@ +#include +#include "util.h" +#include "blob.h" + +int main(int argc, char** argv) +{ + yr_initialize(); + + assert_true_rule_blob( + "import \"elf\" rule test { condition: elf.type }", + ELF32_FILE); + + assert_true_rule_blob( + "import \"elf\" rule test { condition: elf.type }", + ELF64_FILE); + + assert_true_rule_blob( + "import \"elf\" rule test { condition: elf.machine == elf.EM_386 }", + ELF32_FILE) + + assert_true_rule_blob( + "import \"elf\" rule test { condition: elf.machine == elf.EM_X86_64 }", + ELF64_FILE) + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + strings: $a = { b8 01 00 00 00 bb 2a } \ + condition: $a at elf.entry_point \ + }", + ELF32_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + strings: $a = { b8 01 00 00 00 bb 2a } \ + condition: $a at elf.entry_point \ + }", + ELF64_FILE); + + assert_true_rule_blob( + "import \"elf\" rule test { condition: elf.entry_point == 0xa0 }", + ELF32_NOSECTIONS); + + assert_true_rule_blob( + "import \"elf\" rule test { condition: elf.entry_point == 0x1a0 }", + ELF32_SHAREDOBJ); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: elf.sections[2].name == \".comment\" \ + }", + ELF64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: elf.machine == elf.EM_MIPS \ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + elf.number_of_sections == 35 and elf.number_of_segments == 10 \ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + for any i in (0..elf.number_of_sections): ( \ + elf.sections[i].type == elf.SHT_PROGBITS and \ + elf.sections[i].address == 0x400600 and \ + elf.sections[i].name == \".text\") \ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + for any i in (0..elf.number_of_segments): ( \ + elf.segments[i].type == elf.PT_LOAD and \ + elf.segments[i].virtual_address == 0x00400000 and \ + elf.segments[i].file_size == 0x95c)\ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + elf.dynamic_section_entries == 19 and \ + elf.symtab_entries == 80 \ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + for any i in (0..elf.symtab_entries): ( \ + elf.symtab[i].shndx == 9 and \ + elf.symtab[i].value == 0x400650 and \ + elf.symtab[i].name == \"_start_c\") \ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + elf.symtab[68].name == \"_start_c\" and \ + elf.symtab[68].type == elf.STT_FUNC and \ + elf.symtab[68].bind == elf.STB_GLOBAL and \ + elf.symtab[68].value == 0x400650 and \ + elf.symtab[68].size == 56 \ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + elf.dynamic[4].type == elf.DT_STRTAB and \ + elf.dynamic[4].val == 0x400484\ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + for any i in (0..elf.dynamic_section_entries): ( \ + elf.dynamic[i].type == 0x70000006 and \ + elf.dynamic[i].val == 0x400000)\ + }", + ELF32_MIPS_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: elf.machine == elf.EM_X86_64 \ + }", + ELF_x64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + elf.number_of_sections == 22 and \ + elf.number_of_segments == 7 \ + }", + ELF_x64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + for any i in (0..elf.number_of_sections): ( \ + elf.sections[i].type == elf.SHT_PROGBITS and \ + elf.sections[i].address == 0x601000 and \ + elf.sections[i].name == \".got.plt\") \ + }", + ELF_x64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + for any i in (0..elf.number_of_segments): ( \ + elf.segments[i].type == elf.PT_LOAD and \ + elf.segments[i].virtual_address == 0x600e78 and \ + elf.segments[i].file_size == 0x1b0) \ + }", + ELF_x64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + elf.dynamic_section_entries == 18 and \ + elf.symtab_entries == 48 \ + }", + ELF_x64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + for any i in (0..elf.symtab_entries): ( \ + elf.symtab[i].shndx == 8 and \ + elf.symtab[i].value == 0x400400 and \ + elf.symtab[i].name == \"main\") \ + }", + ELF_x64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + elf.symtab[20].name == \"__JCR_LIST__\" and \ + elf.symtab[20].type == elf.STT_OBJECT and \ + elf.symtab[20].bind == elf.STB_LOCAL and \ + elf.symtab[20].value == 0x600e88 and \ + elf.symtab[20].size == 0 \ + }", + ELF_x64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + elf.dynamic[13].type == elf.DT_PLTGOT and \ + elf.dynamic[13].val == 0x601000 \ + }", + ELF_x64_FILE); + + assert_true_rule_blob( + "import \"elf\" \ + rule test { \ + condition: \ + for any i in (0..elf.dynamic_section_entries): ( \ + elf.dynamic[i].type == elf.DT_JMPREL and \ + elf.dynamic[i].val == 0x4003c0) \ + }", + ELF_x64_FILE); + + yr_finalize(); +} diff --git a/yara-master/tests/test-exception.c b/yara-master/tests/test-exception.c new file mode 100644 index 0000000..be0e40d --- /dev/null +++ b/yara-master/tests/test-exception.c @@ -0,0 +1,279 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include "util.h" + +#define COUNT 128 +char wbuf[1024]; + +extern char **environ; + +int fd; +uint8_t* mapped_region; +YR_RULES *rules_a, *rules_0; + +/* +Set up mapped_region so that it is only partially backed by the open +file referred to by fd. Accessing the memory beyond + + mapped_region + COUNT * sizeof(wbuf) / 2 + +should cause a signal (usually SIGBUS) to be raised. +*/ +void setup_mmap() +{ + char* filename = strdup("yara-testblob.XXXXXX"); + fd = mkstemp(filename); + int i; + + if (fd <= 0) + { + perror("Create temp file"); + exit(77); + } + + unlink(filename); + + memset(wbuf, 'a', sizeof(wbuf)); + + for (i = 0; i < COUNT; i++) + { + if (write(fd, wbuf, sizeof(wbuf)) != sizeof(wbuf)) + exit(EXIT_FAILURE); + } + + mapped_region = mmap( + NULL, COUNT * sizeof(wbuf), PROT_READ, MAP_SHARED, fd, 0); + + if (ftruncate(fd, COUNT * sizeof(wbuf) / 2) != 0) + exit(EXIT_FAILURE); +} + +void setup_rules() +{ + yr_initialize(); + + compile_rule( + "rule test { strings: $a = \"aaaa\" condition: all of them }", + &rules_a); + + compile_rule( + "rule test { strings: $a = { 00 00 00 00 } condition: all of them }", + &rules_0); +} + +void* crasher_func (void* x) +{ + sleep(1); + int *i = 0; + puts("crashing process..."); + *i = 0; + return NULL; +} + +/* Set up a thread that will cause a null pointer dereference after one second */ +void setup_crasher() +{ + pthread_t t; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_create(&t, &attr, &crasher_func, NULL); +} + +/* Simple yr_scan_* callback function that delays execution by 2 seconds */ +int delay_callback(int message, + void* message_data, + void* user_data) +{ + if (message == CALLBACK_MSG_RULE_MATCHING) + { + (*(int*) user_data)++; + } + puts("callback: delaying execution..."); + sleep(2); + return CALLBACK_CONTINUE; +} + +/* Scan a partially backed memory map, raising an exceptions, usually SIGBUS or SIGSEGV. */ +int test_crash(int handle_exceptions) +{ + setup_mmap(); + setup_rules(); + + puts("Scanning for \"aaaa\"..."); + int matches = 0; + + int flags = (handle_exceptions ? 0 : SCAN_FLAGS_NO_TRYCATCH); + + int rc = yr_rules_scan_mem( + rules_a, mapped_region, COUNT * sizeof(wbuf), flags, count_matches, &matches, 0); + + printf("err = %d, matches = %d\n", rc, matches); + + if (rc == ERROR_SUCCESS || matches != 0) + return 1; + + return 0; +} + +/* +Scan memory while another thread accesses invalid memory. The signal +for that invalid memory access should not be caught by the handler set +up using YR_TRYCATCH. +*/ +int test_crash_other_thread() +{ + setup_mmap(); + setup_rules(); + setup_crasher(); + + uint8_t mem[4096]; + memset(mem, 'a', sizeof(mem)); + + puts("Scanning for \"aaaa\"..."); + int matches = 0; + + int rc = yr_rules_scan_mem( + rules_a, mem, sizeof(mem), 0, delay_callback, &matches, 0); + + printf("err = %d, matches = %d\n", rc, matches); + + if (rc == ERROR_SUCCESS || matches != 0) + return 1; + + return 0; +} + +/* + This tests that SIGUSR1 is not delivered when setting up SIGBUS + signal handling -- or during SIGBUS signal handling +*/ +int test_blocked_signal() { + setup_mmap(); + setup_rules(); + + puts("Sending blocked SIGUSR1 to ourselves..."); + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + sigprocmask(SIG_BLOCK, &set, NULL); + kill(getpid(), SIGUSR1); + + puts("Scanning for {00 00 00 00}..."); + int matches = 0; + + int rc = yr_rules_scan_mem( + rules_0, mapped_region, COUNT * sizeof(wbuf), 0, count_matches, &matches, 0); + + printf("err = %d, matches = %d\n", rc, matches); + + if (rc == ERROR_SUCCESS || matches != 0) + return 1; + + return 0; +} + +int reexec(char *program) +{ + char *argv[] = { program, NULL }; + int status; + int pid = fork(); + switch(pid) + { + case 0: + return execve(program, argv, environ); + case -1: + return -1; + } + waitpid(pid, &status, 0); + return status; +} + +int main(int argc, char **argv) +{ + char *op = getenv("TEST_OP"); + if (op == NULL) + { + int status; + puts("Test: crash"); + setenv("TEST_OP", "CRASH", 1); + status = reexec(argv[0]); + if (status != 0) + return 1; + + puts("Test: crash-no-handle"); + setenv("TEST_OP", "CRASH-NO-HANDLE", 1); + status = reexec(argv[0]); + if (!WIFSIGNALED(status)) + { + fputs("Expected subprocess to be terminated by signal\n", stderr); + return 1; + } + + puts("Test: blocked-signal"); + setenv("TEST_OP", "BLOCKED-SIGNAL", 1); + status = reexec(argv[0]); + if (status != 0) + return 1; + + puts("Test: crash-other-thread"); + setenv("TEST_OP", "CRASH-OTHER-THREAD", 1); + status = reexec(argv[0]); + if (!WIFSIGNALED(status)) + { + fputs("Expected subprocess to be terminated by signal\n", stderr); + return 1; + } + + puts("Done."); + } + else if (!strcmp(op, "CRASH")) + return test_crash(1); + else if (!strcmp(op, "CRASH-NO-HANDLE")) + return test_crash(0); + else if (!strcmp(op, "BLOCKED-SIGNAL")) + return test_blocked_signal(); + else if (!strcmp(op, "CRASH-OTHER-THREAD")) + return test_crash_other_thread(); + else + { + fprintf(stderr, "wrong op '%s'\n", op); + return 77; + } + return 0; +} diff --git a/yara-master/tests/test-macho.c b/yara-master/tests/test-macho.c new file mode 100644 index 0000000..796641b --- /dev/null +++ b/yara-master/tests/test-macho.c @@ -0,0 +1,191 @@ +#include +#include "util.h" +#include "blob.h" + +int main(int argc, char** argv) +{ + yr_initialize(); + + // Tests for executable files + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.cputype == macho.CPU_TYPE_X86 }", MACHO_X86_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.filetype == macho.MH_EXECUTE }", MACHO_X86_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.flags & macho.MH_PIE }", MACHO_X86_FILE); + + // Segments + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.number_of_segments == 4 }", MACHO_X86_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[0].segname == \"__PAGEZERO\" and \ + macho.segments[1].segname == \"__TEXT\" and \ + macho.segments[2].segname == \"__DATA\" and \ + macho.segments[3].segname == \"__LINKEDIT\" }", MACHO_X86_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[0].vmaddr == 0 and \ + macho.segments[0].vmsize == 0x1000 and \ + macho.segments[2].nsects == 2 and \ + macho.segments[3].fsize == 0x118 }", MACHO_X86_FILE); + + // Sections + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[1].sections[0].addr == 0x1e90 and \ + macho.segments[1].sections[0].size == 0xa6 and \ + macho.segments[1].sections[0].offset == 0x0e90 }", MACHO_X86_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[1].sections[0].sectname == \"__text\" and \ + macho.segments[1].sections[0].segname == \"__TEXT\" }", MACHO_X86_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[1].sections[1].sectname == \"__symbol_stub\" and \ + macho.segments[1].sections[2].sectname == \"__stub_helper\" and \ + macho.segments[1].sections[3].sectname == \"__cstring\" and \ + macho.segments[1].sections[4].sectname == \"__unwind_info\" and \ + macho.segments[2].sections[0].sectname == \"__nl_symbol_ptr\" and \ + macho.segments[2].sections[1].sectname == \"__la_symbol_ptr\" }", + MACHO_X86_FILE); + + // Entry point (LC_MAIN) + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.entry_point == 0xe90 }", MACHO_X86_FILE); + + // Tests for object files + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.cputype == macho.CPU_TYPE_X86 }", MACHO_X86_OBJECT_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.filetype == macho.MH_OBJECT }", MACHO_X86_OBJECT_FILE); + + // Segments and sections + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.number_of_segments == 1 and macho.segments[0].segname == \"\" and \ + macho.segments[0].sections[0].sectname == \"__text\" and \ + macho.segments[0].sections[0].segname == \"__TEXT\" }", + MACHO_X86_OBJECT_FILE); + + // Tests for big-endian byte order + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.cputype == macho.CPU_TYPE_POWERPC }", MACHO_PPC_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.filetype == macho.MH_EXECUTE }", MACHO_PPC_FILE); + + // Segments + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.number_of_segments == 4 and \ + macho.segments[0].segname == \"__PAGEZERO\" and \ + macho.segments[2].segname == \"__DATA\" and \ + macho.segments[2].nsects == 6 and \ + macho.segments[0].vmaddr == 0 and \ + macho.segments[0].vmsize == 0x1000 and \ + macho.segments[3].fileoff == 65536 and \ + macho.segments[3].fsize == 46032 }", MACHO_PPC_FILE); + + // Entry point (LC_UNIXTHREAD) + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.entry_point == 0xeb8 }", MACHO_PPC_FILE); + + // Tests for 64-bit and shared library files + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.cputype == macho.CPU_TYPE_X86_64 }", MACHO_X86_64_DYLIB_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.filetype == macho.MH_DYLIB }", MACHO_X86_64_DYLIB_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.flags & macho.MH_DYLDLINK and \ + macho.flags & macho.MH_NOUNDEFS and \ + macho.flags & macho.MH_NO_REEXPORTED_DYLIBS and \ + macho.flags & macho.MH_TWOLEVEL }", MACHO_X86_64_DYLIB_FILE); + + // Segments and sections + + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.number_of_segments == 2 }", MACHO_X86_64_DYLIB_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[0].segname == \"__TEXT\" and \ + macho.segments[1].segname == \"__LINKEDIT\" }", MACHO_X86_64_DYLIB_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[1].vmaddr == 0x0000000000001000 and \ + macho.segments[1].vmsize == 0x0000000000001000 and \ + macho.segments[1].nsects == 0 and \ + macho.segments[1].fsize == 128 }", MACHO_X86_64_DYLIB_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[0].sections[0].sectname == \"__text\" and \ + macho.segments[0].sections[0].segname == \"__TEXT\" }", + MACHO_X86_64_DYLIB_FILE); + assert_true_rule_blob("import \"macho\" rule test { condition: \ + macho.segments[0].sections[1].addr == 0x0000000000000f98 and \ + macho.segments[0].sections[1].size == 0x0000000000000048 and \ + macho.segments[0].sections[1].offset == 3992 }", MACHO_X86_64_DYLIB_FILE); + + // Mach-O Universal Binaries tests + + assert_true_rule_file("import \"macho\" rule test { condition: \ + macho.fat_magic == macho.FAT_MAGIC and macho.nfat_arch == 2 }", + "tests/data/tiny-universal"); + assert_true_rule_file("import \"macho\" rule test { condition: \ + macho.fat_arch[0].cputype == macho.CPU_TYPE_I386 and \ + macho.fat_arch[0].cpusubtype == macho.CPU_SUBTYPE_I386_ALL and \ + macho.fat_arch[0].offset == 4096 and \ + macho.fat_arch[1].cputype == macho.CPU_TYPE_X86_64 and \ + macho.fat_arch[1].cpusubtype == macho.CPU_SUBTYPE_X86_64_ALL | \ + macho.CPU_SUBTYPE_LIB64 and macho.fat_arch[1].align == 12 }", + "tests/data/tiny-universal"); + assert_true_rule_file("import \"macho\" rule test { condition: \ + macho.file[0].cputype == macho.fat_arch[0].cputype and \ + macho.file[1].cputype == macho.fat_arch[1].cputype }", + "tests/data/tiny-universal"); + + // Entry points for files (LC_MAIN) + + assert_true_rule_file("import \"macho\" rule test { \ + strings: $1 = { 55 89 e5 56 83 ec 34 } \ + condition: $1 at macho.file[0].entry_point + macho.fat_arch[0].offset }", + "tests/data/tiny-universal"); + + assert_true_rule_file("import \"macho\" rule test { \ + strings: $1 = { 55 48 89 e5 48 83 ec 20 } \ + condition: $1 at macho.file[1].entry_point + macho.fat_arch[1].offset }", + "tests/data/tiny-universal"); + + // Helper functions + + assert_true_rule_file("import \"macho\" rule test { condition: \ + macho.file[macho.file_index_for_arch(macho.CPU_TYPE_I386)].entry_point == \ + macho.file[0].entry_point }", "tests/data/tiny-universal"); + assert_true_rule_file("import \"macho\" rule test { condition: \ + macho.file[macho.file_index_for_arch(macho.CPU_TYPE_X86_64)].entry_point == \ + macho.file[1].entry_point }", "tests/data/tiny-universal"); + + assert_true_rule_file("import \"macho\" rule test { condition: \ + macho.file[macho.file_index_for_arch(macho.CPU_TYPE_I386, \ + macho.CPU_SUBTYPE_I386_ALL)].entry_point == \ + macho.file[0].entry_point }", "tests/data/tiny-universal"); + assert_true_rule_file("import \"macho\" rule test { condition: \ + macho.file[macho.file_index_for_arch(macho.CPU_TYPE_X86_64, \ + macho.CPU_SUBTYPE_X86_64_ALL | \ + macho.CPU_SUBTYPE_LIB64)].entry_point == \ + macho.file[1].entry_point }", "tests/data/tiny-universal"); + + // Entry point for specific architecture + + assert_true_rule_file("import \"macho\" rule test { \ + strings: $1 = { 55 89 e5 56 83 ec 34 } \ + condition: $1 at macho.entry_point_for_arch(macho.CPU_TYPE_I386, \ + macho.CPU_SUBTYPE_I386_ALL) }", + "tests/data/tiny-universal"); + + assert_true_rule_file("import \"macho\" rule test { \ + strings: $1 = { 55 48 89 e5 48 83 ec 20 } \ + condition: $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) }", + "tests/data/tiny-universal"); + + yr_finalize(); +} diff --git a/yara-master/tests/test-pe.c b/yara-master/tests/test-pe.c new file mode 100644 index 0000000..29596d9 --- /dev/null +++ b/yara-master/tests/test-pe.c @@ -0,0 +1,160 @@ +#include +#include +#include "util.h" + +int main(int argc, char** argv) +{ + yr_initialize(); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.imports(\"KERNEL32.dll\", \"DeleteCriticalSection\") \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.imports(\"KERNEL32.dll\", \"DeleteCriticalSection\") \ + }", + "tests/data/tiny-idata-51ff"); + + assert_false_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.imports(\"KERNEL32.dll\", \"DeleteCriticalSection\") \ + }", + "tests/data/tiny-idata-5200"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.number_of_imports == 2 \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.number_of_sections == 7 \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.entry_point == 0x14E0 \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.linker_version.major == 2 and \ + pe.linker_version.minor == 26 \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.sections[0].name == \".text\" and \ + pe.sections[1].name == \".data\" and \ + pe.sections[2].name == \".rdata\" and \ + pe.sections[3].name == \".bss\" and \ + pe.sections[4].name == \".idata\" and \ + pe.sections[5].name == \".CRT\" and \ + pe.sections[6].name == \".tls\" \ + }", + "tests/data/tiny"); + + #if defined(HAVE_LIBCRYPTO) || \ + defined(HAVE_WINCRYPT_H) || \ + defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.imphash() == \"1720bf764274b7a4052bbef0a71adc0d\" \ + }", + "tests/data/tiny"); + + #endif + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.section_index(\".text\") == 0 \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.section_index(pe.entry_point) == 0 \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.is_32bit() and not pe.is_64bit() \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.checksum == 0xA8DC \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.checksum == pe.calculate_checksum() \ + }", + "tests/data/tiny"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.overlay.offset == 0x8000 and pe.overlay.size == 7 \ + }", + "tests/data/tiny-overlay"); + + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.overlay.size == 0 \ + }", + "tests/data/tiny"); + + assert_false_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.checksum == pe.calculate_checksum() \ + }", + "tests/data/tiny-idata-51ff"); + + yr_finalize(); + return 0; +} diff --git a/yara-master/tests/test-rules.c b/yara-master/tests/test-rules.c new file mode 100644 index 0000000..7ce61e3 --- /dev/null +++ b/yara-master/tests/test-rules.c @@ -0,0 +1,1918 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include +#include +#include + +#include +#include "blob.h" +#include "util.h" + + +static void test_boolean_operators() +{ + assert_true_rule( + "rule test { condition: true }", NULL); + + assert_true_rule( + "rule test { condition: true or false }", NULL); + + assert_true_rule( + "rule test { condition: true and true }", NULL); + + assert_true_rule( + "rule test { condition: 0x1 and 0x2}", NULL); + + assert_false_rule( + "rule test { condition: false }", NULL); + + assert_false_rule( + "rule test { condition: true and false }", NULL); + + assert_false_rule( + "rule test { condition: false or false }", NULL); +} + + +static void test_comparison_operators() +{ + assert_true_rule( + "rule test { condition: 2 > 1 }", NULL); + + assert_true_rule( + "rule test { condition: 1 < 2 }", NULL); + + assert_true_rule( + "rule test { condition: 2 >= 1 }", NULL); + + assert_true_rule( + "rule test { condition: 1 <= 1 }", NULL); + + assert_true_rule( + "rule test { condition: 1 == 1 }", NULL); + + assert_true_rule( + "rule test { condition: 1.5 == 1.5}", NULL); + + assert_true_rule( + "rule test { condition: 1.0 == 1}", NULL); + + assert_true_rule( + "rule test { condition: 1.5 >= 1.0}", NULL); + + assert_true_rule( + "rule test { condition: 1.5 >= 1}", NULL); + + assert_true_rule( + "rule test { condition: 1.0 >= 1}", NULL); + + assert_true_rule( + "rule test { condition: 0.5 < 1}", NULL); + + assert_true_rule( + "rule test { condition: 0.5 <= 1}", NULL); + + assert_true_rule( + "rule rest { condition: 1.0 <= 1}", NULL); + + assert_true_rule( + "rule rest { condition: \"abc\" == \"abc\"}", NULL); + + assert_true_rule( + "rule rest { condition: \"abc\" <= \"abc\"}", NULL); + + assert_true_rule( + "rule rest { condition: \"abc\" >= \"abc\"}", NULL); + + assert_true_rule( + "rule rest { condition: \"ab\" < \"abc\"}", NULL); + + assert_true_rule( + "rule rest { condition: \"abc\" > \"ab\"}", NULL); + + assert_true_rule( + "rule rest { condition: \"abc\" < \"abd\"}", NULL); + + assert_true_rule( + "rule rest { condition: \"abd\" > \"abc\"}", NULL); + + assert_false_rule( + "rule test { condition: 1 != 1}", NULL); + + assert_false_rule( + "rule test { condition: 1 != 1.0}", NULL); + + assert_false_rule( + "rule test { condition: 2 > 3}", NULL); + + assert_false_rule( + "rule test { condition: 2.1 < 2}", NULL); + + assert_false_rule( + "rule test { condition: \"abc\" != \"abc\"}", NULL); + + assert_false_rule( + "rule test { condition: \"abc\" > \"abc\"}", NULL); + + assert_false_rule( + "rule test { condition: \"abc\" < \"abc\"}", NULL); + +} + +static void test_arithmetic_operators() +{ + assert_true_rule( + "rule test { condition: (1 + 1) * 2 == (9 - 1) \\ 2 }", NULL); + + assert_true_rule( + "rule test { condition: 5 % 2 == 1 }", NULL); + + assert_true_rule( + "rule test { condition: 1.5 + 1.5 == 3}", NULL); + + assert_true_rule( + "rule test { condition: 3 \\ 2 == 1}", NULL); + + assert_true_rule( + "rule test { condition: 3.0 \\ 2 == 1.5}", NULL); + + assert_true_rule( + "rule test { condition: 1 + -1 == 0}", NULL); + + assert_true_rule( + "rule test { condition: -1 + -1 == -2}", NULL); + + assert_true_rule( + "rule test { condition: 4 --2 * 2 == 8}", NULL); + + assert_true_rule( + "rule test { condition: -1.0 * 1 == -1.0}", NULL); + + assert_true_rule( + "rule test { condition: 1-1 == 0}", NULL); + + assert_true_rule( + "rule test { condition: -2.0-3.0 == -5}", NULL); + + assert_true_rule( + "rule test { condition: --1 == 1}", NULL); + + assert_true_rule( + "rule test { condition: 1--1 == 2}", NULL); + + assert_true_rule( + "rule test { condition: 2 * -2 == -4}", NULL); + + assert_true_rule( + "rule test { condition: -4 * 2 == -8}", NULL); + + assert_true_rule( + "rule test { condition: -4 * -4 == 16}", NULL); + + assert_true_rule( + "rule test { condition: -0x01 == -1}", NULL); + + assert_true_rule( + "rule test { condition: 0o10 == 8 }", NULL); + + assert_true_rule( + "rule test { condition: 0o100 == 64 }", NULL); + + assert_true_rule( + "rule test { condition: 0o755 == 493 }", NULL); + + // TODO: This should return ERROR_INTEGER_OVERFLOW, but right now it returns + // ERROR_SYNTAX_ERROR because after the lexer aborts with ERROR_INTEGER_OVERFLOW + // the parser finds an unexpected end fails with error: unexpected $end. + assert_error( + "rule test { condition: 9223372036854775808 > 0 }", + ERROR_SYNTAX_ERROR); + + assert_error( + "rule test { condition: 9007199254740992KB > 0 }", + ERROR_SYNTAX_ERROR); + + assert_error( // integer too long + "rule test { condition: 8796093022208MB > 0 }", + ERROR_SYNTAX_ERROR); + + assert_error( // integer too long + "rule test { condition: 0x8000000000000000 > 0 }", + ERROR_SYNTAX_ERROR); + + assert_error( // integer too long + "rule test { condition: 0o1000000000000000000000 > 0 }", + ERROR_SYNTAX_ERROR); + + assert_error( + "rule test { condition: 0x7FFFFFFFFFFFFFFF + 1 > 0 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: 9223372036854775807 + 1 > 0 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: -9223372036854775807 - 2 > 0 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: -2 + -9223372036854775807 > 0 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: 1 - -9223372036854775807 > 0 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: 0x4000000000000000 * 2 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: 4611686018427387904 * 2 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: 4611686018427387904 * -2 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: -4611686018427387904 * 2 }", + ERROR_INTEGER_OVERFLOW); + + assert_error( + "rule test { condition: -4611686018427387904 * -2 }", + ERROR_INTEGER_OVERFLOW); +} + + +static void test_bitwise_operators() +{ + assert_true_rule( + "rule test { condition: 0x55 | 0xAA == 0xFF }", + NULL); + + assert_true_rule( + "rule test { condition: ~0xAA ^ 0x5A & 0xFF == (~0xAA) ^ (0x5A & 0xFF) }", + NULL); + + assert_true_rule( + "rule test { condition: ~0x55 & 0xFF == 0xAA }", + NULL); + + assert_true_rule( + "rule test { condition: 8 >> 2 == 2 }", + NULL); + + assert_true_rule( + "rule test { condition: 1 << 3 == 8 }", + NULL); + + assert_true_rule( + "rule test { condition: 1 << 64 == 0 }", + NULL); + + assert_true_rule( + "rule test { condition: 1 >> 64 == 0 }", + NULL); + + assert_error( + "rule test { condition: 1 << -1 == 0 }", + ERROR_INVALID_OPERAND); + + assert_error( + "rule test { condition: 1 >> -1 == 0 }", + ERROR_INVALID_OPERAND); + + assert_true_rule( + "rule test { condition: 1 | 3 ^ 3 == 1 | (3 ^ 3) }", + NULL); + + assert_false_rule( + "rule test { condition: ~0xAA ^ 0x5A & 0xFF == 0x0F }", + NULL); + + assert_false_rule( + "rule test { condition: 1 | 3 ^ 3 == (1 | 3) ^ 3}", + NULL); + +} + + +static void test_syntax() +{ + assert_error( + "rule test { strings: $a = \"a\" $a = \"a\" condition: all of them }", + ERROR_DUPLICATED_STRING_IDENTIFIER); +} + + +static void test_anonymous_strings() +{ + assert_true_rule( + "rule test { strings: $ = \"a\" $ = \"b\" condition: all of them }", + "ab"); +} + + +static void test_strings() +{ + char* str = "---- abc ---- xyz"; + uint8_t blob[] = "---- a\0b\0c\0 -\0-\0-\0-\0x\0y\0z\0"; + + assert_true_rule( + "rule test { strings: $a = \"a\" condition: $a }", + str); + + assert_true_rule( + "rule test { strings: $a = \"ab\" condition: $a }", + str); + + assert_true_rule( + "rule test { strings: $a = \"abc\" condition: $a }", + str); + + assert_true_rule( + "rule test { strings: $a = \"xyz\" condition: $a }", + str); + + assert_true_rule( + "rule test { strings: $a = \"abc\" nocase fullword condition: $a }", + str); + + assert_true_rule( + "rule test { strings: $a = \"aBc\" nocase condition: $a }", + str); + + assert_true_rule( + "rule test { strings: $a = \"abc\" fullword condition: $a }", + str); + + assert_false_rule( + "rule test { strings: $a = \"a\" fullword condition: $a }", + str); + + assert_false_rule( + "rule test { strings: $a = \"ab\" fullword condition: $a }", + str); + + assert_false_rule( + "rule test { strings: $a = \"abc\" wide fullword condition: $a }", + str); + + assert_true_rule_blob( + "rule test { strings: $a = \"a\" wide condition: $a }", + blob); + + assert_true_rule_blob( + "rule test { strings: $a = \"a\" wide ascii condition: $a }", + blob); + + assert_true_rule_blob( + "rule test { strings: $a = \"ab\" wide condition: $a }", + blob); + + assert_true_rule_blob( + "rule test { strings: $a = \"ab\" wide ascii condition: $a }", + blob); + + assert_true_rule_blob( + "rule test { strings: $a = \"abc\" wide condition: $a }", + blob); + + assert_true_rule_blob( + "rule test { strings: $a = \"abc\" wide nocase fullword condition: $a }", + blob); + + assert_true_rule_blob( + "rule test { strings: $a = \"aBc\" wide nocase condition: $a }", + blob); + + assert_true_rule_blob( + "rule test { strings: $a = \"aBc\" wide ascii nocase condition: $a }", + blob); + + assert_true_rule_blob( + "rule test { strings: $a = \"---xyz\" wide nocase condition: $a }", + blob); + + assert_true_rule( + "rule test { strings: $a = \"abc\" fullword condition: $a }", + "abc"); + + assert_false_rule( + "rule test { strings: $a = \"abc\" fullword condition: $a }", + "xabcx"); + + assert_false_rule( + "rule test { strings: $a = \"abc\" fullword condition: $a }", + "xabc"); + + assert_false_rule( + "rule test { strings: $a = \"abc\" fullword condition: $a }", + "abcx"); + + assert_false_rule_blob( + "rule test { strings: $a = \"abc\" wide condition: $a }", + "a\1b\0c\0d\0e\0f\0"); + + assert_false_rule_blob( + "rule test { strings: $a = \"abcdef\" wide condition: $a }", + "a\0b\0c\0d\0e\0f\1"); + + assert_false_rule( + "rule test { strings: $a = \"abc\" ascii wide fullword condition: $a }", + "abcx"); + + assert_true_rule_blob( + "rule test { strings: $a = \"abc\" ascii wide fullword condition: $a }", + "a\0abc"); + + assert_true_rule_blob( + "rule test { strings: $a = \"abc\" wide fullword condition: $a }", + "a\0b\0c\0"); + + assert_false_rule_blob( + "rule test { strings: $a = \"abc\" wide fullword condition: $a }", + "x\0a\0b\0c\0x\0"); + + assert_false_rule_blob( + "rule test { strings: $a = \"ab\" wide fullword condition: $a }", + "x\0a\0b\0"); + + assert_false_rule_blob( + "rule test { strings: $a = \"abc\" wide fullword condition: $a }", + "x\0a\0b\0c\0"); + + assert_true_rule_blob( + "rule test { strings: $a = \"abc\" wide fullword condition: $a }", + "x\001a\0b\0c\0"); + + assert_true_rule( + "rule test {\n\ + strings:\n\ + $a = \"abcdef\"\n\ + $b = \"cdef\"\n\ + $c = \"ef\"\n\ + condition:\n\ + all of them\n\ + }", "abcdef"); + + assert_true_rule_file( + "rule test {\n\ + strings:\n\ + $a = \"This program cannot\" xor\n\ + condition:\n\ + #a == 255\n\ + }", "tests/data/xor.out"); + + assert_true_rule_file( + "rule test {\n\ + strings:\n\ + $a = \"This program cannot\" xor ascii\n\ + condition:\n\ + #a == 256\n\ + }", "tests/data/xor.out"); + + assert_true_rule_file( + "rule test {\n\ + strings:\n\ + $a = \"This program cannot\" xor wide\n\ + condition:\n\ + #a == 256\n\ + }", "tests/data/xorwide.out"); + + assert_true_rule_file( + "rule test {\n\ + strings:\n\ + $a = \"ab\" xor nocase\n\ + condition:\n\ + #a == 1084\n\ + }", "tests/data/xornocase.out"); +} + + +static void test_wildcard_strings() +{ + assert_true_rule_blob( + "rule test {\n\ + strings:\n\ + $s1 = \"abc\"\n\ + $s2 = \"xyz\"\n\ + condition:\n\ + for all of ($*) : ($)\n\ + }", + "---- abc ---- A\x00""B\x00""C\x00 ---- xyz"); +} + + +static void test_hex_strings() +{ + assert_true_rule_blob( + "rule test { \ + strings: $a = { 64 01 00 00 60 01 } \ + condition: $a }", + PE32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { 64 0? 00 00 ?0 01 } \ + condition: $a }", + PE32_FILE); + + assert_true_rule_blob(\ + + "rule test { \ + strings: $a = { 6? 01 00 00 60 0? } \ + condition: $a }", + PE32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { 64 01 [1-3] 60 01 } \ + condition: $a }", + PE32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { 64 01 [1-3] (60|61) 01 } \ + condition: $a }", + PE32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { 4D 5A [-] 6A 2A [-] 58 C3} \ + condition: $a }", + PE32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { 4D 5A [300-] 6A 2A [-] 58 C3} \ + condition: $a }", + PE32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { 2e 7? (65 | ?? ) 78 } \ + condition: $a }", + PE32_FILE); + + assert_false_rule_blob( + "rule test { \ + strings: $a = { 4D 5A [0-300] 6A 2A } \ + condition: $a }", + PE32_FILE); + + assert_false_rule_blob( + "rule test { \ + strings: $a = { 4D 5A [0-128] 45 [0-128] 01 [0-128] C3 } \ + condition: $a }", + PE32_FILE); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [-] 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [-] // Inline comment\n\r \ + 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 /* Inline comment */ [-] 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 /* Inline multi-line\n\r \ + comment */ [-] 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = {\n 31 32 [-] 38 39 \n\r} \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [-] 33 34 [-] 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [1] 34 35 [2] 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test {\ + strings: $a = { 31 32 [1-] 34 35 [1-] 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [0-3] 34 35 [1-] 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [0-2] 35 [1-] 37 38 39 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [0-1] 33 } \ + condition: !a == 3}", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [0-1] 34 } \ + condition: !a == 4}", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [0-2] 34 } \ + condition: !a == 4 }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [-] 38 39 } \ + condition: all of them }", + "1234567890"); + + assert_false_rule( + "rule test { \ + strings: $a = { 31 32 [-] 32 33 } \ + condition: $a }", + "1234567890"); + + assert_false_rule( + "rule test { \ + strings: $a = { 35 36 [-] 31 32 } \ + condition: $a }", + "1234567890"); + + assert_false_rule( + "rule test { \ + strings: $a = { 31 32 [2-] 34 35 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [0-1] 33 34 [0-2] 36 37 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [0-1] 34 35 [0-2] 36 37 } \ + condition: $a }", + "1234567890"); + + assert_false_rule( + "rule test { \ + strings: $a = { 31 32 [0-3] 37 38 } \ + condition: $a }", + "1234567890"); + + assert_true_rule( + "rule test { \ + strings: $a = { 31 32 [1] 33 34 } \ + condition: $a }", + "12\n34"); + + assert_true_rule( + "rule test { \ + strings: $a = {31 32 [3-6] 32} \ + condition: !a == 6 }", + "12111222"); + + assert_true_rule( + "rule test { \ + strings: $a = {31 [0-3] (32|33)} \ + condition: !a == 2 }", + "122222222"); + + assert_error( + "rule test { \ + strings: $a = { 01 [0] 02 } \ + condition: $a }", + ERROR_INVALID_HEX_STRING); + + assert_error( + "rule test { \ + strings: $a = { [-] 01 02 } condition: $a }", + ERROR_INVALID_HEX_STRING); + + assert_error( + "rule test { \ + strings: $a = { 01 02 [-] } \ + condition: $a }", + ERROR_INVALID_HEX_STRING); + + assert_error( + "rule test { \ + strings: $a = { 01 02 ([-] 03 | 04) } \ + condition: $a }", + ERROR_INVALID_HEX_STRING); + + assert_error( + "rule test { \ + strings: $a = { 01 02 (03 [-] | 04) } \ + condition: $a }", + ERROR_INVALID_HEX_STRING); + + assert_error( + "rule test { \ + strings: $a = { 01 02 (03 | 04 [-]) } \ + condition: $a ", + ERROR_INVALID_HEX_STRING); + + /* TODO: tests.py:551 ff. */ +} + + +static void test_count() +{ + assert_true_rule( + "rule test { strings: $a = \"ssi\" condition: #a == 2 }", + "mississippi"); +} + + +static void test_at() +{ + assert_true_rule( + "rule test { \ + strings: $a = \"ssi\" \ + condition: $a at 2 and $a at 5 }", + "mississippi"); + + assert_true_rule( + "rule test { \ + strings: $a = \"mis\" \ + condition: $a at ~0xFF & 0xFF }", + "mississippi"); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { 00 00 00 00 ?? 74 65 78 74 } \ + condition: $a at 308}", + PE32_FILE); +} + + +static void test_in() +{ + assert_true_rule_blob( + "rule test { \ + strings: $a = { 6a 2a 58 c3 } \ + condition: $a in (entrypoint .. entrypoint + 1) }", + PE32_FILE); +} + + +static void test_offset() +{ + assert_true_rule( + "rule test { strings: $a = \"ssi\" condition: @a == 2 }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = \"ssi\" condition: @a == @a[1] }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = \"ssi\" condition: @a[2] == 5 }", + "mississippi"); +} + + +static void test_length() +{ + assert_true_rule( + "rule test { strings: $a = /m.*?ssi/ condition: !a == 5 }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = /m.*?ssi/ condition: !a[1] == 5 }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = /m.*ssi/ condition: !a == 8 }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = /m.*ssi/ condition: !a[1] == 8 }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = /ssi.*ppi/ condition: !a[1] == 9 }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = /ssi.*ppi/ condition: !a[2] == 6 }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = { 6D [1-3] 73 73 69 } condition: !a == 5}", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = { 6D [-] 73 73 69 } condition: !a == 5}", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = { 6D [-] 70 70 69 } condition: !a == 11}", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = { 6D 69 73 73 [-] 70 69 } condition: !a == 11}", + "mississippi"); +} + + +static void test_of() +{ + assert_true_rule( + "rule test { strings: $a = \"ssi\" $b = \"mis\" $c = \"oops\" " + "condition: any of them }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = \"ssi\" $b = \"mis\" $c = \"oops\" " + "condition: 1 of them }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a = \"ssi\" $b = \"mis\" $c = \"oops\" " + "condition: 2 of them }", + "mississippi"); + + assert_true_rule( + "rule test { strings: $a1 = \"dummy1\" $b1 = \"dummy1\" $b2 = \"ssi\"" + "condition: any of ($a*, $b*) }", + "mississippi"); + + assert_true_rule_blob( + "rule test { \ + strings: \ + $ = /abc/ \ + $ = /def/ \ + $ = /ghi/ \ + condition: \ + for any of ($*) : ( for any i in (1..#): (uint8(@[i] - 1) == 0x00) )\ + }", + "abc\000def\000ghi"); + + assert_false_rule( + "rule test { \ + strings: \ + $a = \"ssi\" \ + $b = \"mis\" \ + $c = \"oops\" \ + condition: \ + all of them \ + }", + "mississippi"); + + assert_error( + "rule test { condition: all of ($a*) }", + ERROR_UNDEFINED_STRING); + + assert_error( + "rule test { condition: all of them }", + ERROR_UNDEFINED_STRING); +} + + +void test_for() +{ + assert_true_rule( + "rule test { \ + strings: \ + $a = \"ssi\" \ + condition: \ + for all i in (1..#a) : (@a[i] >= 2 and @a[i] <= 5) \ + }", + "mississippi"); + + assert_true_rule( + "rule test { \ + strings: \ + $a = \"ssi\" \ + $b = \"mi\" \ + condition: \ + for all i in (1..#a) : ( for all j in (1..#b) : (@a[i] >= @b[j])) \ + }", + "mississippi"); + + assert_false_rule( + "rule test { \ + strings: \ + $a = \"ssi\" \ + condition: \ + for all i in (1..#a) : (@a[i] == 5) \ + }", + "mississippi"); +} + + +void test_re() +{ + assert_true_rule( + "rule test { strings: $a = /ssi/ condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /ssi(s|p)/ condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /ssim*/ condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /ssa?/ condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /Miss/ nocase condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /(M|N)iss/ nocase condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /[M-N]iss/ nocase condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /(Mi|ssi)ssippi/ nocase condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /ppi\\tmi/ condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /ppi\\.mi/ condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /^mississippi/ fullword condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_true_rule( + "rule test { strings: $a = /mississippi.*mississippi$/s condition: $a }", + "mississippi\tmississippi.mississippi\nmississippi"); + + assert_false_rule( + "rule test { strings: $a = /^ssi/ condition: $a }", + "mississippi"); + + assert_false_rule( + "rule test { strings: $a = /ssi$/ condition: $a }", + "mississippi"); + + assert_false_rule( + "rule test { strings: $a = /ssissi/ fullword condition: $a }", + "mississippi"); + + assert_false_rule( + "rule test { strings: $a = /^[isp]+/ condition: $a }", + "mississippi"); + + assert_true_rule_blob( + "rule test { strings: $a = /a.{1,2}b/ wide condition: !a == 6 }", + "a\0x\0b\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /a.{1,2}b/ wide condition: !a == 8 }", + "a\0x\0x\0b\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /\\babc/ wide condition: $a }", + "a\0b\0c\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /\\babc/ wide condition: $a }", + "\0a\0b\0c\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /\\babc/ wide condition: $a }", + "\ta\0b\0c\0"); + + assert_false_rule_blob( + "rule test { strings: $a = /\\babc/ wide condition: $a }", + "x\0a\0b\0c\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /\\babc/ wide condition: $a }", + "x\ta\0b\0c\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /abc\\b/ wide condition: $a }", + "a\0b\0c\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /abc\\b/ wide condition: $a }", + "a\0b\0c\0\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /abc\\b/ wide condition: $a }", + "a\0b\0c\0\t"); + + assert_false_rule_blob( + "rule test { strings: $a = /abc\\b/ wide condition: $a }", + "a\0b\0c\0x\0"); + + assert_true_rule_blob( + "rule test { strings: $a = /abc\\b/ wide condition: $a }", + "a\0b\0c\0b\t"); + + assert_false_rule_blob( + "rule test { strings: $a = /\\b/ wide condition: $a }", + "abc"); + + assert_regexp_syntax_error(")"); + assert_true_regexp("abc", "abc", "abc"); + assert_false_regexp("abc", "xbc"); + assert_false_regexp("abc", "axc"); + assert_false_regexp("abc", "abx"); + assert_true_regexp("abc", "xabcx", "abc"); + assert_true_regexp("abc", "ababc", "abc"); + assert_true_regexp("a.c", "abc", "abc"); + assert_false_regexp("a.b", "a\nb"); + assert_false_regexp("a.*b", "acc\nccb"); + assert_false_regexp("a.{4,5}b", "acc\nccb"); + assert_true_regexp("a.b", "a\rb", "a\rb"); + assert_true_regexp("ab*c", "abc", "abc"); + assert_true_regexp("ab*c", "ac", "ac"); + assert_true_regexp("ab*bc", "abc", "abc"); + assert_true_regexp("ab*bc", "abbc", "abbc"); + assert_true_regexp("a.*bb", "abbbb", "abbbb"); + assert_true_regexp("a.*?bbb", "abbbbbb", "abbb"); + assert_true_regexp("a.*c", "ac", "ac"); + assert_true_regexp("a.*c", "axyzc", "axyzc"); + assert_true_regexp("ab+c", "abbc", "abbc"); + assert_false_regexp("ab+c", "ac"); + assert_true_regexp("ab+", "abbbb", "abbbb"); + assert_true_regexp("ab+?", "abbbb", "ab"); + assert_false_regexp("ab+bc", "abc"); + assert_false_regexp("ab+bc", "abq"); + assert_true_regexp("a+b+c", "aabbabc", "abc"); + assert_false_regexp("ab?bc", "abbbbc"); + assert_true_regexp("ab?c", "abc", "abc"); + assert_true_regexp("ab*?", "abbb", "a"); + assert_true_regexp("ab?c", "ac", "ac"); + assert_true_regexp("ab??", "ab", "a"); + assert_true_regexp("a(b|x)c", "abc", "abc"); + assert_true_regexp("a(b|x)c", "axc", "axc"); + assert_true_regexp("a(b|.)c", "axc", "axc"); + assert_true_regexp("a(b|x|y)c", "ayc", "ayc"); + assert_true_regexp("(a+|b)*", "ab", "ab"); + assert_true_regexp("a|b|c|d|e", "e", "e"); + assert_true_regexp("(a|b|c|d|e)f", "ef", "ef"); + assert_true_regexp(".b{2}", "abb", "abb"); + assert_true_regexp(".b{2,3}", "abbb", "abbb"); + assert_true_regexp(".b{2,3}?", "abbb", "abb"); + assert_true_regexp("ab{2,3}c", "abbbc", "abbbc"); + assert_true_regexp("ab{2,3}?c", "abbbc", "abbbc"); + assert_true_regexp(".b{2,3}cccc", "abbbcccc", "abbbcccc"); + assert_true_regexp(".b{2,3}?cccc", "abbbcccc", "bbbcccc"); + assert_true_regexp("a.b{2,3}cccc", "aabbbcccc", "aabbbcccc"); + assert_true_regexp("ab{2,3}c", "abbbc", "abbbc"); + assert_true_regexp("ab{2,3}?c", "abbbc", "abbbc"); + assert_true_regexp("ab{0,1}?c", "abc", "abc"); + assert_true_regexp("a{0,1}?bc", "abc", "abc"); + assert_true_regexp("a{0,1}bc", "bbc", "bc"); + assert_true_regexp("a{0,1}?bc", "abc", "bc"); + assert_true_regexp("aa{0,1}?bc", "abc", "abc"); + assert_true_regexp("aa{0,1}?bc", "abc", "abc"); + assert_true_regexp("aa{0,1}bc", "abc", "abc"); + assert_true_regexp("ab{1}c", "abc", "abc"); + assert_true_regexp("ab{1,2}c", "abbc", "abbc"); + assert_false_regexp("ab{1,2}c", "abbbc"); + assert_true_regexp("ab{1,}c", "abbbc", "abbbc"); + assert_false_regexp("ab{1,}b", "ab"); + assert_false_regexp("ab{1}c", "abbc"); + assert_false_regexp("ab{1}c", "ac"); + assert_true_regexp("ab{0,}c", "ac", "ac"); + assert_true_regexp("ab{1,1}c", "abc", "abc"); + assert_true_regexp("ab{0,}c", "abbbc", "abbbc"); + assert_true_regexp("ab{,3}c", "abbbc", "abbbc"); + assert_false_regexp("ab{,2}c", "abbbc"); + assert_false_regexp("ab{4,5}bc", "abbbbc"); + assert_false_regexp("ab{3}c", "abbbbc"); // Issue #817 + assert_false_regexp("ab{4}c", "abbbbbc"); + assert_false_regexp("ab{5}c", "abbbbbbc"); + assert_true_regexp("ab{0,1}", "abbbbb", "ab"); + assert_true_regexp("ab{0,2}", "abbbbb", "abb"); + assert_true_regexp("ab{0,3}", "abbbbb", "abbb"); + assert_true_regexp("ab{0,4}", "abbbbb", "abbbb"); + assert_true_regexp("ab{1,1}", "abbbbb", "ab"); + assert_true_regexp("ab{1,2}", "abbbbb", "abb"); + assert_true_regexp("ab{1,3}", "abbbbb", "abbb"); + assert_true_regexp("ab{2,2}", "abbbbb", "abb"); + assert_true_regexp("ab{2,3}", "abbbbb", "abbb"); + assert_true_regexp("ab{2,4}", "abbbbc", "abbbbc"); + assert_true_regexp("ab{3,4}", "abbb", "abbb"); + assert_true_regexp("ab{3,4}", "abbbbc", "abbbbc"); + assert_true_regexp("ab{3,5}", "abbbbc", "abbbbc"); + assert_false_regexp("ab{3,4}c", "abbbbbc"); + assert_false_regexp("ab{3,4}c", "abbc"); + assert_false_regexp("ab{3,5}c", "abbbbbbc"); + assert_true_regexp("ab{1,3}?", "abbbbb", "ab"); + assert_true_regexp("ab{0,1}?", "abbbbb", "a"); + assert_true_regexp("ab{0,2}?", "abbbbb", "a"); + assert_true_regexp("ab{0,3}?", "abbbbb", "a"); + assert_true_regexp("ab{0,4}?", "abbbbb", "a"); + assert_true_regexp("ab{1,1}?", "abbbbb", "ab"); + assert_true_regexp("ab{1,2}?", "abbbbb", "ab"); + assert_true_regexp("ab{1,3}?", "abbbbb", "ab"); + assert_true_regexp("ab{2,2}?", "abbbbb", "abb"); + assert_true_regexp("ab{2,3}?", "abbbbb", "abb"); + assert_true_regexp(".(abc){0,1}", "xabcabcabcabc", "xabc"); + assert_true_regexp(".(abc){0,2}", "xabcabcabcabc", "xabcabc"); + assert_true_regexp("x{1,2}abcd", "xxxxabcd", "xxabcd"); + assert_true_regexp("x{1,2}abcd", "xxxxabcd", "xxabcd"); + assert_true_regexp("ab{.*}", "ab{c}", "ab{c}"); + assert_true_regexp(".(aa){1,2}", "aaaaaaaaaa", "aaaaa"); + assert_true_regexp("a.(bc.){2}", "aabcabca", "aabcabca"); + assert_true_regexp("(ab{1,2}c){1,3}", "abbcabc", "abbcabc"); + assert_true_regexp("ab(c|cc){1,3}d", "abccccccd", "abccccccd"); + assert_true_regexp("a[bx]c", "abc", "abc"); + assert_true_regexp("a[bx]c", "axc", "axc"); + assert_true_regexp("a[0-9]*b", "ab", "ab"); + assert_true_regexp("a[0-9]*b", "a0123456789b", "a0123456789b"); + assert_true_regexp("[0-9a-f]+", "0123456789abcdef", "0123456789abcdef"); + assert_true_regexp("[0-9a-f]+", "xyz0123456789xyz", "0123456789"); + assert_true_regexp("a[\\s\\S]b", "a b", "a b"); + assert_true_regexp("a[\\d\\D]b", "a1b", "a1b"); + assert_false_regexp("[x-z]+", "abc"); + assert_true_regexp("a[-]?c", "ac", "ac"); + assert_true_regexp("a[-b]", "a-", "a-"); + assert_true_regexp("a[-b]", "ab", "ab"); + assert_true_regexp("a[b-]", "a-", "a-"); + assert_true_regexp("a[b-]", "ab", "ab"); + assert_true_regexp("[a-c-e]", "b", "b"); + assert_true_regexp("[a-c-e]", "-", "-"); + assert_false_regexp("[a-c-e]", "d"); + assert_regexp_syntax_error("[b-a]"); + assert_regexp_syntax_error("(abc"); + assert_regexp_syntax_error("abc)"); + assert_regexp_syntax_error("a[]b"); + assert_true_regexp("a[\\-b]", "a-", "a-"); + assert_true_regexp("a[\\-b]", "ab", "ab"); + assert_true_regexp("a]", "a]", "a]"); + assert_true_regexp("a[]]b", "a]b", "a]b"); + assert_true_regexp("a[\\]]b", "a]b", "a]b"); + assert_true_regexp("a[^bc]d", "aed", "aed"); + assert_false_regexp("a[^bc]d", "abd"); + assert_true_regexp("a[^-b]c", "adc", "adc"); + assert_false_regexp("a[^-b]c", "a-c"); + assert_false_regexp("a[^]b]c", "a]c"); + assert_true_regexp("a[^]b]c", "adc", "adc"); + assert_true_regexp("[^ab]*", "cde", "cde"); + assert_regexp_syntax_error(")("); + assert_true_regexp("a\\sb", "a b", "a b"); + assert_true_regexp("a\\sb", "a\tb", "a\tb"); + assert_true_regexp("a\\sb", "a\rb", "a\rb"); + assert_true_regexp("a\\sb", "a\nb", "a\nb"); + assert_true_regexp("a\\sb", "a\vb", "a\vb"); + assert_true_regexp("a\\sb", "a\fb", "a\fb"); + assert_false_regexp("a\\Sb", "a b"); + assert_false_regexp("a\\Sb", "a\tb"); + assert_false_regexp("a\\Sb", "a\rb"); + assert_false_regexp("a\\Sb", "a\nb"); + assert_false_regexp("a\\Sb", "a\vb"); + assert_false_regexp("a\\Sb", "a\fb"); + assert_true_regexp("\\n\\r\\t\\f\\a", "\n\r\t\f\a", "\n\r\t\f\a"); + assert_true_regexp("[\\n][\\r][\\t][\\f][\\a]", "\n\r\t\f\a", "\n\r\t\f\a"); + assert_true_regexp("\\x01\\x02\\x03", "\x01\x02\x03", "\x01\x02\x03"); + assert_true_regexp("[\\x01-\\x03]+", "\x01\x02\x03", "\x01\x02\x03"); + assert_false_regexp("[\\x00-\\x02]+", "\x03\x04\x05"); + assert_true_regexp("[\\x5D]", "]", "]"); + assert_true_regexp("[\\0x5A-\\x5D]", "\x5B", "\x5B"); + assert_true_regexp("[\\x5D-\\x5F]", "\x5E", "\x5E"); + assert_true_regexp("[\\x5C-\\x5F]", "\x5E", "\x5E"); + assert_true_regexp("[\\x5D-\\x5F]", "\x5E", "\x5E"); + assert_true_regexp("a\\wc", "abc", "abc"); + assert_true_regexp("a\\wc", "a_c", "a_c"); + assert_true_regexp("a\\wc", "a0c", "a0c"); + assert_false_regexp("a\\wc", "a*c"); + assert_true_regexp("\\w+", "--ab_cd0123--", "ab_cd0123"); + assert_true_regexp("[\\w]+", "--ab_cd0123--", "ab_cd0123"); + assert_true_regexp("\\D+", "1234abc5678", "abc"); + assert_true_regexp("[\\d]+", "0123456789", "0123456789"); + assert_true_regexp("[\\D]+", "1234abc5678", "abc"); + assert_true_regexp("[\\da-fA-F]+", "123abc", "123abc"); + assert_false_regexp("^(ab|cd)e", "abcde"); + assert_true_regexp("(abc|)ef", "abcdef", "ef"); + assert_true_regexp("(abc|)ef", "abcef", "abcef"); + assert_true_regexp("\\babc", "abc", "abc"); + assert_true_regexp("abc\\b", "abc", "abc"); + assert_false_regexp("\\babc", "1abc"); + assert_false_regexp("abc\\b", "abc1"); + assert_true_regexp("abc\\s\\b", "abc x", "abc "); + assert_false_regexp("abc\\s\\b", "abc "); + assert_true_regexp("\\babc\\b", " abc ", "abc"); + assert_true_regexp("\\b\\w\\w\\w\\b", " abc ", "abc"); + assert_true_regexp("\\w\\w\\w\\b", "abcd", "bcd"); + assert_true_regexp("\\b\\w\\w\\w", "abcd", "abc"); + assert_false_regexp("\\b\\w\\w\\w\\b", "abcd"); + assert_false_regexp("\\Babc", "abc"); + assert_false_regexp("abc\\B", "abc"); + assert_true_regexp("\\Babc", "1abc", "abc"); + assert_true_regexp("abc\\B", "abc1", "abc"); + assert_false_regexp("abc\\s\\B", "abc x"); + assert_true_regexp("abc\\s\\B", "abc ", "abc "); + assert_true_regexp("\\w\\w\\w\\B", "abcd", "abc"); + assert_true_regexp("\\B\\w\\w\\w", "abcd", "bcd"); + assert_false_regexp("\\B\\w\\w\\w\\B", "abcd"); + + // This is allowed in most regexp engines but in order to keep the + // grammar free of shift/reduce conflicts I've decided not supporting + // it. Users can use the (abc|) form instead. + assert_regexp_syntax_error("(|abc)ef"); + + assert_true_regexp("((a)(b)c)(d)", "abcd", "abcd"); + assert_true_regexp("(a|b)c*d", "abcd", "bcd"); + assert_true_regexp("(ab|ab*)bc", "abc", "abc"); + assert_true_regexp("a([bc]*)c*", "abc", "abc"); + assert_true_regexp("a([bc]*)c*", "ac", "ac"); + assert_true_regexp("a([bc]*)c*", "a", "a"); + assert_true_regexp("a([bc]*)(c*d)", "abcd", "abcd"); + assert_true_regexp("a([bc]+)(c*d)", "abcd", "abcd"); + assert_true_regexp("a([bc]*)(c+d)", "abcd", "abcd"); + assert_true_regexp("a[bcd]*dcdcde", "adcdcde", "adcdcde"); + assert_false_regexp("a[bcd]+dcdcde", "adcdcde"); + assert_true_regexp("\\((.*), (.*)\\)", "(a, b)", "(a, b)"); + assert_true_regexp("abc|123$", "abcx", "abc"); + assert_false_regexp("abc|123$", "123x"); + assert_true_regexp("abc|^123", "123", "123"); + assert_false_regexp("abc|^123", "x123"); + assert_true_regexp("^abc$", "abc", "abc"); + assert_false_regexp("^abc$", "abcc"); + assert_true_regexp("^abc", "abcc", "abc"); + assert_false_regexp("^abc$", "aabc"); + assert_false_regexp("abc^", "abc"); + assert_false_regexp("ab^c", "abc"); + assert_false_regexp("a^bcdef", "abcdef") + assert_true_regexp("abc$", "aabc", "abc"); + assert_false_regexp("$abc", "abc"); + assert_true_regexp("(a|a$)bcd", "abcd", "abcd"); + assert_false_regexp("(a$|a$)bcd", "abcd"); + assert_false_regexp("(abc$|ab$)", "abcd"); + assert_true_regexp("^a(bc+|b[eh])g|.h$", "abhg", "abhg"); + assert_true_regexp("(bc+d$|ef*g.|h?i(j|k))", "effgz", "effgz"); + assert_true_regexp("(bc+d$|ef*g.|h?i(j|k))", "ij", "ij"); + assert_false_regexp("(bc+d$|ef*g.|h?i(j|k))", "effg"); + assert_false_regexp("(bc+d$|ef*g.|h?i(j|k))", "bcdd"); + assert_true_regexp("(bc+d$|ef*g.|h?i(j|k))", "reffgz", "effgz"); + + // Test case for issue #324 + assert_true_regexp("whatever| x. x", " xy x", " xy x"); + + // test case for issue #503, \x without two following hex-digits + assert_regexp_syntax_error("\\x0"); + assert_regexp_syntax_error("\\x"); + + assert_regexp_syntax_error("x{0,0}"); + assert_regexp_syntax_error("x{0}"); + + assert_regexp_syntax_error("\\xxy"); + + // Test case for issue #682 + assert_true_regexp("(a|\\b)[a]{1,}", "aaaa", "aaaa"); + + // Test for integer overflow in repeat interval + assert_regexp_syntax_error("a{2977952116}"); + + assert_error( + "rule test { strings: $a = /a\\/ condition: $a }", + ERROR_SYNTAX_ERROR); + + assert_error( + "rule test { strings: $a = /[a\\/ condition: $a }", + ERROR_SYNTAX_ERROR); + + assert_true_rule_blob( + "rule test { \ + strings: $a = /MZ.{300,}t/ \ + condition: !a == 317 }", + PE32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = /MZ.{300,}?t/ \ + condition: !a == 314 }", + PE32_FILE); + + assert_false_rule( + "rule test { strings: $a = /abc[^d]/ nocase condition: $a }", + "abcd"); + + assert_false_rule( + "rule test { strings: $a = /abc[^d]/ condition: $a }", + "abcd"); + + assert_false_rule( + "rule test { strings: $a = /abc[^D]/ nocase condition: $a }", + "abcd"); + + assert_true_rule( + "rule test { strings: $a = /abc[^D]/ condition: $a }", + "abcd"); + + assert_true_rule( + "rule test { strings: $a = /abc[^f]/ nocase condition: $a }", + "abcd"); + + assert_true_rule( + "rule test { strings: $a = /abc[^f]/ condition: $a }", + "abcd"); + + assert_true_rule( + "rule test { strings: $a = /abc[^F]/ nocase condition: $a }", + "abcd"); + + assert_true_rule( + "rule test { strings: $a = /abc[^F]/ condition: $a }", + "abcd"); +} + + +static void test_entrypoint() +{ + assert_true_rule_blob( + "rule test { \ + strings: $a = { 6a 2a 58 c3 } \ + condition: $a at entrypoint }", + PE32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { b8 01 00 00 00 bb 2a } \ + condition: $a at entrypoint }", + ELF32_FILE); + + assert_true_rule_blob( + "rule test { \ + strings: $a = { b8 01 00 00 00 bb 2a } \ + condition: $a at entrypoint }", + ELF64_FILE); + + assert_false_rule( + "rule test { condition: entrypoint >= 0 }", + NULL); +} + + +static void test_filesize() +{ + char rule[80]; + + snprintf( + rule, + sizeof(rule), + "rule test { condition: filesize == %zd }", + sizeof(PE32_FILE)); + + assert_true_rule_blob( + rule, + PE32_FILE); +} + + +static void test_comments() +{ + assert_true_rule( + "rule test {\n\ + condition:\n\ + // this is a comment\n\ + /*** this is a comment ***/\n\ + /* /* /*\n\ + this is a comment\n\ + */\n\ + true\n\ + }", + NULL); +} + +static void test_matches_operator() +{ + assert_true_rule( + "rule test { condition: \"foo\" matches /foo/ }", + NULL); + + assert_false_rule( + "rule test { condition: \"foo\" matches /bar/ }", + NULL); + + assert_true_rule( + "rule test { condition: \"FoO\" matches /fOo/i }", + NULL); + + assert_true_rule( + "rule test { condition: \"xxFoOxx\" matches /fOo/i }", + NULL); + + assert_false_rule( + "rule test { condition: \"xxFoOxx\" matches /^fOo/i }", + NULL); + + assert_false_rule( + "rule test { condition: \"xxFoOxx\" matches /fOo$/i }", + NULL); + + assert_true_rule( + "rule test { condition: \"foo\" matches /^foo$/i }", + NULL); + + assert_true_rule( + "rule test { condition: \"foo\\nbar\" matches /foo.*bar/s }", + NULL); + + assert_false_rule( + "rule test { condition: \"foo\\nbar\" matches /foo.*bar/ }", + NULL); +} + + +static void test_global_rules() +{ + assert_true_rule( + "global private rule global_rule { \ + condition: \ + true \ + } \ + rule test { \ + condition: true \ + }", + NULL); + + assert_false_rule( + "global private rule global_rule { \ + condition: \ + false \ + } \ + rule test { \ + condition: true \ + }", + NULL); +} + + +static void test_modules() +{ + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.constants.one + 1 == tests.constants.two \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.constants.foo == \"foo\" \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.constants.empty == \"\" \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.empty() == \"\" \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.struct_array[1].i == 1 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.struct_array[0].i == 1 or true \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.integer_array[0] == 0 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.integer_array[1] == 1 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.integer_array[256] == 256 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.string_array[0] == \"foo\" \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.string_array[2] == \"baz\" \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.string_dict[\"foo\"] == \"foo\" \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.string_dict[\"bar\"] == \"bar\" \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.isum(1,2) == 3 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.isum(1,2,3) == 6 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.fsum(1.0,2.0) == 3.0 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.fsum(1.0,2.0,3.0) == 6.0 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.foobar(1) == tests.foobar(1) \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.foobar(1) != tests.foobar(2) \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { \ + condition: tests.length(\"dummy\") == 5 \ + }", + NULL); + + + assert_false_rule( + "import \"tests\" \ + rule test { condition: tests.struct_array[0].i == 1 \ + }", + NULL); + + assert_false_rule( + "import \"tests\" \ + rule test { condition: tests.isum(1,1) == 3 \ + }", + NULL); + + assert_false_rule( + "import \"tests\" \ + rule test { condition: tests.fsum(1.0,1.0) == 3.0 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { condition: tests.match(/foo/,\"foo\") == 3 \ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { condition: tests.match(/foo/,\"bar\") == -1\ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { condition: tests.match(/foo.bar/i,\"FOO\\nBAR\") == -1\ + }", + NULL); + + assert_true_rule( + "import \"tests\" \ + rule test { condition: tests.match(/foo.bar/is,\"FOO\\nBAR\") == 7\ + }", + NULL); + + assert_error( + "import \"\\x00\"", + ERROR_INVALID_MODULE_NAME); + + assert_error( + "import \"\"", + ERROR_INVALID_MODULE_NAME); +} + + +static void test_time_module() +{ + assert_true_rule( + "import \"time\" \ + rule test { condition: time.now() > 0 }", + NULL); +} + + +#if defined(HASH_MODULE) +static void test_hash_module() +{ + uint8_t blob[] = {0x61, 0x62, 0x63, 0x64, 0x65}; + + assert_true_rule_blob( + "import \"hash\" \ + rule test { \ + condition: \ + hash.md5(0, filesize) == \ + \"ab56b4d92b40713acc5af89985d4b786\" \ + and \ + hash.md5(1, filesize) == \ + \"e02cfbe5502b64aa5ae9f2d0d69eaa8d\" \ + and \ + hash.sha1(0, filesize) == \ + \"03de6c570bfe24bfc328ccd7ca46b76eadaf4334\" \ + and \ + hash.sha1(1, filesize) == \ + \"a302d65ae4d9e768a1538d53605f203fd8e2d6e2\" \ + and \ + hash.sha256(0, filesize) == \ + \"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c\" \ + and \ + hash.sha256(1, filesize) == \ + \"aaaaf2863e043b9df604158ad5c16ff1adaf3fd7e9fcea5dcb322b6762b3b59a\" \ + }", + blob); + + // Test hash caching mechanism + + assert_true_rule_blob( + "import \"hash\" \ + rule test { \ + condition: \ + hash.md5(0, filesize) == \ + \"ab56b4d92b40713acc5af89985d4b786\" \ + and \ + hash.md5(1, filesize) == \ + \"e02cfbe5502b64aa5ae9f2d0d69eaa8d\" \ + and \ + hash.md5(0, filesize) == \ + \"ab56b4d92b40713acc5af89985d4b786\" \ + and \ + hash.md5(1, filesize) == \ + \"e02cfbe5502b64aa5ae9f2d0d69eaa8d\" \ + }", + blob); +} +#endif + + +void test_integer_functions() +{ + assert_true_rule( + "rule test { condition: uint8(0) == 0xAA}", + "\xaa\xbb\xcc\xdd"); + + assert_true_rule( + "rule test { condition: uint16(0) == 0xBBAA}", + "\xaa\xbb\xcc\xdd"); + + assert_true_rule( + "rule test { condition: uint32(0) == 0xDDCCBBAA}", + "\xaa\xbb\xcc\xdd"); + + assert_true_rule( + "rule test { condition: uint8be(0) == 0xAA}", + "\xaa\xbb\xcc\xdd"); + + assert_true_rule( + "rule test { condition: uint16be(0) == 0xAABB}", + "\xaa\xbb\xcc\xdd"); + + assert_true_rule( + "rule test { condition: uint32be(0) == 0xAABBCCDD}", + "\xaa\xbb\xcc\xdd"); +} + + +void test_include_files() +{ + assert_true_rule( + "include \"tests/data/baz.yar\" rule t { condition: baz }", + NULL); + + assert_true_rule( + "include \"tests/data/foo.yar\" rule t { condition: foo }", + NULL); +} + + +void test_process_scan() +{ + int pid = fork(); + int status = 0; + int matches = 0; + YR_RULES* rules; + int rc1, rc2; + + if (pid == 0) + { + /* The string should appear somewhere in the shell's process space. */ + if (execl("/bin/sh", "/bin/sh", "-c", "VAR='Hello, world!'; sleep 5; true", NULL) == -1) + exit(1); + } + assert(pid > 0); + + /* Give child process time to initialize */ + sleep(1); + + assert( compile_rule("\ + rule test {\ + strings:\ + $a = { 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 }\ + condition:\ + all of them\ + }", &rules) == ERROR_SUCCESS); + rc1 = yr_rules_scan_proc(rules, pid, 0, count_matches, &matches, 0); + kill(pid, SIGALRM); + + rc2 = waitpid(pid, &status, 0); + if (rc2 == -1) + { + perror("waitpid"); + exit(EXIT_FAILURE); + } + if (status != SIGALRM) + { + fprintf(stderr, "Scanned process exited with unexpected status %d\n", status); + exit(EXIT_FAILURE); + } + + switch (rc1) { + case ERROR_SUCCESS: + if (matches == 0) + { + fputs("Found no matches\n", stderr); + exit(EXIT_FAILURE); + } + break; + case ERROR_COULD_NOT_ATTACH_TO_PROCESS: + fputs("Could not attach to process, ignoring this error\n", stderr); + break; + default: + fprintf(stderr, "yr_rules_scan_proc: Got unexpected error %d\n", rc1); + exit(EXIT_FAILURE); + } +} + + +int main(int argc, char** argv) +{ + yr_initialize(); + + test_boolean_operators(); + test_comparison_operators(); + test_arithmetic_operators(); + test_bitwise_operators(); + test_matches_operator(); + test_syntax(); + test_anonymous_strings(); + test_strings(); + test_wildcard_strings(); + test_hex_strings(); + test_count(); + test_at(); + test_in(); + test_offset(); + test_length(); + test_of(); + test_for(); + test_re(); + test_filesize(); + test_include_files(); + // test_compile_file(); + // test_compile_files(); + + // test_externals(); + // test_callback(); + // test_compare(); + test_comments(); + test_modules(); + test_integer_functions(); + // test_string_io(); + test_entrypoint(); + test_global_rules(); + + #if HAVE_SCAN_PROC_IMPL == 1 + test_process_scan(); + #endif + + #if defined(HASH_MODULE) + test_hash_module(); + #endif + + test_time_module(); + + yr_finalize(); + + return 0; +} diff --git a/yara-master/tests/test-version.c b/yara-master/tests/test-version.c new file mode 100644 index 0000000..be5e988 --- /dev/null +++ b/yara-master/tests/test-version.c @@ -0,0 +1,39 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +int main (int argc, char **argv) +{ + // make sure that versions defined in configure.ac and in + // libyara/include/yara/libyara.h are in sync. + + return strcmp(PACKAGE_VERSION, YR_VERSION); +} diff --git a/yara-master/tests/util.c b/yara-master/tests/util.c new file mode 100644 index 0000000..e704ad3 --- /dev/null +++ b/yara-master/tests/util.c @@ -0,0 +1,257 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include +#include + +#include +#include +#include + +#include + +char compile_error[1024]; + +static void callback_function( + int error_level, + const char* file_name, + int line_number, + const char* message, + void* user_data) +{ + snprintf( + compile_error, + sizeof(compile_error), + "line %d: %s", + line_number, + message); +} + + +int compile_rule( + char* string, + YR_RULES** rules) +{ + YR_COMPILER* compiler = NULL; + int result = ERROR_SUCCESS; + + compile_error[0] = '\0'; + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + { + perror("yr_compiler_create"); + goto _exit; + } + + yr_compiler_set_callback(compiler, callback_function, NULL); + + if (yr_compiler_add_string(compiler, string, NULL) != 0) + { + result = compiler->last_error; + goto _exit; + } + + result = yr_compiler_get_rules(compiler, rules); + +_exit: + yr_compiler_destroy(compiler); + return result; +} + + +int count_matches( + int message, + void* message_data, + void* user_data) +{ + if (message == CALLBACK_MSG_RULE_MATCHING) + { + (*(int*) user_data)++; + } + + return CALLBACK_CONTINUE; +} + +int do_nothing( + int message, + void* message_data, + void* user_data) +{ + return CALLBACK_CONTINUE; +} + + +int matches_blob( + char* rule, + uint8_t* blob, + size_t len) +{ + YR_RULES* rules; + + if (blob == NULL) + { + blob = (uint8_t*) "dummy"; + len = 5; + } + + if (compile_rule(rule, &rules) != ERROR_SUCCESS) + { + fprintf(stderr, "failed to compile rule << %s >>: %s\n", rule, compile_error); + exit(EXIT_FAILURE); + } + + int matches = 0; + int scan_result = yr_rules_scan_mem( + rules, blob, len, 0, count_matches, &matches, 0); + + if (scan_result != ERROR_SUCCESS) + { + fprintf(stderr, "yr_rules_scan_mem: error\n"); + exit(EXIT_FAILURE); + } + + yr_rules_destroy(rules); + + return matches; +} + + +int matches_string( + char* rule, + char* string) +{ + size_t len = 0; + + if (string != NULL) + len = strlen(string); + + return matches_blob(rule, (uint8_t*)string, len); +} + +typedef struct +{ + char* expected; + int found; + +} find_string_t; + + +static int capture_matches( + int message, + void* message_data, + void* user_data) +{ + if (message == CALLBACK_MSG_RULE_MATCHING) + { + find_string_t* f = (find_string_t*) user_data; + + YR_RULE* rule = (YR_RULE*) message_data; + YR_STRING* string; + + yr_rule_strings_foreach(rule, string) + { + YR_MATCH* match; + + yr_string_matches_foreach(string, match) + { + int r = strncmp( + f->expected, (char*) (match->data), match->data_length); + + if (r == 0) + f->found++; + } + } + } + + return CALLBACK_CONTINUE; +} + + +int capture_string( + char* rule, + char* string, + char* expected_string) +{ + YR_RULES* rules; + + if (compile_rule(rule, &rules) != ERROR_SUCCESS) + { + fprintf(stderr, "failed to compile rule << %s >>: %s\n", rule, compile_error); + exit(EXIT_FAILURE); + } + + find_string_t f; + + f.found = 0; + f.expected = expected_string; + + if (yr_rules_scan_mem(rules, (uint8_t*)string, strlen(string), 0, + capture_matches, &f, 0) != ERROR_SUCCESS) + { + fprintf(stderr, "yr_rules_scan_mem: error\n"); + exit(EXIT_FAILURE); + } + + yr_rules_destroy(rules); + + return f.found; +} + + +int read_file( + char* filename, + char** buf) +{ + int fd; + + if ((fd = open(filename, O_RDONLY)) < 0) + return -1; + + size_t sz = lseek(fd, 0, SEEK_END); + int rc = -1; + + if (sz == -1) + goto _exit; + + if (lseek(fd, 0, SEEK_SET) != 0) + goto _exit; + + if ((*buf = malloc(sz)) == NULL) + goto _exit; + + if ((rc = read(fd, *buf, sz)) != sz) + { + rc = -1; + free(*buf); + } + +_exit: + close(fd); + return rc; +} diff --git a/yara-master/tests/util.h b/yara-master/tests/util.h new file mode 100644 index 0000000..3693559 --- /dev/null +++ b/yara-master/tests/util.h @@ -0,0 +1,180 @@ +/* +Copyright (c) 2016. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef _UTIL_H +#define _UTIL_H + +extern char compile_error[1024]; + +int compile_rule( + char* string, + YR_RULES** rules); + + +int count_matches( + int message, + void* message_data, + void* user_data); + + +int do_nothing( + int message, + void* message_data, + void* user_data); + + +int matches_blob( + char* rule, + uint8_t* blob, + size_t len); + + +int matches_string( + char* rule, + char* string); + + +int capture_string( + char* rule, + char* string, + char* expected_string); + + +int read_file( + char* filename, char** buf); + + +#define assert_true_rule(rule, string) \ + do { \ + if (!matches_string(rule, string)) { \ + fprintf(stderr, "%s:%d: rule does not match (but should)\n", \ + __FILE__, __LINE__ ); \ + exit(EXIT_FAILURE); \ + } \ + } while (0); + +#define assert_true_rule_blob_size(rule, blob, size) \ + do { \ + if (!matches_blob(rule, (uint8_t*) (blob), size)) { \ + fprintf(stderr, "%s:%d: rule does not match (but should)\n", \ + __FILE__, __LINE__ ); \ + exit(EXIT_FAILURE); \ + } \ + } while (0); + +#define assert_true_rule_blob(rule, blob) \ + assert_true_rule_blob_size(rule, blob, sizeof(blob)) + +#define assert_true_rule_file(rule, filename) \ + do { \ + char* buf; \ + size_t sz; \ + if ((sz = read_file(filename, &buf)) == -1) { \ + fprintf(stderr, "%s:%d: cannot read file '%s'\n", \ + __FILE__, __LINE__, filename); \ + exit(EXIT_FAILURE); \ + } \ + if (!matches_blob(rule, (uint8_t*) (buf), sz)) { \ + fprintf(stderr, "%s:%d: rule does not match contents of" \ + "'%s' (but should)\n", \ + __FILE__, __LINE__, filename); \ + exit(EXIT_FAILURE); \ + } \ + free(buf); \ + } while (0); + +#define assert_false_rule(rule, string) \ + do { \ + if (matches_string(rule, string)) { \ + fprintf(stderr, "%s:%d: rule matches (but shouldn't)\n", \ + __FILE__, __LINE__ ); \ + exit(EXIT_FAILURE); \ + } \ + } while (0); + +#define assert_false_rule_blob_size(rule, blob, size) \ + do { \ + if (matches_blob(rule, (uint8_t*) (blob), size)) { \ + fprintf(stderr, "%s:%d: rule matches (but shouldn't)\n", \ + __FILE__, __LINE__ ); \ + exit(EXIT_FAILURE); \ + } \ + } while (0); + +#define assert_false_rule_blob(rule, blob) \ + assert_false_rule_blob_size(rule, blob, sizeof(blob)) + +#define assert_false_rule_file(rule, filename) \ + do { \ + char* buf; \ + size_t sz; \ + if ((sz = read_file(filename, &buf)) == -1) { \ + fprintf(stderr, "%s:%d: cannot read file '%s'\n", \ + __FILE__, __LINE__, filename); \ + exit(EXIT_FAILURE); \ + } \ + if (matches_blob(rule, (uint8_t*) (buf), sz)) { \ + fprintf(stderr, "%s:%d: rule matches contents of" \ + "'%s' (but shouldn't)\n", \ + __FILE__, __LINE__, filename); \ + exit(EXIT_FAILURE); \ + } \ + free(buf); \ + } while (0); + +#define assert_error(rule, error) do { \ + YR_RULES* rules; \ + int result = compile_rule(rule, &rules); \ + if (result == ERROR_SUCCESS) \ + yr_rules_destroy(rules); \ + if (result != error) { \ + fprintf(stderr, "%s:%d: expecting error %d but returned %d\n", \ + __FILE__, __LINE__, error, result); \ + exit(EXIT_FAILURE); \ + } \ + } while (0); + +#define assert_true_regexp(regexp,string,expected) do { \ + if (!capture_string("rule test { strings: $a = /" regexp \ + "/ condition: $a }", string, expected)) { \ + fprintf(stderr, "%s:%d: regexp does not match\n", \ + __FILE__, __LINE__); \ + exit(EXIT_FAILURE); \ + } \ + } while (0); + +#define assert_false_regexp(regexp,string) \ + assert_false_rule("rule test { strings: $a = /" regexp \ + "/ condition: $a }", string) + +#define assert_regexp_syntax_error(regexp) \ + assert_error("rule test { strings: $a = /" regexp "/ condition: $a }",\ + ERROR_INVALID_REGULAR_EXPRESSION) + +#endif /* _UTIL_H */ diff --git a/yara-master/threading.c b/yara-master/threading.c new file mode 100644 index 0000000..c92be06 --- /dev/null +++ b/yara-master/threading.c @@ -0,0 +1,180 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#include + +#if !defined(_WIN32) && !defined(__CYGWIN__) +#include +#endif + +#if defined(__FreeBSD__) +#include +#endif + +#include "threading.h" + + +int mutex_init( + MUTEX* mutex) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + InitializeCriticalSection(mutex); + return 0; + #else + return pthread_mutex_init(mutex, NULL); + #endif +} + +void mutex_destroy( + MUTEX* mutex) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + DeleteCriticalSection(mutex); + #else + pthread_mutex_destroy(mutex); + #endif +} + + +void mutex_lock( + MUTEX* mutex) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + EnterCriticalSection(mutex); + #else + pthread_mutex_lock(mutex); + #endif +} + + +void mutex_unlock( + MUTEX* mutex) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + LeaveCriticalSection(mutex); + #else + pthread_mutex_unlock(mutex); + #endif +} + + +int semaphore_init( + SEMAPHORE* semaphore, + int value) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + *semaphore = CreateSemaphore(NULL, value, 65535, NULL); + if (*semaphore == NULL) + return GetLastError(); + #elif defined(__FreeBSD__) + *semaphore = malloc(sizeof(sem_t)); + if (*semaphore == NULL) + return errno; + return sem_init(*semaphore, 0, value); + #else + // Mac OS X doesn't support unnamed semaphores via sem_init, that's why + // we use sem_open instead sem_init and immediately unlink the semaphore + // from the name. More info at: + // + // http://stackoverflow.com/questions/1413785/sem-init-on-os-x + *semaphore = sem_open("/semaphore", O_CREAT, S_IRUSR, value); + + if (*semaphore == SEM_FAILED) + return errno; + + if (sem_unlink("/semaphore") != 0) + return errno; + #endif + + return 0; +} + + +void semaphore_destroy( + SEMAPHORE* semaphore) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + CloseHandle(*semaphore); + #elif defined(__FreeBSD__) + sem_close(*semaphore); + free(*semaphore); + #else + sem_close(*semaphore); + #endif +} + + +void semaphore_wait( + SEMAPHORE* semaphore) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + WaitForSingleObject(*semaphore, INFINITE); + #else + sem_wait(*semaphore); + #endif +} + + +void semaphore_release( + SEMAPHORE* semaphore) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + ReleaseSemaphore(*semaphore, 1, NULL); + #else + sem_post(*semaphore); + #endif +} + + +int create_thread( + THREAD* thread, + THREAD_START_ROUTINE start_routine, + void* param) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + *thread = CreateThread(NULL, 0, start_routine, param, 0, NULL); + if (*thread == NULL) + return GetLastError(); + else + return 0; + #else + return pthread_create(thread, NULL, start_routine, param); + #endif +} + + +void thread_join( + THREAD* thread) +{ + #if defined(_WIN32) || defined(__CYGWIN__) + WaitForSingleObject(*thread, INFINITE); + #else + pthread_join(*thread, NULL); + #endif +} diff --git a/yara-master/threading.h b/yara-master/threading.h new file mode 100644 index 0000000..43a68b6 --- /dev/null +++ b/yara-master/threading.h @@ -0,0 +1,92 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + + +#ifndef THREADING_H +#define THREADING_H + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#else +#include +#include +#include +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) + +typedef HANDLE SEMAPHORE; +typedef CRITICAL_SECTION MUTEX; +typedef HANDLE THREAD; + +typedef LPTHREAD_START_ROUTINE THREAD_START_ROUTINE; + +#else + +typedef sem_t* SEMAPHORE; +typedef pthread_mutex_t MUTEX; +typedef pthread_t THREAD; +typedef void *(*THREAD_START_ROUTINE) (void *); + +#endif + +int mutex_init( + MUTEX* mutex); + +void mutex_destroy( + MUTEX* mutex); + +void mutex_lock( + MUTEX* mutex); + +void mutex_unlock( + MUTEX* mutex); + +int semaphore_init( + SEMAPHORE* semaphore, + int value); + +void semaphore_destroy( + SEMAPHORE* semaphore); + +void semaphore_wait( + SEMAPHORE* semaphore); + +void semaphore_release( + SEMAPHORE* semaphore); + +int create_thread( + THREAD* thread, + THREAD_START_ROUTINE start_routine, + void* param); + +void thread_join( + THREAD* thread); + +#endif diff --git a/yara-master/windows/vs2015/NuGet.Config b/yara-master/windows/vs2015/NuGet.Config new file mode 100644 index 0000000..c695e4f --- /dev/null +++ b/yara-master/windows/vs2015/NuGet.Config @@ -0,0 +1,9 @@ + + + + + + + diff --git a/yara-master/windows/vs2015/libyara/libyara.vcxproj b/yara-master/windows/vs2015/libyara/libyara.vcxproj new file mode 100644 index 0000000..6d69c23 --- /dev/null +++ b/yara-master/windows/vs2015/libyara/libyara.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {E236CE39-D8F3-4DB6-985C-F2794FF17746} + 8.1 + + + + StaticLibrary + true + v141 + + + StaticLibrary + true + v141 + + + StaticLibrary + false + v141 + + + false + v141 + StaticLibrary + + + + + + + + + + + + + + + + + + + $(ProjectName)32 + $(Configuration)\ + + + $(ProjectName)64 + $(Configuration)\ + $(Configuration)\ + + + $(ProjectName)32 + $(Configuration)\ + + + $(ProjectName)64 + $(Configuration)\ + $(Configuration)\ + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x86.1.1.0\include;..\packages\YARA.OpenSSL.x86.1.1.0\include;%(AdditionalIncludeDirectories) + 4005;4273;4090 + CompileAsCpp + $(IntDir)/%(RelativeDir) + ProgramDatabase + + MultiThreadedDLL + + + $(OutDir)$(TargetName)$(TargetExt) + crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + MachineX86 + ..\packages\YARA.OpenSSL.x86.1.1.0\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + false + + + advapi32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x64.1.1.0\include;..\packages\YARA.OpenSSL.x64.1.1.0\include;%(AdditionalIncludeDirectories) + 4005;4273;4090 + CompileAsCpp + $(IntDir)/%(RelativeDir) + ProgramDatabase + false + + MultiThreadedDLL + + + $(OutDir)$(TargetName)$(TargetExt) + crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + ..\packages\YARA.OpenSSL.x64.1.1.0\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + false + + + advapi32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x86.1.1.0\include;..\packages\YARA.OpenSSL.x86.1.1.0\include;%(AdditionalIncludeDirectories) + 4005;4273;4090 + CompileAsCpp + $(IntDir)/%(RelativeDir) + + MultiThreadedDLL + + + crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + MachineX86 + ..\packages\YARA.OpenSSL.x86.1.1.0\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + advapi32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + false + + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x64.1.1.0\include;..\packages\YARA.OpenSSL.x64.1.1.0\include;%(AdditionalIncludeDirectories) + 4005;4273;4090 + CompileAsCpp + $(IntDir)/%(RelativeDir) + false + + MultiThreadedDLL + + + crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + false + ..\packages\YARA.OpenSSL.x64.1.1.0\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + advapi32.lib;%(AdditionalDependencies) + Default + No + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/yara-master/windows/vs2015/libyara/packages.config b/yara-master/windows/vs2015/libyara/packages.config new file mode 100644 index 0000000..207005b --- /dev/null +++ b/yara-master/windows/vs2015/libyara/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/yara-master/windows/vs2015/yara.sln b/yara-master/windows/vs2015/yara.sln new file mode 100644 index 0000000..71b815a --- /dev/null +++ b/yara-master/windows/vs2015/yara.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libyara", "libyara\libyara.vcxproj", "{E236CE39-D8F3-4DB6-985C-F2794FF17746}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yara", "yara\yara.vcxproj", "{DF8232C7-D8C1-4D05-9921-F8F504134410}" + ProjectSection(ProjectDependencies) = postProject + {E236CE39-D8F3-4DB6-985C-F2794FF17746} = {E236CE39-D8F3-4DB6-985C-F2794FF17746} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yarac", "yarac\yarac.vcxproj", "{7C72350B-AA5B-41AD-8957-CE3924A7F11B}" + ProjectSection(ProjectDependencies) = postProject + {E236CE39-D8F3-4DB6-985C-F2794FF17746} = {E236CE39-D8F3-4DB6-985C-F2794FF17746} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x64.ActiveCfg = Debug|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x64.Build.0 = Debug|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x86.ActiveCfg = Debug|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x86.Build.0 = Debug|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x64.ActiveCfg = Release|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x64.Build.0 = Release|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x86.ActiveCfg = Release|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x86.Build.0 = Release|Win32 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Debug|x64.ActiveCfg = Debug|x64 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Debug|x64.Build.0 = Debug|x64 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Debug|x86.ActiveCfg = Debug|Win32 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Debug|x86.Build.0 = Debug|Win32 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Release|x64.ActiveCfg = Release|x64 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Release|x64.Build.0 = Release|x64 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Release|x86.ActiveCfg = Release|Win32 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Release|x86.Build.0 = Release|Win32 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Debug|x64.ActiveCfg = Debug|x64 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Debug|x64.Build.0 = Debug|x64 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Debug|x86.ActiveCfg = Debug|Win32 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Debug|x86.Build.0 = Debug|Win32 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Release|x64.ActiveCfg = Release|x64 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Release|x64.Build.0 = Release|x64 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Release|x86.ActiveCfg = Release|Win32 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/yara-master/windows/vs2015/yara/yara.vcxproj b/yara-master/windows/vs2015/yara/yara.vcxproj new file mode 100644 index 0000000..d138ee8 --- /dev/null +++ b/yara-master/windows/vs2015/yara/yara.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {DF8232C7-D8C1-4D05-9921-F8F504134410} + Win32Proj + yara + + + + Application + true + MultiByte + v140 + + + Application + true + MultiByte + true + v140 + + + Application + false + true + MultiByte + v140 + + + Application + false + true + MultiByte + v140 + + + + + + + + + + + + + + + + + + + false + $(ProjectName)32 + + + $(ProjectName)64 + $(SolutionDir)\$(Configuration)\ + $(Configuration)\ + + + false + $(ProjectName)32 + + + false + $(ProjectName)64 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + + Level3 + NotUsing + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..;%(AdditionalIncludeDirectories) + false + CompileAsCpp + ProgramDatabase + MultiThreadedDLL + + + Console + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + + + + + Level3 + NotUsing + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..;%(AdditionalIncludeDirectories) + false + CompileAsCpp + ProgramDatabase + MultiThreadedDLL + + + Console + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + Default + + + + + Level3 + NotUsing + MaxSpeed + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..;%(AdditionalIncludeDirectories) + CompileAsCpp + ProgramDatabase + MultiThreadedDLL + + + Console + true + true + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + No + + + false + + + + + Level3 + NotUsing + MaxSpeed + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..;%(AdditionalIncludeDirectories) + CompileAsCpp + ProgramDatabase + MultiThreadedDLL + + + Console + true + true + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + No + + + + + + + + + + \ No newline at end of file diff --git a/yara-master/windows/vs2015/yarac/yarac.vcxproj b/yara-master/windows/vs2015/yarac/yarac.vcxproj new file mode 100644 index 0000000..9e95924 --- /dev/null +++ b/yara-master/windows/vs2015/yarac/yarac.vcxproj @@ -0,0 +1,178 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7C72350B-AA5B-41AD-8957-CE3924A7F11B} + Win32Proj + yarac + + + + Application + true + Unicode + v140 + + + Application + true + Unicode + v140 + + + Application + false + true + Unicode + v140 + + + Application + false + true + Unicode + v140 + + + + + + + + + + + + + + + + + + + false + $(ProjectName)32 + + + false + $(ProjectName)64 + $(SolutionDir)\$(Configuration)\ + $(Configuration)\ + + + false + $(ProjectName)32 + + + false + $(ProjectName)64 + $(SolutionDir)\$(Configuration)\ + $(Configuration)\ + + + + Level3 + NotUsing + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..;%(AdditionalIncludeDirectories) + false + CompileAsCpp + ProgramDatabase + MultiThreadedDLL + + + Console + true + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + + + + + Level3 + NotUsing + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..;%(AdditionalIncludeDirectories) + CompileAsCpp + ProgramDatabase + MultiThreadedDLL + + + Console + true + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + + + + + Level3 + NotUsing + MaxSpeed + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..;%(AdditionalIncludeDirectories) + CompileAsCpp + ProgramDatabase + MultiThreadedDLL + + + Console + No + true + true + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + false + + + + + Level3 + NotUsing + MaxSpeed + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..;%(AdditionalIncludeDirectories) + CompileAsCpp + ProgramDatabase + MultiThreadedDLL + + + Console + No + true + true + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + false + + + + + + + + + \ No newline at end of file diff --git a/yara-master/yara.c b/yara-master/yara.c new file mode 100644 index 0000000..ff5aba9 --- /dev/null +++ b/yara-master/yara.c @@ -0,0 +1,1266 @@ +/* +Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#if !defined(_WIN32) && !defined(__CYGWIN__) + +#include +#include +#include +#include + +#else + +#include + +#define PRIx64 "I64x" +#define PRId64 "I64d" + +#endif + +#include +#include +#include +#include +#include + +#include + +#include "args.h" +#include "common.h" +#include "threading.h" + + +#define ERROR_COULD_NOT_CREATE_THREAD 100 + +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif + +#ifndef min +#define min(x, y) ((x < y) ? (x) : (y)) +#endif + +#ifdef _MSC_VER +#define snprintf _snprintf +#define strdup _strdup +#endif + +#define MAX_QUEUED_FILES 64 + + +typedef struct _MODULE_DATA +{ + const char* module_name; + YR_MAPPED_FILE mapped_file; + struct _MODULE_DATA* next; + +} MODULE_DATA; + + +typedef struct _CALLBACK_ARGS +{ + const char* file_path; + int current_count; + +} CALLBACK_ARGS; + + +typedef struct _THREAD_ARGS +{ + YR_SCANNER* scanner; + CALLBACK_ARGS callback_args; + time_t start_time; + int current_count; + +} THREAD_ARGS; + + +typedef struct _QUEUED_FILE +{ + char* path; + +} QUEUED_FILE; + + +typedef struct COMPILER_RESULTS +{ + int errors; + int warnings; + +} COMPILER_RESULTS; + + +#define MAX_ARGS_TAG 32 +#define MAX_ARGS_IDENTIFIER 32 +#define MAX_ARGS_EXT_VAR 32 +#define MAX_ARGS_MODULE_DATA 32 + +static char* tags[MAX_ARGS_TAG + 1]; +static char* identifiers[MAX_ARGS_IDENTIFIER + 1]; +static char* ext_vars[MAX_ARGS_EXT_VAR + 1]; +static char* modules_data[MAX_ARGS_EXT_VAR + 1]; + +static int recursive_search = FALSE; +static int show_module_data = FALSE; +static int show_tags = FALSE; +static int show_strings = FALSE; +static int show_string_length = FALSE; +static int show_meta = FALSE; +static int show_namespace = FALSE; +static int show_version = FALSE; +static int show_help = FALSE; +static int ignore_warnings = FALSE; +static int fast_scan = FALSE; +static int negate = FALSE; +static int print_count_only = FALSE; +static int total_count = 0; +static int limit = 0; +static int timeout = 1000000; +static int stack_size = DEFAULT_STACK_SIZE; +static int threads = MAX_THREADS; +static int fail_on_warnings = FALSE; +static int max_strings_per_rule = DEFAULT_MAX_STRINGS_PER_RULE; + + +#define USAGE_STRING \ + "Usage: yara [OPTION]... [NAMESPACE:]RULES_FILE... FILE | DIR | PID" + + +args_option_t options[] = +{ + OPT_STRING_MULTI('t', "tag", &tags, MAX_ARGS_TAG, + "print only rules tagged as TAG", "TAG"), + + OPT_STRING_MULTI('i', "identifier", &identifiers, MAX_ARGS_IDENTIFIER, + "print only rules named IDENTIFIER", "IDENTIFIER"), + + OPT_BOOLEAN('c', "count", &print_count_only, + "print only number of matches"), + + OPT_BOOLEAN('n', "negate", &negate, + "print only not satisfied rules (negate)", NULL), + + OPT_BOOLEAN('D', "print-module-data", &show_module_data, + "print module data"), + + OPT_BOOLEAN('g', "print-tags", &show_tags, + "print tags"), + + OPT_BOOLEAN('m', "print-meta", &show_meta, + "print metadata"), + + OPT_BOOLEAN('s', "print-strings", &show_strings, + "print matching strings"), + + OPT_BOOLEAN('L', "print-string-length", &show_string_length, + "print length of matched strings"), + + OPT_BOOLEAN('e', "print-namespace", &show_namespace, + "print rules' namespace"), + + OPT_INTEGER('p', "threads", &threads, + "use the specified NUMBER of threads to scan a directory", "NUMBER"), + + OPT_INTEGER('l', "max-rules", &limit, + "abort scanning after matching a NUMBER of rules", "NUMBER"), + + OPT_STRING_MULTI('d', NULL, &ext_vars, MAX_ARGS_EXT_VAR, + "define external variable", "VAR=VALUE"), + + OPT_STRING_MULTI('x', NULL, &modules_data, MAX_ARGS_MODULE_DATA, + "pass FILE's content as extra data to MODULE", "MODULE=FILE"), + + OPT_INTEGER('a', "timeout", &timeout, + "abort scanning after the given number of SECONDS", "SECONDS"), + + OPT_INTEGER('k', "stack-size", &stack_size, + "set maximum stack size (default=16384)", "SLOTS"), + + OPT_INTEGER(0, "max-strings-per-rule", &max_strings_per_rule, + "set maximum number of strings per rule (default=10000)", "NUMBER"), + + OPT_BOOLEAN('r', "recursive", &recursive_search, + "recursively search directories"), + + OPT_BOOLEAN('f', "fast-scan", &fast_scan, + "fast matching mode"), + + OPT_BOOLEAN('w', "no-warnings", &ignore_warnings, + "disable warnings"), + + OPT_BOOLEAN(0, "fail-on-warnings", &fail_on_warnings, + "fail on warnings"), + + OPT_BOOLEAN('v', "version", &show_version, + "show version information"), + + OPT_BOOLEAN('h', "help", &show_help, + "show this help and exit"), + + OPT_END() +}; + + +// file_queue is size-limited queue stored as a circular array, files are +// removed from queue_head position and new files are added at queue_tail +// position. The array has room for one extra element to avoid queue_head +// being equal to queue_tail in a full queue. The only situation where +// queue_head == queue_tail is when queue is empty. + +QUEUED_FILE file_queue[MAX_QUEUED_FILES + 1]; + +int queue_head; +int queue_tail; + +SEMAPHORE used_slots; +SEMAPHORE unused_slots; + +MUTEX queue_mutex; +MUTEX output_mutex; + +MODULE_DATA* modules_data_list = NULL; + + +static int file_queue_init() +{ + int result; + + queue_tail = 0; + queue_head = 0; + + result = mutex_init(&queue_mutex); + + if (result != 0) + return result; + + result = semaphore_init(&used_slots, 0); + + if (result != 0) + return result; + + return semaphore_init(&unused_slots, MAX_QUEUED_FILES); +} + + +static void file_queue_destroy() +{ + mutex_destroy(&queue_mutex); + semaphore_destroy(&unused_slots); + semaphore_destroy(&used_slots); +} + + +static void file_queue_finish() +{ + int i; + + for (i = 0; i < MAX_THREADS; i++) + semaphore_release(&used_slots); +} + + +static void file_queue_put( + const char* file_path) +{ + semaphore_wait(&unused_slots); + mutex_lock(&queue_mutex); + + file_queue[queue_tail].path = strdup(file_path); + queue_tail = (queue_tail + 1) % (MAX_QUEUED_FILES + 1); + + mutex_unlock(&queue_mutex); + semaphore_release(&used_slots); +} + + +static char* file_queue_get() +{ + char* result; + + semaphore_wait(&used_slots); + mutex_lock(&queue_mutex); + + if (queue_head == queue_tail) // queue is empty + { + result = NULL; + } + else + { + result = file_queue[queue_head].path; + queue_head = (queue_head + 1) % (MAX_QUEUED_FILES + 1); + } + + mutex_unlock(&queue_mutex); + semaphore_release(&unused_slots); + + return result; +} + + +#if defined(_WIN32) || defined(__CYGWIN__) + +static int is_directory( + const char* path) +{ + DWORD attributes = GetFileAttributes(path); + + if (attributes != INVALID_FILE_ATTRIBUTES && + attributes & FILE_ATTRIBUTE_DIRECTORY) + return TRUE; + else + return FALSE; +} + +static void scan_dir( + const char* dir, + int recursive, + time_t start_time) +{ + static char path_and_mask[MAX_PATH]; + + snprintf(path_and_mask, sizeof(path_and_mask), "%s\\*", dir); + + WIN32_FIND_DATA FindFileData; + HANDLE hFind = FindFirstFile(path_and_mask, &FindFileData); + + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + char full_path[MAX_PATH]; + + snprintf(full_path, sizeof(full_path), "%s\\%s", + dir, FindFileData.cFileName); + + if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + file_queue_put(full_path); + } + else if (recursive && + strcmp(FindFileData.cFileName, ".") != 0 && + strcmp(FindFileData.cFileName, "..") != 0) + { + scan_dir(full_path, recursive, start_time); + } + + } while (FindNextFile(hFind, &FindFileData)); + + FindClose(hFind); + } +} + +#else + +static int is_directory( + const char* path) +{ + struct stat st; + + if (stat(path,&st) == 0) + return S_ISDIR(st.st_mode); + + return 0; +} + + +static void scan_dir( + const char* dir, + int recursive, + time_t start_time) +{ + DIR* dp = opendir(dir); + + if (dp) + { + struct dirent* de = readdir(dp); + + while (de && difftime(time(NULL), start_time) < timeout) + { + char full_path[MAX_PATH]; + struct stat st; + + snprintf(full_path, sizeof(full_path), "%s/%s", dir, de->d_name); + + int err = lstat(full_path, &st); + + if (err == 0) + { + if(S_ISREG(st.st_mode)) + { + file_queue_put(full_path); + } + else if(recursive && + S_ISDIR(st.st_mode) && + !S_ISLNK(st.st_mode) && + strcmp(de->d_name, ".") != 0 && + strcmp(de->d_name, "..") != 0) + { + scan_dir(full_path, recursive, start_time); + } + } + + de = readdir(dp); + } + + closedir(dp); + } +} + +#endif + +static void print_string( + const uint8_t* data, + int length) +{ + for (int i = 0; i < length; i++) + { + if (data[i] >= 32 && data[i] <= 126) + printf("%c", data[i]); + else + printf("\\x%02X", data[i]); + } + + printf("\n"); +} + + +static char cescapes[] = +{ + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 'a', + 'b', 't', 'n', 'v', 'f', 'r', 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +}; + + +static void print_escaped( + const uint8_t* data, + size_t length) +{ + size_t i; + + for (i = 0; i < length; i++) + { + switch (data[i]) + { + case '\"': + case '\'': + case '\\': + printf("\\%c", data[i]); + break; + + default: + if (data[i] >= 127) + printf("\\%03o", data[i]); + else if (data[i] >= 32) + putchar(data[i]); + else if (cescapes[data[i]] != 0) + printf("\\%c", cescapes[data[i]]); + else + printf("\\%03o", data[i]); + } + } +} + + +static void print_hex_string( + const uint8_t* data, + int length) +{ + for (int i = 0; i < min(32, length); i++) + printf("%s%02X", (i == 0 ? "" : " "), data[i]); + + puts(length > 32 ? " ..." : ""); +} + + +static void print_error( + int error) +{ + switch (error) + { + case ERROR_SUCCESS: + break; + case ERROR_COULD_NOT_ATTACH_TO_PROCESS: + fprintf(stderr, "can not attach to process (try running as root)\n"); + break; + case ERROR_INSUFFICIENT_MEMORY: + fprintf(stderr, "not enough memory\n"); + break; + case ERROR_SCAN_TIMEOUT: + fprintf(stderr, "scanning timed out\n"); + break; + case ERROR_COULD_NOT_OPEN_FILE: + fprintf(stderr, "could not open file\n"); + break; + case ERROR_UNSUPPORTED_FILE_VERSION: + fprintf(stderr, "rules were compiled with a newer version of YARA\n"); + break; + case ERROR_CORRUPT_FILE: + fprintf(stderr, "corrupt compiled rules file.\n"); + break; + case ERROR_EXEC_STACK_OVERFLOW: + fprintf(stderr, "stack overflow while evaluating condition " + "(see --stack-size argument) \n"); + break; + case ERROR_INVALID_EXTERNAL_VARIABLE_TYPE: + fprintf(stderr, "invalid type for external variable\n"); + break; + case ERROR_TOO_MANY_MATCHES: + fprintf(stderr, "too many matches\n"); + break; + default: + fprintf(stderr, "internal error: %d\n", error); + break; + } +} + +static void print_scanner_error( + YR_SCANNER* scanner, + int error) +{ + YR_RULE* rule = yr_scanner_last_error_rule(scanner); + YR_STRING* string = yr_scanner_last_error_string(scanner); + + if (rule != NULL && string != NULL) + { + fprintf( + stderr, + "string \"%s\" in rule \"%s\" caused ", + string->identifier, + rule->identifier); + } + else if (rule != NULL) + { + fprintf( + stderr, + "rule \"%s\" caused ", + rule->identifier); + } + + print_error(error); +} + + +static void print_compiler_error( + int error_level, + const char* file_name, + int line_number, + const char* message, + void* user_data) +{ + if (error_level == YARA_ERROR_LEVEL_ERROR) + { + fprintf(stderr, "%s(%d): error: %s\n", file_name, line_number, message); + } + else if (!ignore_warnings) + { + COMPILER_RESULTS* compiler_results = (COMPILER_RESULTS*) user_data; + compiler_results->warnings++; + + fprintf(stderr, "%s(%d): warning: %s\n", file_name, line_number, message); + } +} + + +static int handle_message( + int message, + YR_RULE* rule, + void* data) +{ + const char* tag; + int show = TRUE; + + if (tags[0] != NULL) + { + // The user specified one or more -t arguments, let's show this rule + // only if it's tagged with some of the specified tags. + + show = FALSE; + + for (int i = 0; !show && tags[i] != NULL; i++) + { + yr_rule_tags_foreach(rule, tag) + { + if (strcmp(tag, tags[i]) == 0) + { + show = TRUE; + break; + } + } + } + } + + if (identifiers[0] != NULL) + { + // The user specified one or more -i arguments, let's show + // this rule only if it's identifier is among of the provided ones. + + show = FALSE; + + for (int i = 0; !show && identifiers[i] != NULL; i++) + { + if (strcmp(identifiers[i], rule->identifier) == 0) + { + show = TRUE; + break; + } + } + } + + int is_matching = (message == CALLBACK_MSG_RULE_MATCHING); + + show = show && ((!negate && is_matching) || (negate && !is_matching)); + + if (show && !print_count_only) + { + mutex_lock(&output_mutex); + + if (show_namespace) + printf("%s:", rule->ns->name); + + printf("%s ", rule->identifier); + + if (show_tags) + { + printf("["); + + yr_rule_tags_foreach(rule, tag) + { + // print a comma except for the first tag + if (tag != rule->tags) + printf(","); + + printf("%s", tag); + } + + printf("] "); + } + + // Show meta-data. + + if (show_meta) + { + YR_META* meta; + + printf("["); + + yr_rule_metas_foreach(rule, meta) + { + if (meta != rule->metas) + printf(","); + + if (meta->type == META_TYPE_INTEGER) + { + printf("%s=%" PRId64, meta->identifier, meta->integer); + } + else if (meta->type == META_TYPE_BOOLEAN) + { + printf("%s=%s", meta->identifier, meta->integer ? "true" : "false"); + } + else + { + printf("%s=\"", meta->identifier); + print_escaped((uint8_t*) (meta->string), strlen(meta->string)); + putchar('"'); + } + } + + printf("] "); + } + + printf("%s\n", ((CALLBACK_ARGS*) data)->file_path); + + // Show matched strings. + + if (show_strings || show_string_length) + { + YR_STRING* string; + + yr_rule_strings_foreach(rule, string) + { + YR_MATCH* match; + + yr_string_matches_foreach(string, match) + { + if (show_string_length) + printf("0x%" PRIx64 ":%d:%s", + match->base + match->offset, + match->data_length, + string->identifier); + else + printf("0x%" PRIx64 ":%s", + match->base + match->offset, + string->identifier); + + if (show_strings) + { + printf(": "); + + if (STRING_IS_HEX(string)) + print_hex_string(match->data, match->data_length); + else + print_string(match->data, match->data_length); + } + else + { + printf("\n"); + } + } + } + } + + mutex_unlock(&output_mutex); + } + + if (is_matching) + { + ((CALLBACK_ARGS*) data)->current_count++; + total_count++; + } + + if (limit != 0 && total_count >= limit) + return CALLBACK_ABORT; + + return CALLBACK_CONTINUE; +} + + +static int callback( + int message, + void* message_data, + void* user_data) +{ + YR_MODULE_IMPORT* mi; + YR_OBJECT* object; + MODULE_DATA* module_data; + + switch(message) + { + case CALLBACK_MSG_RULE_MATCHING: + case CALLBACK_MSG_RULE_NOT_MATCHING: + return handle_message(message, (YR_RULE*) message_data, user_data); + + case CALLBACK_MSG_IMPORT_MODULE: + + mi = (YR_MODULE_IMPORT*) message_data; + module_data = modules_data_list; + + while (module_data != NULL) + { + if (strcmp(module_data->module_name, mi->module_name) == 0) + { + mi->module_data = (void*) module_data->mapped_file.data; + mi->module_data_size = module_data->mapped_file.size; + break; + } + + module_data = module_data->next; + } + + return CALLBACK_CONTINUE; + + case CALLBACK_MSG_MODULE_IMPORTED: + + if (show_module_data) + { + object = (YR_OBJECT*) message_data; + + mutex_lock(&output_mutex); + + yr_object_print_data(object, 0, 1); + printf("\n"); + + mutex_unlock(&output_mutex); + } + + return CALLBACK_CONTINUE; + } + + return CALLBACK_ERROR; +} + + +#if defined(_WIN32) || defined(__CYGWIN__) +static DWORD WINAPI scanning_thread(LPVOID param) +#else +static void* scanning_thread(void* param) +#endif +{ + int result = ERROR_SUCCESS; + THREAD_ARGS* args = (THREAD_ARGS*) param; + char* file_path = file_queue_get(); + + while (file_path != NULL) + { + args->callback_args.current_count = 0; + args->callback_args.file_path = file_path; + + int elapsed_time = (int) difftime(time(NULL), args->start_time); + + if (elapsed_time < timeout) + { + yr_scanner_set_timeout(args->scanner, timeout - elapsed_time); + + result = yr_scanner_scan_file(args->scanner, file_path); + + if (print_count_only) + { + mutex_lock(&output_mutex); + printf("%s: %d\n", file_path, args->callback_args.current_count); + mutex_unlock(&output_mutex); + } + + if (result != ERROR_SUCCESS) + { + mutex_lock(&output_mutex); + fprintf(stderr, "error scanning %s: ", file_path); + print_scanner_error(args->scanner, result); + mutex_unlock(&output_mutex); + } + + free(file_path); + file_path = file_queue_get(); + } + else + { + file_path = NULL; + } + } + + return 0; +} + + +static int define_external_variables( + YR_RULES* rules, + YR_COMPILER* compiler) +{ + int result = ERROR_SUCCESS; + + for (int i = 0; ext_vars[i] != NULL; i++) + { + char* equal_sign = strchr(ext_vars[i], '='); + + if (!equal_sign) + { + fprintf(stderr, "error: wrong syntax for `-d` option.\n"); + return ERROR_SUCCESS; + } + + // Replace the equal sign with null character to split the external + // variable definition (i.e: myvar=somevalue) in two strings: identifier + // and value. + + *equal_sign = '\0'; + + char* identifier = ext_vars[i]; + char* value = equal_sign + 1; + + if (is_float(value)) + { + if (rules != NULL) + result = yr_rules_define_float_variable( + rules, + identifier, + atof(value)); + + if (compiler != NULL) + result = yr_compiler_define_float_variable( + compiler, + identifier, + atof(value)); + } + else if (is_integer(value)) + { + if (rules != NULL) + result = yr_rules_define_integer_variable( + rules, + identifier, + atoi(value)); + + if (compiler != NULL) + result = yr_compiler_define_integer_variable( + compiler, + identifier, + atoi(value)); + } + else if (strcmp(value, "true") == 0 || strcmp(value, "false") == 0) + { + if (rules != NULL) + result = yr_rules_define_boolean_variable( + rules, + identifier, + strcmp(value, "true") == 0); + + if (compiler != NULL) + result = yr_compiler_define_boolean_variable( + compiler, + identifier, + strcmp(value, "true") == 0); + } + else + { + if (rules != NULL) + result = yr_rules_define_string_variable( + rules, + identifier, + value); + + if (compiler != NULL) + result = yr_compiler_define_string_variable( + compiler, + identifier, + value); + } + } + + return result; +} + + +static int load_modules_data() +{ + for (int i = 0; modules_data[i] != NULL; i++) + { + char* equal_sign = strchr(modules_data[i], '='); + + if (!equal_sign) + { + fprintf(stderr, "error: wrong syntax for `-x` option.\n"); + return FALSE; + } + + *equal_sign = '\0'; + + MODULE_DATA* module_data = (MODULE_DATA*) malloc(sizeof(MODULE_DATA)); + + if (module_data != NULL) + { + module_data->module_name = modules_data[i]; + + int result = yr_filemap_map(equal_sign + 1, &module_data->mapped_file); + + if (result != ERROR_SUCCESS) + { + free(module_data); + fprintf(stderr, "error: could not open file \"%s\".\n", equal_sign + 1); + return FALSE; + } + + module_data->next = modules_data_list; + modules_data_list = module_data; + } + } + + return TRUE; +} + + +static void unload_modules_data() +{ + MODULE_DATA* module_data = modules_data_list; + + while(module_data != NULL) + { + MODULE_DATA* next_module_data = module_data->next; + + yr_filemap_unmap(&module_data->mapped_file); + free(module_data); + + module_data = next_module_data; + } + + modules_data_list = NULL; +} + + +int main( + int argc, + const char** argv) +{ + COMPILER_RESULTS cr; + + YR_COMPILER* compiler = NULL; + YR_RULES* rules = NULL; + YR_SCANNER* scanner = NULL; + + int flags = 0; + int result, i; + + argc = args_parse(options, argc, argv); + + if (show_version) + { + printf("%s\n", YR_VERSION); + return EXIT_SUCCESS; + } + + if (show_help) + { + printf( + "YARA %s, the pattern matching swiss army knife.\n" + "%s\n\n" + "Mandatory arguments to long options are mandatory for " + "short options too.\n\n", YR_VERSION, USAGE_STRING); + + args_print_usage(options, 40); + printf("\nSend bug reports and suggestions to: vmalvarez@virustotal.com.\n"); + + return EXIT_SUCCESS; + } + + if (threads > MAX_THREADS) + { + fprintf(stderr, "maximum number of threads is %d\n", MAX_THREADS); + return EXIT_FAILURE; + } + + if (argc < 2) + { + // After parsing the command-line options we expect two additional + // arguments, the rules file and the target file, directory or pid to + // be scanned. + + fprintf(stderr, "yara: wrong number of arguments\n"); + fprintf(stderr, "%s\n\n", USAGE_STRING); + fprintf(stderr, "Try `--help` for more options\n"); + + return EXIT_FAILURE; + } + + if (!load_modules_data()) + exit_with_code(EXIT_FAILURE); + + result = yr_initialize(); + + if (result != ERROR_SUCCESS) + { + fprintf(stderr, "error: initialization error (%d)\n", result); + exit_with_code(EXIT_FAILURE); + } + + yr_set_configuration(YR_CONFIG_STACK_SIZE, &stack_size); + yr_set_configuration(YR_CONFIG_MAX_STRINGS_PER_RULE, &max_strings_per_rule); + + // Try to load the rules file as a binary file containing + // compiled rules first + + result = yr_rules_load(argv[0], &rules); + + // Accepted result are ERROR_SUCCESS or ERROR_INVALID_FILE + // if we are passing the rules in source form, if result is + // different from those exit with error. + + if (result != ERROR_SUCCESS && + result != ERROR_COULD_NOT_OPEN_FILE && + result != ERROR_INVALID_FILE) + { + print_error(result); + exit_with_code(EXIT_FAILURE); + } + + if (result == ERROR_SUCCESS) + { + // When a binary file containing compiled rules is provided, yara accepts + // only two arguments, the compiled rules file and the target to be scanned. + + if (argc != 2) + { + fprintf(stderr, + "error: can't accept multiple rules files if one of them is in " + "compiled form.\n"); + exit_with_code(EXIT_FAILURE); + } + + result = define_external_variables(rules, NULL); + + if (result != ERROR_SUCCESS) + { + print_error(result); + exit_with_code(EXIT_FAILURE); + } + } + else + { + // Rules file didn't contain compiled rules, let's handle it + // as a text file containing rules in source form. + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + exit_with_code(EXIT_FAILURE); + + result = define_external_variables(NULL, compiler); + + if (result != ERROR_SUCCESS) + { + print_error(result); + exit_with_code(EXIT_FAILURE); + } + + cr.errors = 0; + cr.warnings = 0; + + yr_compiler_set_callback(compiler, print_compiler_error, &cr); + + if (!compile_files(compiler, argc, argv)) + exit_with_code(EXIT_FAILURE); + + if (cr.errors > 0) + exit_with_code(EXIT_FAILURE); + + if (fail_on_warnings && cr.warnings > 0) + exit_with_code(EXIT_FAILURE); + + result = yr_compiler_get_rules(compiler, &rules); + + yr_compiler_destroy(compiler); + + compiler = NULL; + + if (result != ERROR_SUCCESS) + { + fprintf(stderr, "error: %d\n", result); + exit_with_code(EXIT_FAILURE); + } + } + + mutex_init(&output_mutex); + + if (fast_scan) + flags |= SCAN_FLAGS_FAST_MODE; + + if (is_directory(argv[argc - 1])) + { + if (file_queue_init() != 0) + { + print_error(ERROR_INTERNAL_FATAL_ERROR); + exit_with_code(EXIT_FAILURE); + } + + THREAD thread[MAX_THREADS]; + THREAD_ARGS thread_args[MAX_THREADS]; + + time_t start_time = time(NULL); + + for (i = 0; i < threads; i++) + { + thread_args[i].start_time = start_time; + thread_args[i].current_count = 0; + + result = yr_scanner_create(rules, &thread_args[i].scanner); + + if (result != ERROR_SUCCESS) + { + print_error(result); + exit_with_code(EXIT_FAILURE); + } + + yr_scanner_set_callback( + thread_args[i].scanner, + callback, + &thread_args[i].callback_args); + + yr_scanner_set_flags(thread_args[i].scanner, flags); + + if (create_thread(&thread[i], scanning_thread, (void*) &thread_args[i])) + { + print_error(ERROR_COULD_NOT_CREATE_THREAD); + exit_with_code(EXIT_FAILURE); + } + } + + scan_dir(argv[argc - 1], recursive_search, start_time); + + file_queue_finish(); + + // Wait for scan threads to finish + for (i = 0; i < threads; i++) + thread_join(&thread[i]); + + for (i = 0; i < threads; i++) + yr_scanner_destroy(thread_args[i].scanner); + + file_queue_destroy(); + } + else + { + CALLBACK_ARGS user_data = { argv[argc - 1], 0 }; + + result = yr_scanner_create(rules, &scanner); + + if (result != ERROR_SUCCESS) + { + fprintf(stderr, "error: %d\n", result); + exit_with_code(EXIT_FAILURE); + } + + yr_scanner_set_callback(scanner, callback, &user_data); + yr_scanner_set_flags(scanner, flags); + yr_scanner_set_timeout(scanner, timeout); + + if (is_integer(argv[argc - 1])) + result = yr_scanner_scan_proc(scanner, atoi(argv[argc - 1])); + else + result = yr_scanner_scan_file(scanner, argv[argc - 1]); + + if (result != ERROR_SUCCESS) + { + fprintf(stderr, "error scanning %s: ", argv[argc - 1]); + print_scanner_error(scanner, result); + exit_with_code(EXIT_FAILURE); + } + + if (print_count_only) + printf("%d\n", user_data.current_count); + } + + result = EXIT_SUCCESS; + +_exit: + + #ifdef PROFILING_ENABLED + if (rules != NULL) + yr_rules_print_profiling_info(rules); + #endif + + unload_modules_data(); + + if (scanner != NULL) + yr_scanner_destroy(scanner); + + if (compiler != NULL) + yr_compiler_destroy(compiler); + + if (rules != NULL) + yr_rules_destroy(rules); + + yr_finalize(); + + return result; +} diff --git a/yara-master/yara.man b/yara-master/yara.man new file mode 100644 index 0000000..ea5d9d4 --- /dev/null +++ b/yara-master/yara.man @@ -0,0 +1,145 @@ +.TH yara 1 "September 22, 2008" "Victor M. Alvarez" +.SH NAME +yara \- find files matching patterns and rules written in a special-purpose +language. +.SH SYNOPSIS +.B yara +[OPTION]... RULES_FILE FILE | DIR | PID +.SH DESCRIPTION +yara scans the given FILE, all files contained in directory DIR, or the process +identified by PID looking for matches of patterns and rules provided in a +special purpose-language. The rules are read from RULES_FILE. +.PP +The options to +.IR yara (1) +are: +.TP +.BI \-t " tag" " --tag=" tag +Print rules tagged as +.I tag +and ignore the rest. This option can be used multiple times. +.TP +.BI \-i " identifier" " --identifier=" identifier +Print rules named +.I identifier +and ignore the rest. This option can be used multiple times. +.TP +.B \-c " --count" +Print number of matches only. +.TP +.B \-n " --negate" +Print rules that doesn't apply (negate). +.TP +.B \-D " --print-module-data" +Print module data. +.TP +.B \-g " --print-tags" +Print the tags associated to the rule. +.TP +.B \-m " --print-meta" +Print metadata associated to the rule. +.TP +.B \-s " --print-strings" +Print strings found in the file. +.TP +.B \-L " --print-string-length" +Print length of strings found in the file. +.TP +.BI \-p " number" " --threads=" number +Use the specified +.I number +of threads to scan a directory. +.TP +.BI \-l " number" " --max-rules=" number +Abort scanning after a +.I number +of rules matched. +.TP +.BI \-a " seconds" " --timeout=" seconds +Abort scanning after a number of +.I seconds +has elapsed. +.TP +.BI \-k " slots" " --stack-size=" slots +Set maximum stack size to the specified number of +.I slots. +.TP +.BI \-d " identifier"=value +Define an external variable. This option can be used multiple times. +.TP +.BI \-x " module"=file +Pass file's content as extra data to module. This option can be used multiple +times. +.TP +.B \-r " --recursive" +Scan files in directories recursively. +.TP +.B \-f " --fast-scan" +Speeds up scanning by searching only for the first occurrence of each pattern. +.TP +.B \-w " --no-warnings" +Disable warnings. +.TP +.B " --fail-on-warnings" +Treat warnings as errors. Has no effect if used with +.B --no-warnings. +.TP +.BI " --max-strings-per-rule=" number +Set maximum number of strings per rule (default=10000) +.TP +.B \-v " --version" +Show version information. +.SH EXAMPLES +$ yara /foo/bar/rules . +.RS +.PP +Apply rules on +.I /foo/bar/rules +to all files on current directory. Subdirectories are not scanned. +.RE +.PP +$ yara -t Packer -t Compiler /foo/bar/rules bazfile +.RS +.PP +Apply rules on +.I /foo/bar/rules +to +.I bazfile. +Only reports rules tagged as +.I Packer +or +.I Compiler. +.RE +.PP +$ cat /foo/bar/rules | yara -r /foo +.RS +.PP +Scan all files in the +.I /foo +directory and its subdirectories. Rules are read from standard input. +.RE +.PP +$ yara -d mybool=true -d myint=5 -d mystring="my string" /foo/bar/rules bazfile +.RS +.PP +Defines three external variables +.I mybool +.I myint +and +.I mystring. +.RE +.PP +$ yara -x cuckoo=cuckoo_json_report /foo/bar/rules bazfile +.RS +.PP +Apply rules on +.I /foo/bar/rules +to +.I bazfile +while passing the content of +.I cuckoo_json_report +to the cuckoo module. +.RE + +.SH AUTHOR +Victor M. Alvarez ; diff --git a/yara-master/yarac.c b/yara-master/yarac.c new file mode 100644 index 0000000..a7a83bd --- /dev/null +++ b/yara-master/yarac.c @@ -0,0 +1,273 @@ +/* +Copyright (c) 2013. The YARA Authors. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. +*/ + +#ifndef _WIN32 + +#include +#include +#include +#include + +#else + +#include + +#endif + +#include +#include +#include +#include +#include + +#include "args.h" +#include "common.h" + + +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif + +#define MAX_ARGS_EXT_VAR 32 + + +typedef struct COMPILER_RESULTS +{ + int errors; + int warnings; + +} COMPILER_RESULTS; + + +static char* ext_vars[MAX_ARGS_EXT_VAR + 1]; +static int ignore_warnings = FALSE; +static int show_version = FALSE; +static int show_help = FALSE; +static int fail_on_warnings = FALSE; +static int max_strings_per_rule = DEFAULT_MAX_STRINGS_PER_RULE; + + +#define USAGE_STRING \ + "Usage: yarac [OPTION]... [NAMESPACE:]SOURCE_FILE... OUTPUT_FILE" + +args_option_t options[] = +{ + OPT_STRING_MULTI('d', NULL, &ext_vars, MAX_ARGS_EXT_VAR, + "define external variable", "VAR=VALUE"), + + OPT_BOOLEAN('w', "no-warnings", &ignore_warnings, + "disable warnings"), + + OPT_BOOLEAN(0, "fail-on-warnings", &fail_on_warnings, + "fail on warnings"), + + OPT_INTEGER(0, "max-strings-per-rule", &max_strings_per_rule, + "set maximum number of strings per rule (default=10000)", "NUMBER"), + + OPT_BOOLEAN('v', "version", &show_version, + "show version information"), + + OPT_BOOLEAN('h', "help", &show_help, + "show this help and exit"), + + OPT_END() +}; + + +static void report_error( + int error_level, + const char* file_name, + int line_number, + const char* message, + void* user_data) +{ + if (error_level == YARA_ERROR_LEVEL_ERROR) + { + fprintf(stderr, "%s(%d): error: %s\n", file_name, line_number, message); + } + else if (!ignore_warnings) + { + COMPILER_RESULTS* compiler_results = (COMPILER_RESULTS*) user_data; + compiler_results->warnings++; + + fprintf(stderr, "%s(%d): warning: %s\n", file_name, line_number, message); + } +} + + +static int define_external_variables( + YR_COMPILER* compiler) +{ + for (int i = 0; ext_vars[i] != NULL; i++) + { + char* equal_sign = strchr(ext_vars[i], '='); + + if (!equal_sign) + { + fprintf(stderr, "error: wrong syntax for `-d` option.\n"); + return FALSE; + } + + // Replace the equal sign with null character to split the external + // variable definition (i.e: myvar=somevalue) in two strings: identifier + // and value. + + *equal_sign = '\0'; + + char* identifier = ext_vars[i]; + char* value = equal_sign + 1; + + if (is_float(value)) + { + yr_compiler_define_float_variable( + compiler, + identifier, + atof(value)); + } + else if (is_integer(value)) + { + yr_compiler_define_integer_variable( + compiler, + identifier, + atoi(value)); + } + else if (strcmp(value, "true") == 0 || strcmp(value, "false") == 0) + { + yr_compiler_define_boolean_variable( + compiler, + identifier, + strcmp(value, "true") == 0); + } + else + { + yr_compiler_define_string_variable( + compiler, + identifier, + value); + } + } + + return TRUE; +} + + +int main( + int argc, + const char** argv) +{ + COMPILER_RESULTS cr; + + YR_COMPILER* compiler = NULL; + YR_RULES* rules = NULL; + + int result; + + argc = args_parse(options, argc, argv); + + if (show_version) + { + printf("%s\n", YR_VERSION); + return EXIT_SUCCESS; + } + + if (show_help) + { + printf("%s\n\n", USAGE_STRING); + + args_print_usage(options, 35); + printf("\nSend bug reports and suggestions to: vmalvarez@virustotal.com\n"); + + return EXIT_SUCCESS; + } + + if (argc < 2) + { + fprintf(stderr, "yarac: wrong number of arguments\n"); + fprintf(stderr, "%s\n\n", USAGE_STRING); + fprintf(stderr, "Try `--help` for more options\n"); + + exit_with_code(EXIT_FAILURE); + } + + result = yr_initialize(); + + if (result != ERROR_SUCCESS) + exit_with_code(EXIT_FAILURE); + + if (yr_compiler_create(&compiler) != ERROR_SUCCESS) + exit_with_code(EXIT_FAILURE); + + if (!define_external_variables(compiler)) + exit_with_code(EXIT_FAILURE); + + cr.errors = 0; + cr.warnings = 0; + + yr_set_configuration(YR_CONFIG_MAX_STRINGS_PER_RULE, &max_strings_per_rule); + yr_compiler_set_callback(compiler, report_error, &cr); + + if (!compile_files(compiler, argc, argv)) + exit_with_code(EXIT_FAILURE); + + if (cr.errors > 0) + exit_with_code(EXIT_FAILURE); + + if (fail_on_warnings && cr.warnings > 0) + exit_with_code(EXIT_FAILURE); + + result = yr_compiler_get_rules(compiler, &rules); + + if (result != ERROR_SUCCESS) + { + fprintf(stderr, "error: %d\n", result); + exit_with_code(EXIT_FAILURE); + } + + result = yr_rules_save(rules, argv[argc - 1]); + + if (result != ERROR_SUCCESS) + { + fprintf(stderr, "error: %d\n", result); + exit_with_code(EXIT_FAILURE); + } + + result = EXIT_SUCCESS; + +_exit: + + if (compiler != NULL) + yr_compiler_destroy(compiler); + + if (rules != NULL) + yr_rules_destroy(rules); + + yr_finalize(); + + return result; +} diff --git a/yara-master/yarac.man b/yara-master/yarac.man new file mode 100644 index 0000000..0852da9 --- /dev/null +++ b/yara-master/yarac.man @@ -0,0 +1,53 @@ +.\"Text automatically generated by txt2man +.TH YARAC "1" "Jan 2014" "YARAC 2.0" "compile rules to yara" +.SH NAME +\fByarac \fP- compile rules to yara +.SH SYNOPSIS +.nf +.fam C +\fByarac\fP [OPTION]\.\.\. [RULE_FILE]\.\.\. \fIOUTPUT_FILE\fP +.fam T +.fi +.fam T +.fi +.SH DESCRIPTION +To invoke YARA you will need two things: a file with the rules you want to +use (either in source code or compiled form) and the target to be scanned. +The target can be a file, a folder, or a process. +.PP +Rule files can be passed directly in source code form, or can be previously +compiled with the \fByarac\fP tool. You may prefer to use your rules in compiled +form if you are going to invoke YARA multiple times with the same rules. +This way you’ll save time, because for YARA is faster to load compiled rules +than compiling the same rules over and over again. +.PP +The rules will be applied to the target specified as the last argument to YARA, +if it’s a path to a directory all the files contained in it will be scanned. +.SH OPTIONS +.TP +.B +\fB-d\fP = +define external variable. +.TP +.B \-w " --no-warnings" +Disable warnings. +.TP +.B " --fail-on-warnings" +Treat warnings as errors. Has no effect if used with +.B --no-warnings. +.TP +.B \-v " --version" +Show version information. +.SH EXAMPLE +The \fB-d\fP is used to define external variables. For example: +.PP +\fB-d\fP flag=true +.PP +\fB-d\fP beast=666 +.PP +\fB-d\fP name="James Bond" +.SH SEE ALSO +\fByara\fP(1) +.SH AUTHOR +\fByarac\fP was written by Victor M. Alvarez . +This manual page was written by Joao Eriberto Mota Filho for the Debian project (but may be used by others).