├── server ├── log │ ├── .gitkeep │ └── development.log ├── app │ ├── assets │ │ ├── sigs │ │ │ └── .keep │ │ ├── javascripts │ │ │ ├── sessions.js │ │ │ ├── alerts.js │ │ │ ├── application.js │ │ │ └── users.js │ │ ├── stylesheets │ │ │ ├── scaffolds.css.scss │ │ │ ├── dll.css.scss │ │ │ ├── alert.css.scss │ │ │ ├── alerts.css.scss │ │ │ ├── available_dll.css.scss │ │ │ └── signature_sets.css.scss │ │ └── images │ │ │ └── rails.png │ ├── mailers │ │ └── .gitkeep │ ├── models │ │ ├── .gitkeep │ │ ├── available_dll.rb │ │ ├── parameter.rb │ │ ├── user.rb │ │ ├── alert_arg.rb │ │ ├── alert.rb │ │ ├── available_function.rb │ │ ├── argument.rb │ │ ├── action.rb │ │ └── signature_set.rb │ ├── helpers │ │ ├── dll_helper.rb │ │ ├── alerts_helper.rb │ │ ├── available_dll_helper.rb │ │ ├── signature_sets_helper.rb │ │ └── application_helper.rb │ ├── views │ │ ├── dll │ │ │ ├── new.html.erb │ │ │ └── delete.html.erb │ │ ├── signature_sets │ │ │ ├── new.html.erb │ │ │ ├── edit.html.erb │ │ │ ├── regcmd.html.erb │ │ │ ├── adm.html.erb │ │ │ ├── _import.erb │ │ │ ├── index.html.erb │ │ │ ├── _form.html.erb │ │ │ └── regexinfo.html.erb │ │ ├── alerts │ │ │ ├── show.html.erb │ │ │ └── index.html.erb │ │ ├── sessions │ │ │ └── new.html.erb │ │ ├── layouts │ │ │ └── application.html.erb │ │ └── users │ │ │ └── index.html.erb │ └── controllers │ │ ├── available_function_controller.rb │ │ ├── available_dll_controller.rb │ │ ├── application_controller.rb │ │ ├── sessions_controller.rb │ │ ├── users_controller.rb │ │ ├── alerts_controller.rb │ │ ├── signature_sets_controller.rb │ │ └── actions_controller.rb ├── lib │ ├── assets │ │ └── .gitkeep │ └── tasks │ │ └── .gitkeep ├── vendor │ ├── plugins │ │ └── .gitkeep │ └── assets │ │ └── stylesheets │ │ └── .gitkeep ├── public │ ├── installer.msi │ ├── favicon.ico │ ├── robots.txt │ ├── 422.html │ ├── 404.html │ └── 500.html ├── config.ru ├── config │ ├── boot.rb │ ├── locales │ │ └── en.yml │ ├── initializers │ │ ├── mime_types.rb │ │ ├── inflections.rb │ │ ├── backtrace_silencers.rb │ │ ├── session_store.rb │ │ ├── wrap_parameters.rb │ │ └── secret_token.rb │ ├── environment.rb │ ├── database.yml │ ├── environments │ │ ├── development.rb │ │ ├── test.rb │ │ └── production.rb │ ├── application.rb │ └── routes.rb ├── doc │ └── README_FOR_APP ├── Rakefile ├── script │ └── rails ├── Gemfile └── db │ └── schema.rb ├── sig.dat ├── client ├── Release │ ├── setup.exe │ ├── sig.dat │ ├── apihook.dll │ ├── config.exe │ ├── hookTester.exe │ ├── installer.msi │ └── vcredist_x86 │ │ └── vcredist_x86.exe ├── installer │ ├── sig.dat │ ├── libeay32.dll │ ├── openssl.exe │ └── ssleay32.dll ├── apihook │ ├── apihook.aps │ ├── resource.h │ ├── reporting.h │ ├── udis │ │ ├── syn.h │ │ ├── input.h │ │ ├── extern.h │ │ ├── syn.c │ │ ├── udis86.c │ │ ├── syn-att.c │ │ ├── syn-intel.c │ │ ├── types.h │ │ └── input.c │ ├── asm │ │ ├── loadlibrary64.asm │ │ ├── loadlibrary32.asm │ │ ├── apc64.asm │ │ ├── executex64.asm │ │ ├── apc32.asm │ │ └── remotethread.asm │ ├── wslre.h │ ├── apihookx86.h │ ├── apihookx64.h │ ├── apihook.rc │ ├── slre.h │ ├── NCodeHook.h │ ├── base_inject.h │ ├── apihook.h │ ├── signatures.h │ └── apihook.vcproj ├── x64 │ └── Release │ │ ├── sig.dat │ │ ├── apihook64.dll │ │ └── hookTester.exe ├── Ambush.sln ├── config │ ├── config.vcproj │ └── logparser.cpp └── hookTester │ ├── main.cpp │ └── hookTester.vcproj ├── .gitignore ├── HOWTO_setup_clients.txt ├── exampleSignatureSet.yml └── HOWTO_setup_server.txt /server/log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/app/assets/sigs/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/app/mailers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/lib/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/lib/tasks/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/log/development.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/app/assets/javascripts/sessions.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/vendor/assets/stylesheets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/app/assets/stylesheets/scaffolds.css.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /server/app/helpers/dll_helper.rb: -------------------------------------------------------------------------------- 1 | module DllHelper 2 | end 3 | -------------------------------------------------------------------------------- /server/public/installer.msi: -------------------------------------------------------------------------------- 1 | ../../client/Release/installer.msi -------------------------------------------------------------------------------- /server/app/helpers/alerts_helper.rb: -------------------------------------------------------------------------------- 1 | module AlertsHelper 2 | end 3 | -------------------------------------------------------------------------------- /sig.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/sig.dat -------------------------------------------------------------------------------- /server/app/helpers/available_dll_helper.rb: -------------------------------------------------------------------------------- 1 | module AvailableDllHelper 2 | end 3 | -------------------------------------------------------------------------------- /server/app/helpers/signature_sets_helper.rb: -------------------------------------------------------------------------------- 1 | module SignatureSetsHelper 2 | end 3 | -------------------------------------------------------------------------------- /client/Release/setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/Release/setup.exe -------------------------------------------------------------------------------- /client/Release/sig.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/Release/sig.dat -------------------------------------------------------------------------------- /client/installer/sig.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/installer/sig.dat -------------------------------------------------------------------------------- /server/app/views/dll/new.html.erb: -------------------------------------------------------------------------------- 1 |

Dll#new

2 |

Find me in app/views/dll/new.html.erb

3 | -------------------------------------------------------------------------------- /client/Release/apihook.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/Release/apihook.dll -------------------------------------------------------------------------------- /client/Release/config.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/Release/config.exe -------------------------------------------------------------------------------- /client/apihook/apihook.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/apihook/apihook.aps -------------------------------------------------------------------------------- /client/x64/Release/sig.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/x64/Release/sig.dat -------------------------------------------------------------------------------- /server/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/server/public/favicon.ico -------------------------------------------------------------------------------- /client/Release/hookTester.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/Release/hookTester.exe -------------------------------------------------------------------------------- /client/Release/installer.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/Release/installer.msi -------------------------------------------------------------------------------- /client/installer/libeay32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/installer/libeay32.dll -------------------------------------------------------------------------------- /client/installer/openssl.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/installer/openssl.exe -------------------------------------------------------------------------------- /client/installer/ssleay32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/installer/ssleay32.dll -------------------------------------------------------------------------------- /server/app/views/dll/delete.html.erb: -------------------------------------------------------------------------------- 1 |

Dll#delete

2 |

Find me in app/views/dll/delete.html.erb

3 | -------------------------------------------------------------------------------- /client/x64/Release/apihook64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/x64/Release/apihook64.dll -------------------------------------------------------------------------------- /client/x64/Release/hookTester.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/x64/Release/hookTester.exe -------------------------------------------------------------------------------- /server/app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/server/app/assets/images/rails.png -------------------------------------------------------------------------------- /client/Release/vcredist_x86/vcredist_x86.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scriptjunkie/Ambush/HEAD/client/Release/vcredist_x86/vcredist_x86.exe -------------------------------------------------------------------------------- /server/app/views/signature_sets/new.html.erb: -------------------------------------------------------------------------------- 1 |

New signature_set

2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Back', signature_sets_path %> 6 | -------------------------------------------------------------------------------- /server/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Ambush::Application 5 | -------------------------------------------------------------------------------- /server/app/views/signature_sets/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :headeritem do %> 2 | back 3 | <% end %> 4 | <%= render 'form' %> 5 | -------------------------------------------------------------------------------- /server/app/assets/stylesheets/dll.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Dll controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /server/app/assets/stylesheets/alert.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the alert controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /server/app/assets/stylesheets/alerts.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Alerts controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /server/config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /server/app/assets/stylesheets/available_dll.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the AvailableDll controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /server/doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /server/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /server/app/views/signature_sets/regcmd.html.erb: -------------------------------------------------------------------------------- 1 | reg add HKLM\Software\Scriptjunkie\Ambush /v SignatureServer /t REG_SZ /d "<%=params[:domain] %>" /f 2 | reg add HKLM\Software\Scriptjunkie\Ambush /v SignatureSet /t REG_DWORD /d "<%=@signature_set.id %>" /f 3 | -------------------------------------------------------------------------------- /server/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /server/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /server/Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | Ambush::Application.load_tasks 8 | -------------------------------------------------------------------------------- /server/script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /server/app/controllers/available_function_controller.rb: -------------------------------------------------------------------------------- 1 | class AvailableFunctionController < ApplicationController 2 | before_filter :login_required 3 | respond_to :json 4 | 5 | # GET /available_function/1.json 6 | def show 7 | func = AvailableFunction.find(params[:id]) 8 | respond_with(:params => func.parameters.all(:order => 'num'), 9 | :decl => func.decl) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /server/app/views/signature_sets/adm.html.erb: -------------------------------------------------------------------------------- 1 | CLASS MACHINE 2 | CATEGORY "Ambush" 3 | POLICY "Signatures" 4 | KEYNAME "Software\Scriptjunkie\Ambush" 5 | PART "Signature Server" EDITTEXT REQUIRED 6 | VALUENAME "SignatureServer" 7 | DEFAULT "<%=params[:domain] %>" 8 | END PART 9 | PART "Signature Set" NUMERIC REQUIRED DEFAULT <%=@signature_set.id %> 10 | VALUENAME "SignatureSet" 11 | END PART 12 | END POLICY 13 | END CATEGORY 14 | -------------------------------------------------------------------------------- /server/app/views/alerts/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :headeritem do %> 2 | back 3 | <% end %> 4 | 5 |
6 | 7 |

8 | <%= h(@alert.action.name) %> 9 | <%= h(@alert.action.severity) %> 10 | <%= h(@alert.action.actionStr) %> 11 | <%= h(@alert.action.available_function.available_dll.name) %> 12 | <%= h(@alert.action.available_function.name+'('+@alert.display+')') %> 13 |

14 |
15 | -------------------------------------------------------------------------------- /server/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | -------------------------------------------------------------------------------- /server/app/assets/javascripts/alerts.js: -------------------------------------------------------------------------------- 1 | //= require jquery.tools.min.js 2 | function updateAlerts(){ 3 | $.getJSON('/alerts.json?time='+lastUpdate,function(data){ 4 | for(id in data.remove) 5 | $('#'+id).remove(); 6 | $('tr').removeClass('new') 7 | $('#sigtbody').prepend(data.rows); 8 | lastUpdate = data.lastUpdate; 9 | } 10 | ); 11 | } 12 | if (location.href.indexOf('offset') == -1) 13 | window.poll = setInterval(updateAlerts,10000); 14 | -------------------------------------------------------------------------------- /server/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /server/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Ambush::Application.config.session_store :cookie_store, key: '_ambush_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # Ambush::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /client/apihook/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by apihook.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /server/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into including all the files listed below. 2 | // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically 3 | // be included in the compiled file accessible from http://example.com/assets/application.js 4 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 5 | // the compiled file. 6 | // 7 | //= require_tree . 8 | 9 | -------------------------------------------------------------------------------- /server/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | Rails.logger = Logger.new(STDOUT) 5 | 6 | # Initialize the rails application 7 | Ambush::Application.initialize! 8 | 9 | require 'fileutils' 10 | 11 | dir = File.join(File.dirname(__FILE__), '..', 'app', 'assets', 'sigs') 12 | Dir.foreach(dir) do |f| 13 | if not f.end_with?('.key','.','.keep') then 14 | FileUtils.rm_f( File.join(dir,f) ) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /server/app/controllers/available_dll_controller.rb: -------------------------------------------------------------------------------- 1 | class AvailableDllController < ApplicationController 2 | before_filter :login_required 3 | respond_to :json 4 | 5 | # GET /available_dll/show.json?name= 6 | def show 7 | respond_with(AvailableFunction.find(:all, 8 | :include => [:available_dll], 9 | :conditions => ['available_dlls.name = ? and available_functions.decl IS NOT NULL', params[:name]], 10 | :order => "available_functions.name").map{ |f| [f.id,f.name] }) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Ambush files 2 | *.key 3 | *.dat 4 | 5 | #OS junk files 6 | [Tt]humbs.db 7 | *.DS_Store 8 | 9 | #Visual Studio files 10 | *.[Oo]bj 11 | *.user 12 | *.aps 13 | *.pch 14 | *.vspscc 15 | *.vssscc 16 | *_i.c 17 | *_p.c 18 | *.ncb 19 | *.pdb 20 | *.suo 21 | *.tlb 22 | *.tlh 23 | *.bak 24 | *.[Cc]ache 25 | *.ilk 26 | *.log 27 | *.lib 28 | *.sbr 29 | *.sdf 30 | *.opensdf 31 | *.unsuccessfulbuild 32 | ipch/ 33 | obj/ 34 | [Bb]in 35 | [Dd]ebug*/ 36 | Ankh.NoLoad 37 | 38 | # visual studio database projects 39 | *.dbmdl 40 | -------------------------------------------------------------------------------- /server/app/assets/stylesheets/signature_sets.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the SignatureSets controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | 5 | p.param{ 6 | box-shadow: none; 7 | color: white; 8 | margin: 1px; 9 | padding: 1px; 10 | font-family: arial; 11 | } 12 | textarea.list{ 13 | width:400px; 14 | } 15 | #lists{ 16 | top: 50px; 17 | width: 500px; 18 | left: 50%; 19 | margin-left: -250px; 20 | position: fixed; 21 | display: none; 22 | z-index:2 23 | } 24 | -------------------------------------------------------------------------------- /server/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /client/apihook/reporting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "apihook.h" 3 | 4 | //default max 100mb log file size 5 | #define LOG_FILE_SIZE_LIMIT 100000000 6 | 7 | typedef struct myAlertQueueNode { 8 | PHOOKAPI_MESSAGE message; 9 | HANDLE eventHandle; 10 | myAlertQueueNode * next; 11 | } AlertQueueNode; 12 | 13 | BOOL checkLogging(); 14 | void sendAlert(HOOKAPI_FUNC_CONF* conf, HOOKAPI_ACTION_CONF* action, void** calledArgPtr); 15 | 16 | //exception reporting 17 | DWORD exceptionFilter(LPEXCEPTION_POINTERS pointers); 18 | BOOL reportError(PWCHAR errorStr); 19 | -------------------------------------------------------------------------------- /server/app/views/signature_sets/_import.erb: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /server/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | helper_method :current_user 4 | 5 | private 6 | 7 | def current_user 8 | begin 9 | @current_user ||= User.find(session[:user_id]) if session[:user_id] 10 | rescue 11 | nil 12 | end 13 | end 14 | 15 | # call this as a before_filter to require them to be logged in 16 | def login_required 17 | if current_user.nil? 18 | redirect_to login_url, :alert => "You must first log in or sign up before accessing this page." 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /server/app/views/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | <% if @first_time %> 4 |

Ambush Setup

Enter admin credentials:

5 | <% else %> 6 |

Ambush Login

7 | <% end %> 8 | <%= form_tag sessions_path do %> 9 |

10 | <%= label_tag :login, "Username" %> 11 | 12 |

13 |

14 | <%= label_tag :password %> 15 | 16 |

17 |

18 | <% if @first_time %> 19 | <%= submit_tag "Register" %> 20 | <% else %> 21 | <%= submit_tag "Log in" %> 22 | <% end %> 23 |

24 | <% end %> 25 |
26 |
27 | -------------------------------------------------------------------------------- /client/apihook/udis/syn.h: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * syn.h 3 | * 4 | * Copyright (c) 2006, Vivek Mohan 5 | * All rights reserved. See LICENSE 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | #ifndef UD_SYN_H 9 | #define UD_SYN_H 10 | 11 | #include 12 | #include 13 | #include "types.h" 14 | 15 | extern const char* ud_reg_tab[]; 16 | 17 | static void mkasm(struct ud* u, const char* fmt, ...) 18 | { 19 | va_list ap; 20 | va_start(ap, fmt); 21 | u->insn_fill += vsprintf((char*) u->insn_buffer + u->insn_fill, fmt, ap); 22 | va_end(ap); 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /server/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem 'activerecord-jdbcsqlite3-adapter' 3 | # 4 | # Configure Using Gemfile 5 | # gem 'activerecord-jdbcsqlite3-adapter' 6 | # 7 | development: 8 | adapter: sqlite3 9 | database: db/development.sqlite3 10 | 11 | # Warning: The database defined as "test" will be erased and 12 | # re-generated from your development database when you run "rake". 13 | # Do not set this db to the same as development or production. 14 | test: 15 | adapter: sqlite3 16 | database: db/test.sqlite3 17 | 18 | production: 19 | adapter: mysql2 20 | encoding: utf8 21 | reconnect: false 22 | database: ambush 23 | pool: 5 24 | host: localhost 25 | username: ambush 26 | password: password 27 | -------------------------------------------------------------------------------- /server/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /server/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | 8 | require 'securerandom' 9 | 10 | secret_token_filename = File.join(File.dirname(__FILE__), 'secret_token') 11 | ambush_secret_token = SecureRandom.hex(15) 12 | begin 13 | f=File.open(secret_token_filename,"r") 14 | ambush_secret_token = f.read 15 | f.close 16 | rescue 17 | f=File.open(secret_token_filename,"w") 18 | f.write(ambush_secret_token) 19 | f.close 20 | end 21 | 22 | Ambush::Application.config.secret_token = ambush_secret_token 23 | -------------------------------------------------------------------------------- /server/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /server/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |

We've been notified about this issue and we'll take a look at it shortly.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /server/app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | protect_from_forgery 3 | def new 4 | @first_time = (User.count == 0) 5 | end 6 | 7 | def create 8 | if User.count == 0 9 | user = User.new(:username => params[:login], :password => params[:password]) 10 | user.save 11 | redirect_to root_url, :notice => "Registration successful. Please log in." 12 | return 13 | end 14 | user = User.authenticate(params[:login], params[:password]) 15 | if user 16 | session[:user_id] = user.id 17 | redirect_to root_url, :notice => "Logged in successfully." 18 | else 19 | flash.now[:alert] = "Invalid login or password." 20 | render :action => 'new' 21 | end 22 | end 23 | 24 | def destroy 25 | session[:user_id] = nil 26 | redirect_to root_url, :notice => "You have been logged out." 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /server/app/models/available_dll.rb: -------------------------------------------------------------------------------- 1 | class AvailableDll < ActiveRecord::Base 2 | has_many :available_functions, :dependent => :destroy 3 | 4 | def self.find_or_create(name) 5 | dll = AvailableDll.find(:first, :conditions => {:name => name}) 6 | if dll == nil 7 | dll = AvailableDll.new(:name => name) 8 | dll.save 9 | end 10 | dll 11 | end 12 | 13 | def compiled(ssid) 14 | dname = self.name.downcase + ("\x00"*(4-(self.name.length % 4))) 15 | funcs = self.available_functions.joins(:actions).where('actions.signature_set_id' => ssid) 16 | numfuncs = 0 17 | temp = '' 18 | funcs.each do |func| 19 | funcompiled = func.compiled(ssid) 20 | if(funcompiled.length > 0) 21 | temp << funcompiled 22 | numfuncs += 1 23 | end 24 | end 25 | return '' if numfuncs == 0 26 | out = [numfuncs, dname.length].pack("V*") + dname + temp 27 | # size, numfuncs, namelen, name[], funcs[] 28 | [out.size + 4].pack("V*") + out 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /server/app/models/parameter.rb: -------------------------------------------------------------------------------- 1 | class Parameter < ActiveRecord::Base 2 | @@types = ['ignore', 'integer', 'range', 'c string', 'wide-char string', 'pointer', 'bitmask', 'blob', 'not'] 3 | belongs_to :available_function 4 | 5 | def compiled 6 | raise "Error - invalid parameter type" if self.paramtype == nil 7 | out = [self.paramtype].pack("V*") 8 | case @@types[self.paramtype] 9 | when 'ignore' 10 | when 'integer', 'not', 'c string', 'wide-char string' 11 | out << [0].pack("V*") 12 | when 'range', 'pointer', 'bitmask' 13 | out << [0, 0].pack("V*") 14 | when 'blob' 15 | Rails.logger.debug self.inspect 16 | # if not a number, must be a ref 17 | self.arg = -1 if self.arg == nil 18 | self.size = 0 if self.size == nil 19 | out << [self.arg, self.size, 0].pack("V*") 20 | else 21 | raise "Error - type #{self.paramtype} not supported" 22 | end 23 | # size, type, value 24 | [out.size + 4].pack("V*") + out 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /server/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def browserclass 3 | @browser_name ||= begin 4 | ua = request.env['HTTP_USER_AGENT'].downcase 5 | if ua.index('msie') && !ua.index('opera') && !ua.index('webtv') 6 | msieindx = ua.index('msie') 7 | if ua[msieindx + 5,ua.index(';',msieindx)-msieindx-5].to_i < 10 8 | 'earlyie' 9 | else 10 | 'ie10' 11 | end 12 | elsif ua.index('gecko/') || ua.index('mozilla/') 13 | 'gecko' 14 | elsif ua.index('applewebkit/') 15 | 'webkit' 16 | end 17 | end 18 | end 19 | 20 | # turns a regex list from display format (multiline) to a lowercase regex 21 | # also null pads to 4 byte alignment 22 | def self.splitregex(str) 23 | return "\x00\x00\x00\x00".encode('binary') if str == nil or str.chomp == '' 24 | newstr = '(' + str.chomp.gsub(/\r\n/,'|').gsub(/\n/,'|') + ')' 25 | newstr = newstr.downcase.encode("UTF-16LE").force_encoding('binary') 26 | newstr = newstr + ("\x00" * (4 - (newstr.length % 4))) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /server/app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_filter :login_required 3 | 4 | # GET /users 5 | # GET /users.json 6 | def index 7 | @users = User.all 8 | respond_to do |format| 9 | format.html # index.html.erb 10 | format.json { 11 | render json: @users 12 | } 13 | end 14 | end 15 | 16 | # DELETE /users/1.json 17 | def destroy 18 | user = User.find(params[:id]) 19 | user.destroy 20 | send_data '' 21 | end 22 | 23 | # POST /users 24 | # POST /users.json 25 | def create 26 | #Changing password 27 | if(params[:user][:id]) 28 | user = User.find(params[:user][:id]) 29 | user.password = params[:user][:password] 30 | user.save! 31 | send_data '' 32 | return 33 | end 34 | #New user 35 | founduser = User.find_by_username(params[:user][:username]) 36 | if(founduser) 37 | render :status => :forbidden, :text => "Not allowed to overwrite user" 38 | else 39 | user = User.new(params[:user]) 40 | user.save 41 | send_data '' 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /server/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ambush IPS 5 | <%= stylesheet_link_tag "application" %> 6 | <%= stylesheet_link_tag params[:controller] %> 7 | <%= javascript_include_tag params[:controller] %> 8 | <%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %> 9 | 10 | 11 |
12 | <%= yield :unwrapped %> 13 |
14 |
15 |

16 | <% if current_user.nil? %> 17 | Ambush HIPS 18 | <% else %> 19 | Alerts | Signatures | Users | Logout<%= yield :headeritem %> 20 | <% end %> 21 |

22 |
23 | <%= yield %> 24 |
25 |
26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /server/app/models/user.rb: -------------------------------------------------------------------------------- 1 | require 'digest/sha1' 2 | class User < ActiveRecord::Base 3 | attr_accessible :username, :password, :password_confirmation 4 | attr_accessor :password 5 | before_save :prepare_password 6 | 7 | validates_presence_of :password, :on => :create 8 | validates_confirmation_of :password 9 | validates_length_of :password, :minimum => 4, :allow_blank => true 10 | 11 | def self.authenticate(login, pass) 12 | user = find_by_username(login) 13 | return user if user && user.matching_password?(pass) 14 | end 15 | 16 | def matching_password?(pass) 17 | self.password_hash == encrypt_password(pass) 18 | end 19 | 20 | private 21 | 22 | def prepare_password 23 | unless password.blank? 24 | # gen salt 25 | chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a 26 | self.password_salt = "" 27 | 1.upto(10) do |i| 28 | self.password_salt << chars[rand(chars.size-1)] 29 | end 30 | self.password_hash = encrypt_password(password) 31 | end 32 | end 33 | 34 | def encrypt_password(pass) 35 | Digest::SHA1.hexdigest(pass + password_salt) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /server/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'rails', '>= 3.1.2' 4 | 5 | # Bundle edge Rails instead: 6 | # gem 'rails', :git => 'git://github.com/rails/rails.git' 7 | 8 | gem 'activerecord-jdbcsqlite3-adapter', :platforms => :jruby 9 | gem 'jruby-openssl', :platforms => :jruby 10 | gem 'mysql2', :platforms => :ruby 11 | gem 'therubyracer', :platforms => :ruby 12 | 13 | # Gems used only for assets and not required 14 | # in production environments by default. 15 | group :assets do 16 | gem 'sass-rails', '~> 3.1.5.rc.2' 17 | gem 'coffee-rails', '~> 3.1.1' 18 | gem 'uglifier', '>= 1.0.3' 19 | end 20 | 21 | gem 'jquery-rails' 22 | 23 | # To use ActiveModel has_secure_password 24 | # gem 'bcrypt-ruby', '~> 3.0.0' 25 | 26 | # Use unicorn as the web server 27 | # gem 'unicorn' 28 | 29 | # Deploy with Capistrano 30 | # gem 'capistrano' 31 | 32 | # To use debugger 33 | # gem 'ruby-debug19', :require => 'ruby-debug' 34 | 35 | group :test do 36 | # Pretty printed test output 37 | gem 'turn', '0.8.2', :require => false 38 | end 39 | 40 | group :development do 41 | gem 'sqlite3' 42 | end 43 | -------------------------------------------------------------------------------- /client/apihook/asm/loadlibrary64.asm: -------------------------------------------------------------------------------- 1 | ;-----------------------------------------------------------------------------; 2 | ; Author: scriptjunkie (scriptjunkie[at]scriptjunkie[dot]us), 3 | ; Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) 4 | ; Compatible: Windows 7, 2003 5 | ; 17 Jan 2012 6 | ;-----------------------------------------------------------------------------; 7 | 8 | [BITS 64] 9 | [ORG 0] 10 | 11 | cld ; Clear the direction flag. 12 | and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned 13 | call start ; Call start, this pushes the address of 'api_call' onto the stack. 14 | delta: ; 15 | %include "./src/block/block_api.asm" ; 16 | start: ; 17 | pop rbp ; Pop off the address of 'api_call' for calling later. 18 | lea rcx, [ebp+libpath-delta] 19 | mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) 20 | call rbp ; LoadLibraryA( &libpath ); 21 | ; Finish up with the EXITFUNK. 22 | %include "./src/block/block_exitfunk.asm" 23 | libpath: 24 | ;db "funkystuff.dll", 0 25 | -------------------------------------------------------------------------------- /client/apihook/asm/loadlibrary32.asm: -------------------------------------------------------------------------------- 1 | ;-----------------------------------------------------------------------------; 2 | ; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) 3 | ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4 4 | ; Version: 1.0 (28 July 2009) 5 | ; Size: 189 bytes + strlen(libpath) + 1 6 | ; Build: >build.py single_loadlibrary 7 | ;-----------------------------------------------------------------------------; 8 | 9 | [BITS 32] 10 | [ORG 0] 11 | 12 | cld ; Clear the direction flag. 13 | call start ; Call start, this pushes the address of 'api_call' onto the stack. 14 | delta: ; 15 | %include "./src/block/block_api.asm" ; 16 | start: ; 17 | pop ebp ; Pop off the address of 'api_call' for calling later. 18 | lea eax, [ebp+libpath-delta] 19 | push eax ; 20 | push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) 21 | call ebp ; LoadLibraryA( &libpath ); 22 | ; Finish up with the EXITFUNK. 23 | %include "./src/block/block_exitfunk.asm" 24 | libpath: 25 | ;db "funkystuff.dll", 0 26 | -------------------------------------------------------------------------------- /server/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Ambush::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger 20 | config.active_support.deprecation = :log 21 | 22 | # Only use best-standards-support built into browsers 23 | config.action_dispatch.best_standards_support = :builtin 24 | 25 | # Do not compress assets 26 | config.assets.compress = false 27 | 28 | # Expands the lines which load the assets 29 | config.assets.debug = true 30 | end 31 | -------------------------------------------------------------------------------- /server/app/models/alert_arg.rb: -------------------------------------------------------------------------------- 1 | class AlertArg < ActiveRecord::Base 2 | belongs_to :parameter 3 | belongs_to :alert 4 | 5 | def initialize (alert, message, param) 6 | super(:alert => alert) 7 | size = message.slice!(0, 4).unpack('V')[0] 8 | type = message.slice!(0, 4).unpack('V')[0] 9 | self.data = message.slice!(0, size - 8) 10 | self.data = self.data.force_encoding("UTF-16LE").encode('UTF-8') if param.paramtype == 4 11 | self.parameter = param 12 | self.save 13 | end 14 | 15 | def display 16 | if self.data and self.parameter.paramtype == 1 # if integer 17 | # get 64 bit or 32 bit 18 | if self.data.length == 4 19 | number = self.data.unpack('V')[0] 20 | else 21 | number = self.data.unpack('Q')[0] 22 | end 23 | # find an intelligent base to display in. 10 by default, unless number is a power of two or power of two - 1 24 | # or the argument is a bitmask type 25 | arg = self.alert.action.arguments.order('id').offset(self.parameter.num - 1).first 26 | if number != 0 && (number & (number - 1) == 0 || number & (number + 1) == 0 || 27 | (arg && arg.argtype == 6)) 28 | return "0x#{number.to_s(16)}" 29 | else 30 | return number.to_s 31 | end 32 | end 33 | self.data.inspect 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /server/app/views/alerts/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :headeritem do %> 2 | clear 3 | <% end %> 4 | <%= javascript_include_tag 'sorttable.js' %> 5 | 8 |
9 | 10 |
Alerts
11 | 12 | 25 | 26 | <% @alerts.each do |alert| %> 27 | <%= raw alert.row(false) %> 28 | <% end %> 29 | 30 |
NameTimeSeverityActionUserSystemProcessModuleDLLCallCount
13 | <% if @offset >= @limit %> 14 | <% if @offset == @limit %> 15 | previous 16 | <% else %> 17 | previous 18 | <% end %> 19 | <% end %> 20 | 21 | <% if @alerts.count == @limit %> 22 | next 23 | <% end %> 24 |
31 |
32 | -------------------------------------------------------------------------------- /client/apihook/udis/input.h: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * input.h 3 | * 4 | * Copyright (c) 2006, Vivek Mohan 5 | * All rights reserved. See LICENSE 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | #ifndef UD_INPUT_H 9 | #define UD_INPUT_H 10 | 11 | #include "types.h" 12 | 13 | uint8_t inp_next(struct ud*); 14 | uint8_t inp_peek(struct ud*); 15 | uint8_t inp_uint8(struct ud*); 16 | uint16_t inp_uint16(struct ud*); 17 | uint32_t inp_uint32(struct ud*); 18 | uint64_t inp_uint64(struct ud*); 19 | void inp_move(struct ud*, size_t); 20 | void inp_back(struct ud*); 21 | 22 | /* inp_init() - Initializes the input system. */ 23 | #define inp_init(u) \ 24 | do { \ 25 | u->inp_curr = 0; \ 26 | u->inp_fill = 0; \ 27 | u->inp_ctr = 0; \ 28 | u->inp_end = 0; \ 29 | } while (0) 30 | 31 | /* inp_start() - Should be called before each de-code operation. */ 32 | #define inp_start(u) u->inp_ctr = 0 33 | 34 | /* inp_back() - Resets the current pointer to its position before the current 35 | * instruction disassembly was started. 36 | */ 37 | #define inp_reset(u) \ 38 | do { \ 39 | u->inp_curr -= u->inp_ctr; \ 40 | u->inp_ctr = 0; \ 41 | } while (0) 42 | 43 | /* inp_sess() - Returns the pointer to current session. */ 44 | #define inp_sess(u) (u->inp_sess) 45 | 46 | /* inp_cur() - Returns the current input byte. */ 47 | #define inp_curr(u) ((u)->inp_cache[(u)->inp_curr]) 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /server/app/assets/javascripts/users.js: -------------------------------------------------------------------------------- 1 | //= require jquery.tools.min.js 2 | // select all desired input fields and attach tooltips to them 3 | $("#new :text").tooltip({ 4 | position: "center right", 5 | effect: "fade", 6 | opacity: 0.8 7 | }); 8 | function closeOverlay(name){ 9 | if(!name) 10 | name = '#new'; 11 | $(name).overlay().close(); 12 | } 13 | function showNew(){ 14 | $('#new').overlay({load:true, fixed: false}).load(); 15 | } 16 | function submitNewUser(){ 17 | $.post('/users/', $('#newform').serialize() + "&authenticity_token=" + encodeURIComponent(AUTH_TOKEN), 18 | function(data){ 19 | document.location.reload(); 20 | } 21 | ).error(function(data){alert('Error creating user!');}); 22 | closeOverlay(); 23 | return false; 24 | } 25 | function deleteUser(id){ 26 | if(confirm('Delete this user?')) 27 | $.ajax({url: '/users/' + id + '.json', 28 | type: 'DELETE', 29 | success: function(returned){ 30 | $($('#'+id+'_box')[0].parentNode).remove(); 31 | }, 32 | data: "authenticity_token=" + encodeURIComponent(AUTH_TOKEN) 33 | }); 34 | } 35 | function changePassword(id){ 36 | $('#userid').val(id); 37 | $('#pass').overlay({load:true, fixed: false}).load(); 38 | } 39 | function submitNewPass(){ 40 | try{ 41 | if(confirm('Change password?')) 42 | $.post('/users/', $('#passform').serialize() + "&authenticity_token=" + encodeURIComponent(AUTH_TOKEN), 43 | function(data){ 44 | alert("Password changed"); 45 | } 46 | ).error(function(data){alert('Error changing password!');}); 47 | closeOverlay('#pass'); 48 | }catch(e){ 49 | } 50 | return false; 51 | } 52 | -------------------------------------------------------------------------------- /server/app/views/signature_sets/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :unwrapped do %> 2 | <%= javascript_include_tag 'sorttable.js' %> 3 | 11 | <% end %> 12 | 13 | <%= render 'import' %> 14 | 15 |
16 | 17 |
Signature Sets
18 | 19 | 20 | <% @signature_sets.each do |signature_set| %> 21 | 22 | <% end %> 23 | 24 | 25 |
NumberNameSignatures
<%= signature_set.id %><%= signature_set.name %>View/Edit SignaturesDelete Signature Set
26 |
27 |
28 | Import 29 | New 30 |
31 | -------------------------------------------------------------------------------- /HOWTO_setup_clients.txt: -------------------------------------------------------------------------------- 1 | Ambush Clients Setup 2 | 3 | Before you set up clients, you must set up a server. See the server setup HOWTO. Then you must configure each client by 4 | 1. Installing Ambush with the installer.msi file, and 5 | 2. Configuring the client which signature set to use and which server to pull it from 6 | 7 | Compatibility: Ambush was written for Windows Vista, 7, or 8. You are at your own risk using it on any other OS. Actually, you are at your own risk using it on those too, but it's at least been tested on those. 8 | 9 | #################### 10 | The group policy way 11 | #################### 12 | 13 | Ambush was designed to deploy to a network of clients. 14 | 15 | To do that, log into the Ambush server, click on the Signatures link at the top to go to the signatures page, and click on the signature set you want to assign to clients. Click on the details link in the upper-right-hand corner of the page and click the link to download the ADM file. You can load this administrative template (.adm) file into Group Policy to assign to clients. 16 | 17 | Download the MSI installer from http://your.vm.ip:3000/installer.msi to push out to your systems. 18 | 19 | Ideally you should push out the server configuration before the installer to avoid delays in installation and signature propagation, although this is not necessary. 20 | 21 | 22 | ################## 23 | The individual way 24 | ################## 25 | 26 | Download the MSI installer from http://your.vm.ip:3000/installer.msi and install on the system. Now you must configure a server and signature set to pull signatures from. To do that, run the following command with adminstrative privileges: 27 | "%PROGRAMFILES%\Scriptjunkie Software\Ambush\config.exe" server 2.3.4.5 1 28 | where 2.3.4.5 is the IP address of your server and 1 is the number of the signature set to use. 29 | -------------------------------------------------------------------------------- /server/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Ambush::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Use SQL instead of Active Record's schema dumper when creating the test database. 33 | # This is necessary if your schema can't be completely dumped by the schema dumper, 34 | # like if you have constraints or database-specific column types 35 | # config.active_record.schema_format = :sql 36 | 37 | # Print deprecation notices to the stderr 38 | config.active_support.deprecation = :stderr 39 | end 40 | -------------------------------------------------------------------------------- /client/apihook/udis/extern.h: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * extern.h 3 | * 4 | * Copyright (c) 2004, 2005, 2006, Vivek Mohan 5 | * All rights reserved. See LICENSE 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | #ifndef UD_EXTERN_H 9 | #define UD_EXTERN_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #include 16 | #include "types.h" 17 | 18 | /* ============================= PUBLIC API ================================= */ 19 | 20 | extern void ud_init(struct ud*); 21 | 22 | extern void ud_set_mode(struct ud*, uint8_t); 23 | 24 | extern void ud_set_pc(struct ud*, uint64_t); 25 | 26 | extern void ud_set_input_hook(struct ud*, int (*)(struct ud*)); 27 | 28 | extern void ud_set_input_buffer(struct ud*, uint8_t*, size_t); 29 | 30 | #ifndef __UD_STANDALONE__ 31 | extern void ud_set_input_file(struct ud*, FILE*); 32 | #endif /* __UD_STANDALONE__ */ 33 | 34 | extern void ud_set_vendor(struct ud*, unsigned); 35 | 36 | extern void ud_set_syntax(struct ud*, void (*)(struct ud*)); 37 | 38 | extern void ud_input_skip(struct ud*, size_t); 39 | 40 | extern int ud_input_end(struct ud*); 41 | 42 | extern unsigned int ud_decode(struct ud*); 43 | 44 | extern unsigned int ud_disassemble(struct ud*); 45 | 46 | extern void ud_translate_intel(struct ud*); 47 | 48 | extern void ud_translate_att(struct ud*); 49 | 50 | extern char* ud_insn_asm(struct ud* u); 51 | 52 | extern uint8_t* ud_insn_ptr(struct ud* u); 53 | 54 | extern uint64_t ud_insn_off(struct ud*); 55 | 56 | extern char* ud_insn_hex(struct ud*); 57 | 58 | extern unsigned int ud_insn_len(struct ud* u); 59 | 60 | extern const char* ud_lookup_mnemonic(enum ud_mnemonic_code c); 61 | 62 | /* ========================================================================== */ 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | #endif 68 | -------------------------------------------------------------------------------- /client/apihook/udis/syn.c: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * syn.c 3 | * 4 | * Copyright (c) 2002, 2003, 2004 Vivek Mohan 5 | * All rights reserved. See (LICENSE) 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | 9 | /* ----------------------------------------------------------------------------- 10 | * Intel Register Table - Order Matters (types.h)! 11 | * ----------------------------------------------------------------------------- 12 | */ 13 | const char* ud_reg_tab[] = 14 | { 15 | "al", "cl", "dl", "bl", 16 | "ah", "ch", "dh", "bh", 17 | "spl", "bpl", "sil", "dil", 18 | "r8b", "r9b", "r10b", "r11b", 19 | "r12b", "r13b", "r14b", "r15b", 20 | 21 | "ax", "cx", "dx", "bx", 22 | "sp", "bp", "si", "di", 23 | "r8w", "r9w", "r10w", "r11w", 24 | "r12w", "r13W" , "r14w", "r15w", 25 | 26 | "eax", "ecx", "edx", "ebx", 27 | "esp", "ebp", "esi", "edi", 28 | "r8d", "r9d", "r10d", "r11d", 29 | "r12d", "r13d", "r14d", "r15d", 30 | 31 | "rax", "rcx", "rdx", "rbx", 32 | "rsp", "rbp", "rsi", "rdi", 33 | "r8", "r9", "r10", "r11", 34 | "r12", "r13", "r14", "r15", 35 | 36 | "es", "cs", "ss", "ds", 37 | "fs", "gs", 38 | 39 | "cr0", "cr1", "cr2", "cr3", 40 | "cr4", "cr5", "cr6", "cr7", 41 | "cr8", "cr9", "cr10", "cr11", 42 | "cr12", "cr13", "cr14", "cr15", 43 | 44 | "dr0", "dr1", "dr2", "dr3", 45 | "dr4", "dr5", "dr6", "dr7", 46 | "dr8", "dr9", "dr10", "dr11", 47 | "dr12", "dr13", "dr14", "dr15", 48 | 49 | "mm0", "mm1", "mm2", "mm3", 50 | "mm4", "mm5", "mm6", "mm7", 51 | 52 | "st0", "st1", "st2", "st3", 53 | "st4", "st5", "st6", "st7", 54 | 55 | "xmm0", "xmm1", "xmm2", "xmm3", 56 | "xmm4", "xmm5", "xmm6", "xmm7", 57 | "xmm8", "xmm9", "xmm10", "xmm11", 58 | "xmm12", "xmm13", "xmm14", "xmm15", 59 | 60 | "rip" 61 | }; 62 | -------------------------------------------------------------------------------- /client/apihook/wslre.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2005 Sergey Lyubka 3 | * All rights reserved 4 | * 5 | * "THE BEER-WARE LICENSE" (Revision 42): 6 | * Sergey Lyubka wrote this file. As long as you retain this notice you 7 | * can do whatever you want with this stuff. If we meet some day, and you think 8 | * this stuff is worth it, you can buy me a beer in return. 9 | */ 10 | 11 | /* Modified for wchar_t support by scriptjunkie */ 12 | 13 | #ifndef WSLRE_HEADER_DEFINED 14 | #define WSLRE_HEADER_DEFINED 15 | 16 | /* 17 | * Compiled regular expression 18 | */ 19 | struct wslre { 20 | wchar_t code[256]; 21 | wchar_t data[256]; 22 | int code_size; 23 | int data_size; 24 | int num_caps; /* Number of bracket pairs */ 25 | int anchored; /* Must match from string start */ 26 | const wchar_t *err_str; /* Error string */ 27 | }; 28 | 29 | /* 30 | * Captured substring 31 | */ 32 | struct wcap { 33 | const wchar_t *ptr; /* Pointer to the substring */ 34 | int len; /* Substring length */ 35 | }; 36 | 37 | /* 38 | * Compile regular expression. If success, 1 is returned. 39 | * If error, 0 is returned and slre.err_str points to the error message. 40 | */ 41 | int wslre_compile(struct wslre *, const wchar_t *re); 42 | 43 | /* 44 | * Return 1 if match, 0 if no match. 45 | * If `captured_substrings' array is not NULL, then it is filled with the 46 | * values of captured substrings. captured_substrings[0] element is always 47 | * a full matched substring. The round bracket captures start from 48 | * captured_substrings[1]. 49 | * It is assumed that the size of captured_substrings array is enough to 50 | * hold all captures. The caller function must make sure it is! So, the 51 | * array_size = number_of_round_bracket_pairs + 1 52 | */ 53 | int wslre_match(const struct wslre *, const wchar_t *buf, int buf_len, 54 | struct wcap *captured_substrings); 55 | 56 | #endif /* SLRE_HEADER_DEFINED */ -------------------------------------------------------------------------------- /server/app/views/signature_sets/_form.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= form_tag(@signature_set, :method => :put) do %> 3 | 4 | <% if @signature_set.errors.any? %> 5 |
6 |

<%= pluralize(@signature_set.errors.count, "error") %> prohibited this signature_set from being saved:

7 | 8 |
    9 | <% @signature_set.errors.full_messages.each do |msg| %> 10 |
  • <%= msg %>
  • 11 | <% end %> 12 |
13 |
14 | <% end %> 15 | 16 | 17 |
Signature set <%= @signature_set.id %> - details
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
FieldValue
Name<%= text_field :signature_set, :name %>
Export as YAMLDownload
Alert aggregator (syslog)<%= text_field :signature_set, :aggregator %>
Aggregator port (default 514)<%= text_field :signature_set, :aggregator_port %>
Process blacklist (regular expressions) <%= text_area :signature_set, :procblacklist %>
Client setupClients need one of the below configuration options and the msi installer.
ADM file (group policy)Download
Batch fileDownload
31 | 32 |
33 |
Back 34 | Save
35 | 36 | <% end %> 37 | -------------------------------------------------------------------------------- /server/app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :unwrapped do %> 2 | 11 | 20 | <% end %> 21 | 22 |
23 | 24 |
Users
25 | 26 | 27 | <% @users.each do |user| %> 28 | 29 | <% end %> 30 | 31 | 32 |
UsernameActions
<%= user.username %>Change passwordDelete user
33 |
34 |
35 | New 36 |
37 | -------------------------------------------------------------------------------- /server/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | if defined?(Bundler) 6 | # If you precompile assets before deploying to production, use this line 7 | Bundler.require(*Rails.groups(:assets => %w(development test))) 8 | # If you want your assets lazily compiled in production, use this line 9 | # Bundler.require(:default, :assets, Rails.env) 10 | end 11 | 12 | module Ambush 13 | class Application < Rails::Application 14 | # Settings in config/environments/* take precedence over those specified here. 15 | # Application configuration should go into files in config/initializers 16 | # -- all .rb files in that directory are automatically loaded. 17 | 18 | # Custom directories with classes and modules you want to be autoloadable. 19 | # config.autoload_paths += %W(#{config.root}/extras) 20 | 21 | # Only load the plugins named here, in the order given (default is alphabetical). 22 | # :all can be used as a placeholder for all plugins not explicitly named. 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 24 | 25 | # Activate observers that should always be running. 26 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 27 | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 30 | # config.time_zone = 'Central Time (US & Canada)' 31 | 32 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 33 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 34 | # config.i18n.default_locale = :de 35 | 36 | # Configure the default encoding used in templates for Ruby 1.9. 37 | config.encoding = "utf-8" 38 | 39 | # Configure sensitive parameters which will be filtered from the log file. 40 | config.filter_parameters += [:password] 41 | 42 | # Enable the asset pipeline 43 | config.assets.enabled = true 44 | 45 | # Version of your assets, change this if you want to expire all your assets 46 | config.assets.version = '1.0' 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /client/Ambush.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 10.00 2 | # Visual Studio 2008 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "apihook", "apihook\apihook.vcproj", "{57E5F0A7-2F7D-452B-A9C4-443DA43781C5}" 4 | EndProject 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hookTester", "hookTester\hookTester.vcproj", "{6C26D565-0DEA-48A7-AB84-1BA43C2E1CC7}" 6 | EndProject 7 | Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "installer", "installer\installer.vdproj", "{1A5BB00C-3799-4D1C-920D-2AA35B276EE6}" 8 | EndProject 9 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "config", "config\config.vcproj", "{84624F0D-0C61-43EE-BFA6-40FC05395D2B}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Release|Win32 = Release|Win32 14 | Release|x64 = Release|x64 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {57E5F0A7-2F7D-452B-A9C4-443DA43781C5}.Release|Win32.ActiveCfg = Release|Win32 18 | {57E5F0A7-2F7D-452B-A9C4-443DA43781C5}.Release|Win32.Build.0 = Release|Win32 19 | {57E5F0A7-2F7D-452B-A9C4-443DA43781C5}.Release|x64.ActiveCfg = Release|x64 20 | {57E5F0A7-2F7D-452B-A9C4-443DA43781C5}.Release|x64.Build.0 = Release|x64 21 | {6C26D565-0DEA-48A7-AB84-1BA43C2E1CC7}.Release|Win32.ActiveCfg = Release|Win32 22 | {6C26D565-0DEA-48A7-AB84-1BA43C2E1CC7}.Release|Win32.Build.0 = Release|Win32 23 | {6C26D565-0DEA-48A7-AB84-1BA43C2E1CC7}.Release|x64.ActiveCfg = Release|x64 24 | {6C26D565-0DEA-48A7-AB84-1BA43C2E1CC7}.Release|x64.Build.0 = Release|x64 25 | {1A5BB00C-3799-4D1C-920D-2AA35B276EE6}.Release|Win32.ActiveCfg = Release 26 | {1A5BB00C-3799-4D1C-920D-2AA35B276EE6}.Release|Win32.Build.0 = Release 27 | {1A5BB00C-3799-4D1C-920D-2AA35B276EE6}.Release|x64.ActiveCfg = Release 28 | {1A5BB00C-3799-4D1C-920D-2AA35B276EE6}.Release|x64.Build.0 = Release 29 | {84624F0D-0C61-43EE-BFA6-40FC05395D2B}.Release|Win32.ActiveCfg = Release|Win32 30 | {84624F0D-0C61-43EE-BFA6-40FC05395D2B}.Release|Win32.Build.0 = Release|Win32 31 | {84624F0D-0C61-43EE-BFA6-40FC05395D2B}.Release|x64.ActiveCfg = Release|Win32 32 | {84624F0D-0C61-43EE-BFA6-40FC05395D2B}.Release|x64.Build.0 = Release|Win32 33 | EndGlobalSection 34 | GlobalSection(SolutionProperties) = preSolution 35 | HideSolutionNode = FALSE 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /server/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Ambush::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = true 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to Rails.root.join("public/assets") 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Use a different logger for distributed setups 37 | # config.logger = SyslogLogger.new 38 | 39 | # Use a different cache store in production 40 | # config.cache_store = :mem_cache_store 41 | 42 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 43 | # config.action_controller.asset_host = "http://assets.example.com" 44 | 45 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 46 | # config.assets.precompile += %w( search.js ) 47 | 48 | # Disable delivery errors, bad email addresses will be ignored 49 | # config.action_mailer.raise_delivery_errors = false 50 | 51 | # Enable threaded mode 52 | # config.threadsafe! 53 | 54 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 55 | # the I18n.default_locale when a translation can not be found) 56 | config.i18n.fallbacks = true 57 | 58 | # Send deprecation notices to registered listeners 59 | config.active_support.deprecation = :notify 60 | end 61 | -------------------------------------------------------------------------------- /server/app/models/alert.rb: -------------------------------------------------------------------------------- 1 | class Alert < ActiveRecord::Base 2 | belongs_to :action 3 | has_many :alert_args, :dependent => :destroy 4 | @@severities = {0 => 'none', 1000 => 'low', 2000 => 'medium', 3000 => 'high', 4000 => 'critical'} 5 | 6 | def san(val) 7 | ActionController::Base.helpers.sanitize(val).to_s.gsub("\\","\\").gsub(",",",") 8 | end 9 | 10 | def display 11 | self.alert_args.map { |aa| aa.display }.join(",") 12 | end 13 | 14 | def row(new) 15 | rowclass = '' 16 | rowclass = ' class="new"' if new 17 | severityStr = @@severities[self.action.severity] || self.action.severity.to_s 18 | "#{san(self.action.name) }#{self.created_at } #{self.updated_at if self.count > 1 and self.updated_at - self.created_at > 5 }#{severityStr}#{san(self.action.actionStr) }#{san(self.user) }#{san(self.computer) } (#{self.ip })#{san(self.process) } (#{self.pid })#{san(self.module)}#{san(self.action.available_function.available_dll.name) }#{san(self.action.available_function.name+'('+self.display)})#{self.count}" 19 | end 20 | 21 | #formats according to a VISUAL element in syslog - minus quotes, :, =, and ] 22 | def cleanSyslog(str) 23 | newstr = '' 24 | str.each_char do |c| 25 | cval = c.ord 26 | newstr << c if cval >= 35 and cval <= 126 and cval != 58 and cval != 61 and cval != 93 27 | end 28 | newstr 29 | end 30 | 31 | def toSyslog 32 | dllname = self.action.available_function.available_dll.name 33 | 34 | #version 1; facility 699; severity scaled, rounded, and reversed to 0-7 integer range 35 | message = "1 699 " + (7 - [[0,self.action.severity].max, 3999].min / 4000.0 * 8).floor.to_s 36 | 37 | #rfc 3339 time format; hostname; sender name; sender inst 38 | message << " #{self.updated_at.strftime('%FT%T')} #{cleanSyslog(self.computer)} ambush - " 39 | 40 | #message, with unfiltered string values, in JSON 41 | message + ActiveSupport::JSON.encode({:computer => self.computer, :count => self.count, 42 | :ip => self.ip, :module => self.module, :pid => self.pid, :process => self.process, :user => self.user, 43 | :name => self.action.name, :signature_set => self.action.signature_set_id, :created_at => self.created_at, 44 | :updated_at => self.updated_at, :severity => self.action.severity, 45 | :dll => dllname, :function => self.action.available_function.name, 46 | :args => self.display}) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /client/apihook/apihookx86.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /////////////////////////////////////////////////////////////////////////////////////////// 3 | // This file defines x86-specific code for dynamically-generated code, etc. 4 | /////////////////////////////////////////////////////////////////////////////////////////// 5 | 6 | #define GET_PEB "\x64\xa1\x30\x00\x00\x00\xc3" //mov eax,[fs:0x30] ret 7 | 8 | #define SET_EAX "\x59\x58\xff\xe1" // pop ecx, pop eax, jmp ecx 9 | 10 | #define GET_HOOK_ARG "\x89\xc8\xc3\x00" // mov eax, ecx; ret 11 | 12 | #define STACK_FIXUP "\x5f\x5f\x5e\x5b\x59\xc2" //pop edi; pop edi; pop esi; pop ebx; pop ecx; ret [amount] 13 | //for hook function tail: pop edi; pop edi; pop esi; pop ebx; mov esp,ebp; pop ebp; ret [amount] 14 | 15 | #define POP_RET_ONE "\x5f\x5f\x5e\xc2\x04\x00" //pop edi; pop edi; pop esi; ret 4 16 | #define POP_RET_THREE "\x5f\x5f\x5e\xc2\x0c\x00" //pop edi; pop edi; pop esi; ret C 17 | 18 | #define CALL_API "\x8b\x54\x24\x04\x8b\x4c\x24\x08\x8b\x44\x24\x0c\x53\x85\xc9\x74\x09\x49\x8b\x1c\x8a\x53\x85\xc9\x75\xf7\xff\xd0\x5b\xc2\x0c\x00" 19 | /* //callApi: takes pointer to function args, count of args and function pointer, and makes the call 20 | mov edx, [esp+4] // args 21 | mov ecx, [esp+8] // count 22 | mov eax, [esp+12]// func 23 | push ebx 24 | 25 | test ecx,ecx // while count != 0 26 | jz done // 27 | loop: 28 | dec ecx // count-- 29 | mov ebx, [edx+ecx*4] //get args[count] 30 | push ebx 31 | test ecx,ecx 32 | jnz loop 33 | 34 | done: 35 | call eax // call function 36 | pop ebx 37 | ret 12 38 | */ 39 | 40 | // mov ecx, arg; mov edx, hook; jmp edx 41 | #pragma pack(1) 42 | typedef struct sHOOKAPI_SPRINGBOARD 43 | { 44 | unsigned char movEcxOpcode; 45 | void* argument; 46 | unsigned char movEdxOpcode; 47 | void* hookAddress; 48 | unsigned short int jmpEdx; 49 | } HOOKAPI_SPRINGBOARD, *PHOOKAPI_SPRINGBOARD; 50 | 51 | inline PHOOKAPI_SPRINGBOARD getSpringboard(void* args, void* hook, HANDLE rwxHeap){ 52 | //Get memory for springboard 53 | HOOKAPI_SPRINGBOARD* springboard = (HOOKAPI_SPRINGBOARD*)HeapAlloc(rwxHeap, 0, sizeof(HOOKAPI_SPRINGBOARD)); 54 | if(springboard == NULL) 55 | return NULL; 56 | 57 | //Now make springboard code 58 | //Stores mov ecx, funcaddr mov edx, hookaddr jmp edx 59 | //(ecx and edx are caller saved) 60 | springboard->movEcxOpcode = 0xb9; 61 | springboard->argument = args; // mov ecx, argument 62 | springboard->movEdxOpcode = 0xba; 63 | springboard->hookAddress = hook; // mov edx, hookaddr 64 | springboard->jmpEdx = 0xe2ff; // jmp edx 65 | return springboard; 66 | } 67 | -------------------------------------------------------------------------------- /server/app/models/available_function.rb: -------------------------------------------------------------------------------- 1 | class AvailableFunction < ActiveRecord::Base 2 | belongs_to :available_dll 3 | has_many :parameters, :dependent => :destroy 4 | has_many :actions, :dependent => :destroy 5 | 6 | # Either get a function or create a new one if it is changed 7 | def self.find_or_create(funcname, funcparams, dll) 8 | newFunc = false 9 | func = AvailableFunction.where("decl IS NOT NULL").find(:first, :conditions => 10 | {'available_dll_id' => dll.id, 'name' => funcname}) 11 | 12 | #Check if we need to make a new one - if it wasn't found or params have changed 13 | paramtypes = ['?', 'integer', '?', 'c string', 'wide-char string', 'pointer', '?', 'blob'] 14 | if func != nil 15 | parameters = func.parameters.all(:order => 'num') 16 | changed = parameters.length != funcparams.length 17 | funcparams.each_with_index do |fp, i| 18 | break if not fp.has_key? 'name' # standard function - no param info is provided 19 | 20 | if parameters[i] == nil or parameters[i].name != fp['name'] or 21 | parameters[i].paramtype != paramtypes.index(fp['paramtype']) 22 | changed = true 23 | break 24 | end 25 | end 26 | return func if not changed # no need to continue if no change 27 | end 28 | 29 | #make a new func 30 | func = AvailableFunction.new(:name => funcname, :available_dll => dll) 31 | func.save 32 | 33 | #add params 34 | funcparams.each_with_index do |fp, i| 35 | p = Parameter.new(:name => ActionController::Base.helpers.strip_tags(fp['name']), 36 | :num => i+1, :available_function => func) 37 | p.paramtype = paramtypes.index(fp['paramtype']) 38 | raise "Error - invalid parameter type; try one of these:\n#{fp.inspect}" if p.paramtype == nil 39 | 40 | if fp['type'] == 'Blob' #must give blob length 41 | p.arg = fp['blobval'] if fp['subtype'] == 'ARG' 42 | p.size = fp['blobval'] if fp['subtype'] == 'VAL' 43 | 44 | # simplified format uses 'size argument' or 'size' 45 | p.arg = fp['size argument'] if fp.has_key? 'size argument' 46 | p.size = fp['size'] if fp.has_key? 'size' 47 | end 48 | p.save 49 | end 50 | func 51 | end 52 | 53 | def compiled(ssid) 54 | #get actions 55 | ssid = SignatureSet.first.id if ssid == nil 56 | actions = Action.where(:available_function_id => self.id, :signature_set_id => ssid) 57 | return '' if actions.length == 0 58 | 59 | #setup name 60 | fname = self.name + ("\x00"*(4-(self.name.length % 4))) 61 | params = self.parameters.all(:order => 'num') 62 | out = [params.length, actions.length, fname.length].pack("V*") + fname 63 | actions.each do |action| 64 | out << action.compiled 65 | end 66 | params.each do |parameter| 67 | out << parameter.compiled 68 | end 69 | # size, numArgs, numActions, nameLen, name[], actions[], parameters[] 70 | [out.size+4].pack("V*") + out 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /client/apihook/apihookx64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /////////////////////////////////////////////////////////////////////////////////////////// 3 | // This file defines x64-specific code for dynamically-generated code, etc. 4 | /////////////////////////////////////////////////////////////////////////////////////////// 5 | 6 | #define GET_PEB "\x65\x48\x8b\x04\x25\x60\x00\x00\x00\xc3" // mov rax, [gs:96]; ret 7 | 8 | #define SET_EAX "\x48\x89\xc8\xc3" // mov rax, rcx; ret 9 | 10 | #define STACK_FIXUP "\xc3" //ret; Caller-cleaned stack on x64. YAY! 11 | 12 | #define GET_HOOK_ARG "\x4c\x89\xd0\xc3" // mov rax, r10; ret 13 | 14 | #define POP_RET_ONE "\xc3" // ret; Caller-cleaned stack on x64. YAY! 15 | #define POP_RET_THREE POP_RET_ONE 16 | 17 | #define CALL_API "\x53\x48\x89\xd3\x48\x83\xec\x20\x48\x85\xd2\x74\x0d\x48\xff\xca\x48\x8b\x04\xd1\x50\x48\x85\xd2\x75\xf3\x4c\x89\xc0\x48\x8b\x0c\x24\x48\x8b\x54\x24\x08\x4c\x8b\x44\x24\x10\x4c\x8b\x4c\x24\x18\xff\xd0\x48\x85\xdb\x74\x09\x5a\x48\xff\xcb\x48\x85\xdb\x75\xf7\x48\x83\xc4\x20\x5b\xc3" 18 | /* //callApi: takes pointer to function args, count of args and function pointer, and makes the call 19 | // rcx = args 20 | // rdx = count 21 | // r8 = func 22 | push rbx 23 | mov rbx, rdx 24 | sub rsp, 0x20 25 | 26 | test rdx,rdx // while count != 0 27 | jz done 28 | 29 | loop: 30 | dec rdx // count-- 31 | mov rax, [rcx+rdx*8] //get args[count] 32 | push rax 33 | test rdx,rdx 34 | jnz loop 35 | 36 | done: 37 | mov rax, r8 // rax = func 38 | 39 | // set up registers 40 | mov rcx, [rsp] 41 | mov rdx, [rsp+8] 42 | mov r8, [rsp+0x10] 43 | mov r9, [rsp+0x18] 44 | call rax // call function 45 | // clean up. :-( 46 | 47 | test rbx,rbx // while count-- != 0 48 | jz doret 49 | 50 | restoreloop: 51 | pop rdx 52 | dec rbx 53 | test rbx,rbx 54 | jnz restoreloop 55 | 56 | doret: 57 | add rsp, 0x20 58 | pop rbx 59 | ret 60 | */ 61 | 62 | #pragma pack(1) 63 | typedef struct sHOOKAPI_SPRINGBOARD 64 | { 65 | unsigned short movR10Opcode; 66 | void* argument; 67 | unsigned short movR11Opcode; 68 | void* hookAddress; 69 | unsigned int jmpR11; 70 | } HOOKAPI_SPRINGBOARD, *PHOOKAPI_SPRINGBOARD; 71 | 72 | inline PHOOKAPI_SPRINGBOARD getSpringboard(void* args, void* hook, HANDLE rwxHeap){ 73 | //Get memory for springboard 74 | HOOKAPI_SPRINGBOARD* springboard = (HOOKAPI_SPRINGBOARD*)HeapAlloc(rwxHeap, 0, sizeof(HOOKAPI_SPRINGBOARD)); 75 | if(springboard == NULL) 76 | return NULL; 77 | 78 | //Now make springboard code 79 | //(r10 and r11 are caller saved) 80 | springboard->movR10Opcode = 0xba49; 81 | springboard->argument = args; // mov r10, argument 82 | springboard->movR11Opcode = 0xbb49; 83 | springboard->hookAddress = hook; // mov r11, hookaddr 84 | springboard->jmpR11 = '\x41\xff\xe3\x00'; // jmp r11 85 | return springboard; 86 | } 87 | -------------------------------------------------------------------------------- /client/apihook/asm/apc64.asm: -------------------------------------------------------------------------------- 1 | ;-----------------------------------------------------------------------------; 2 | ; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) 3 | ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4 4 | ; Architecture: x64 5 | ; Version: 2.0 (March 2010) 6 | ; Size: 323 bytes 7 | ; Build: >build.py apc 8 | ;-----------------------------------------------------------------------------; 9 | 10 | ; A small stub to be used for thread injection where we gain execution via an injected APC. See the 11 | ; file "\msf3\external\source\meterpreter\source\common\arch\win\i386\base_inject.c" for more details 12 | 13 | ;typedef struct _APCCONTEXT 14 | ;{ 15 | ; union 16 | ; { 17 | ; LPVOID lpStartAddress; 18 | ; BYTE bPadding1[8]; 19 | ; } s; 20 | ; union 21 | ; { 22 | ; LPVOID lpParameter; 23 | ; BYTE bPadding2[8]; 24 | ; } p; 25 | ; BYTE bExecuted; 26 | ;} APCCONTEXT, * LPAPCCONTEXT; 27 | 28 | [BITS 64] 29 | [ORG 0] 30 | 31 | cld ; Clear the direction flag. 32 | cmp byte [rcx+16], 0 ; Has this context allready been injected? 'if( ctx->bExecuted == FALSE )' 33 | jne cleanup ; If so just leave this APC 34 | mov byte [rcx+16], 1 ; Otherwise mark the context as executed and proceed 35 | sub rsp, 120 ; Alloc some space on stack 36 | call start ; Call start, this pushes the address of 'api_call' onto the stack. 37 | delta: ; 38 | %include "./src/block/block_api.asm" ; 39 | start: ; 40 | pop rbp ; Pop off the address of 'api_call' for calling later. 41 | xor rdx, rdx ; zero RDX 42 | mov rax, [gs:rdx+48] ; Get the current TEB 43 | cmp qword [rax+712], rdx ; Is the TEB ActivationContextStackPointer pointer NULL? 44 | jne continue ; If there already is an ActivationContext structure setup, just continue 45 | lea rdx, [rbp+context-delta] ; calculate the address of our dummy ActivationContext 46 | mov qword [rax+712], rdx ; and set the address of our dummy ActivationContext in the current TEB 47 | continue: 48 | mov r8, [rcx] ; r8 = ctx->lpStartAddress 49 | mov r9, [rcx+8] ; r9 = ctx->lpParameter 50 | xor rcx, rcx ; Clear ECX, lpThreadAttributes 51 | xor rdx, rdx ; Clear EDX, dwStackSize 52 | push rcx ; lpThreadId 53 | push rcx ; dwCreationFlags 54 | mov r10d, 0x160D6838 ; hash( "kernel32.dll", "CreateThread" ) 55 | call rbp ; CreateThread( NULL, 0, ctx->lpStartAddress, ctx->lpParameter, 0, NULL ); 56 | add rsp, (120 + 32 + (8*2)) ; fix up stack (120 bytes we alloced, 32 bytes for the single call to api_call, and 2*8 bytes for the two params we pushed). 57 | cleanup: 58 | ret ; Return and finish our APC routine. 59 | context: 60 | TIMES 0x24 db 0 ; An empty ntdll!_ACTIVATION_CONTEXT_STACK structure -------------------------------------------------------------------------------- /client/apihook/apihook.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "afxres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (U.S.) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | #ifdef _WIN32 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | #pragma code_page(1252) 22 | #endif //_WIN32 23 | 24 | #ifdef APSTUDIO_INVOKED 25 | ///////////////////////////////////////////////////////////////////////////// 26 | // 27 | // TEXTINCLUDE 28 | // 29 | 30 | 1 TEXTINCLUDE 31 | BEGIN 32 | "resource.h\0" 33 | END 34 | 35 | 2 TEXTINCLUDE 36 | BEGIN 37 | "#include ""afxres.h""\r\n" 38 | "\0" 39 | END 40 | 41 | 3 TEXTINCLUDE 42 | BEGIN 43 | "\r\n" 44 | "\0" 45 | END 46 | 47 | #endif // APSTUDIO_INVOKED 48 | 49 | 50 | ///////////////////////////////////////////////////////////////////////////// 51 | // 52 | // Version 53 | // 54 | 55 | VS_VERSION_INFO VERSIONINFO 56 | FILEVERSION 1,0,0,0 57 | PRODUCTVERSION 1,0,0,0 58 | FILEFLAGSMASK 0x17L 59 | #ifdef _DEBUG 60 | FILEFLAGS 0x1L 61 | #else 62 | FILEFLAGS 0x0L 63 | #endif 64 | FILEOS 0x4L 65 | FILETYPE 0x2L 66 | FILESUBTYPE 0x0L 67 | BEGIN 68 | BLOCK "StringFileInfo" 69 | BEGIN 70 | BLOCK "040904b0" 71 | BEGIN 72 | VALUE "CompanyName", "Scriptjunkie Software" 73 | VALUE "FileDescription", "Ambush API Hook DLL" 74 | VALUE "FileVersion", "1, 0, 0, 0" 75 | VALUE "InternalName", "apihook" 76 | VALUE "LegalCopyright", "Copyright (C) Matthew Weeks 2011" 77 | #ifdef _M_X64 78 | VALUE "OriginalFilename", "apihook64.dll" 79 | #else 80 | VALUE "OriginalFilename", "apihook.dll" 81 | #endif 82 | VALUE "ProductName", "Ambush Host Intrusion Prevention System" 83 | VALUE "ProductVersion", "1, 0, 0, 0" 84 | END 85 | END 86 | BLOCK "VarFileInfo" 87 | BEGIN 88 | VALUE "Translation", 0x409, 1200 89 | END 90 | END 91 | 92 | #endif // English (U.S.) resources 93 | ///////////////////////////////////////////////////////////////////////////// 94 | 95 | 96 | 97 | #ifndef APSTUDIO_INVOKED 98 | ///////////////////////////////////////////////////////////////////////////// 99 | // 100 | // Generated from the TEXTINCLUDE 3 resource. 101 | // 102 | 103 | 104 | ///////////////////////////////////////////////////////////////////////////// 105 | #endif // not APSTUDIO_INVOKED 106 | 107 | -------------------------------------------------------------------------------- /server/app/views/signature_sets/regexinfo.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
3 |
Regular Expressions
4 |
5 |

All process and module blacklists and whitelists and string argument restrictions in Ambush are regular expressions. This means that with a single expression you can specify a wide variety of restrictions, but mistakes are easy to make.

6 |

Use

7 |

  • Blacklists and whitelists have one regular expression per line. Ambush will combine each regular expression into the complete blacklist (or whitelist).
  • 8 |
  • Blacklists and whitelists will be applied case-insensitively, but argument restrictions will be case-sensitive.
  • 9 |
  • The regular expressions will match any portion of the string or path unless you start your regular expression with ^ to only match at the beginning or $ to only match at the end.
  • 10 |

11 |

Examples

12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
Regular ExpressionMatchesDoes not match
chrome.exeC:\Users\Bob\Appdata\Local\Google\Chrome\Application\chrome.exeC:\Temp\bhrome.exe
C:\Temp\chromezexe.txt
C:\Temp\zzzchrome.exe.bat
[abc]hrome\.exeC:\Users\Bob\Appdata\Local\Google\Chrome\Application\chrome.exeC:\Temp\chromezexe.txt
C:\Temp\zzzchrome.exe.bat
C:\Temp\bhrome.exe
\\chrome\.exe$C:\Users\Bob\Appdata\Local\Google\Chrome\Application\chrome.exeC:\Temp\chromezexe.txt
C:\Temp\zzzchrome.exe.bat
chrome\d\.exechrome1.exechromea.exe
27 |

Syntax

28 |
      ^               Match beginning of a buffer
29 |       $               Match end of a buffer
30 |       ()              Grouping and substring capturing
31 |       [...]           Match any character from set
32 |       [^...]          Match any character but ones from set
33 |       \s              Match whitespace
34 |       \S              Match non-whitespace
35 |       \d              Match decimal digit
36 |       \r              Match carriage return
37 |       \n              Match newline
38 |       +               Match one or more times (greedy)
39 |       +?              Match one or more times (non-greedy)
40 |       *               Match zero or more times (greedy)
41 |       *?              Match zero or more times (non-greedy)
42 |       ?               Match zero or once
43 |       \xDD            Match byte with hex value 0xDD
44 |       \meta           Match one of the meta character: ^$().[*+?\
45 |       
46 |
47 |
48 |
49 | Ok 50 |
51 | -------------------------------------------------------------------------------- /server/config/routes.rb: -------------------------------------------------------------------------------- 1 | Ambush::Application.routes.draw do 2 | root :to => "signature_sets#index" 3 | get "available_functions/list" 4 | 5 | get "dll/new" 6 | 7 | get "dll/delete" 8 | match "signature_sets/:id/adm" => "signature_sets#adm" 9 | match "signature_sets/:id/regcmd" => "signature_sets#regcmd" 10 | match "signature_sets/:id/compiled" => "signature_sets#compiled" 11 | match "signature_sets/:id/signature" => "signature_sets#signature" 12 | match "signature_sets/:id/yaml" => "signature_sets#yaml" 13 | match "compiled" => "signature_sets#compiled", :id => 1 14 | match "alerts/clear" => "alerts#clear" 15 | 16 | match 'signup' => 'users#new', :as => :signup 17 | match 'logout' => 'sessions#destroy' 18 | match 'login' => 'sessions#new' 19 | match 'documentation/regex' => 'signature_sets#regexinfo' 20 | match 'installer_sig' => 'signature_sets#installer_sig' 21 | 22 | resources :signature_sets 23 | resources :condition 24 | resources :actions 25 | resources :alerts 26 | resources :available_dll 27 | resources :available_function 28 | resources :sessions 29 | resources :users 30 | 31 | # The priority is based upon order of creation: 32 | # first created -> highest priority. 33 | 34 | # Sample of regular route: 35 | # match 'products/:id' => 'catalog#view' 36 | # Keep in mind you can assign values other than :controller and :action 37 | 38 | # Sample of named route: 39 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase 40 | # This route can be invoked with purchase_url(:id => product.id) 41 | 42 | # Sample resource route (maps HTTP verbs to controller actions automatically): 43 | # resources :products 44 | 45 | # Sample resource route with options: 46 | # resources :products do 47 | # member do 48 | # get 'short' 49 | # post 'toggle' 50 | # end 51 | # 52 | # collection do 53 | # get 'sold' 54 | # end 55 | # end 56 | 57 | # Sample resource route with sub-resources: 58 | # resources :products do 59 | # resources :comments, :sales 60 | # resource :seller 61 | # end 62 | 63 | # Sample resource route with more complex sub-resources 64 | # resources :products do 65 | # resources :comments 66 | # resources :sales do 67 | # get 'recent', :on => :collection 68 | # end 69 | # end 70 | 71 | # Sample resource route within a namespace: 72 | # namespace :admin do 73 | # # Directs /admin/products/* to Admin::ProductsController 74 | # # (app/controllers/admin/products_controller.rb) 75 | # resources :products 76 | # end 77 | 78 | # You can have the root of your site routed with "root" 79 | # just remember to delete public/index.html. 80 | # root :to => 'welcome#index' 81 | 82 | # See how all your routes lay out with "rake routes" 83 | 84 | # This is a legacy wild controller route that's not recommended for RESTful applications. 85 | # Note: This route will make all actions in every controller accessible via GET requests. 86 | # match ':controller(/:action(/:id(.:format)))' 87 | end 88 | -------------------------------------------------------------------------------- /client/apihook/asm/executex64.asm: -------------------------------------------------------------------------------- 1 | ;-----------------------------------------------------------------------------; 2 | ; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) 3 | ; Compatible: Windows 7, 2008, Vista, 2003, XP 4 | ; Architecture: wow64 5 | ; Version: 1.0 (Jan 2010) 6 | ; Size: 75 bytes 7 | ; Build: >build.py executex64 8 | ;-----------------------------------------------------------------------------; 9 | 10 | ; A simple function to execute native x64 code from a wow64 (x86) process. 11 | ; Can be called from C using the following prototype: 12 | ; typedef DWORD (WINAPI * EXECUTEX64)( X64FUNCTION pFunction, DWORD dwParameter ); 13 | ; The native x64 function you specify must be in the following form (as well as being x64 code): 14 | ; typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter ); 15 | 16 | ; Clobbers: EAX, ECX and EDX (ala the normal stdcall calling convention) 17 | ; Un-Clobbered: EBX, ESI, EDI, ESP and EBP can be expected to remain un-clobbered. 18 | 19 | [BITS 32] 20 | 21 | WOW64_CODE_SEGMENT EQU 0x23 22 | X64_CODE_SEGMENT EQU 0x33 23 | 24 | start: 25 | push ebp ; prologue, save EBP... 26 | mov ebp, esp ; and create a new stack frame 27 | push esi ; save the registers we shouldn't clobber 28 | push edi ; 29 | mov esi, [ebp+8] ; ESI = pFunction 30 | mov ecx, [ebp+12] ; ECX = dwParameter 31 | call delta ; 32 | delta: 33 | pop eax ; 34 | add eax, (native_x64-delta) ; get the address of native_x64 35 | 36 | sub esp, 8 ; alloc some space on stack for far jump 37 | mov edx, esp ; EDX will be pointer our far jump 38 | mov dword [edx+4], X64_CODE_SEGMENT ; set the native x64 code segment 39 | mov dword [edx], eax ; set the address we want to jump to (native_x64) 40 | 41 | call go_all_native ; perform the transition into native x64 and return here when done. 42 | 43 | add esp, (8+4+8) ; remove the 8 bytes we allocated + the return address which was never popped off + the qword pushed from native_x64 44 | pop edi ; restore the clobbered registers 45 | pop esi ; 46 | pop ebp ; restore EBP 47 | retn (4*2) ; return to caller (cleaning up our two function params) 48 | 49 | go_all_native: 50 | mov edi, [esp] ; EDI is the wow64 return address 51 | jmp dword far [edx] ; perform the far jump, which will return to the caller of go_all_native 52 | 53 | native_x64: 54 | [BITS 64] ; we are now executing native x64 code... 55 | xor rax, rax ; zero RAX 56 | push rdi ; save RDI (EDI being our wow64 return address) 57 | call rsi ; call our native x64 function (the param for our native x64 function is allready in RCX) 58 | pop rdi ; restore RDI (EDI being our wow64 return address) 59 | push rax ; simply push it to alloc some space 60 | mov dword [rsp+4], WOW64_CODE_SEGMENT ; set the wow64 code segment 61 | mov dword [rsp], edi ; set the address we want to jump to (the return address from the go_all_native call) 62 | jmp dword far [rsp] ; perform the far jump back to the wow64 caller... 63 | -------------------------------------------------------------------------------- /client/apihook/slre.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2005 Sergey Lyubka 3 | * All rights reserved 4 | * 5 | * "THE BEER-WARE LICENSE" (Revision 42): 6 | * Sergey Lyubka wrote this file. As long as you retain this notice you 7 | * can do whatever you want with this stuff. If we meet some day, and you think 8 | * this stuff is worth it, you can buy me a beer in return. 9 | */ 10 | 11 | /* 12 | * This is a regular expression library that implements a subset of Perl RE. 13 | * Please refer to http://slre.sourceforge.net for detailed description. 14 | * 15 | * Usage example (parsing HTTP request): 16 | * 17 | * struct slre slre; 18 | * struct cap captures[4 + 1]; // Number of braket pairs + 1 19 | * ... 20 | * 21 | * slre_compile(&slre,"^(GET|POST) (\S+) HTTP/(\S+?)\r\n"); 22 | * 23 | * if (slre_match(&slre, buf, len, captures)) { 24 | * printf("Request line length: %d\n", captures[0].len); 25 | * printf("Method: %.*s\n", captures[1].len, captures[1].ptr); 26 | * printf("URI: %.*s\n", captures[2].len, captures[2].ptr); 27 | * } 28 | * 29 | * Supported syntax: 30 | * ^ Match beginning of a buffer 31 | * $ Match end of a buffer 32 | * () Grouping and substring capturing 33 | * [...] Match any character from set 34 | * [^...] Match any character but ones from set 35 | * \s Match whitespace 36 | * \S Match non-whitespace 37 | * \d Match decimal digit 38 | * \r Match carriage return 39 | * \n Match newline 40 | * + Match one or more times (greedy) 41 | * +? Match one or more times (non-greedy) 42 | * * Match zero or more times (greedy) 43 | * *? Match zero or more times (non-greedy) 44 | * ? Match zero or once 45 | * \xDD Match byte with hex value 0xDD 46 | * \meta Match one of the meta character: ^$().[*+?\ 47 | */ 48 | 49 | #ifndef SLRE_HEADER_DEFINED 50 | #define SLRE_HEADER_DEFINED 51 | 52 | /* 53 | * Compiled regular expression 54 | */ 55 | struct slre { 56 | unsigned char code[256]; 57 | unsigned char data[256]; 58 | int code_size; 59 | int data_size; 60 | int num_caps; /* Number of bracket pairs */ 61 | int anchored; /* Must match from string start */ 62 | const char *err_str; /* Error string */ 63 | }; 64 | 65 | /* 66 | * Captured substring 67 | */ 68 | struct cap { 69 | const char *ptr; /* Pointer to the substring */ 70 | int len; /* Substring length */ 71 | }; 72 | 73 | /* 74 | * Compile regular expression. If success, 1 is returned. 75 | * If error, 0 is returned and slre.err_str points to the error message. 76 | */ 77 | int slre_compile(struct slre *, const char *re); 78 | 79 | /* 80 | * Return 1 if match, 0 if no match. 81 | * If `captured_substrings' array is not NULL, then it is filled with the 82 | * values of captured substrings. captured_substrings[0] element is always 83 | * a full matched substring. The round bracket captures start from 84 | * captured_substrings[1]. 85 | * It is assumed that the size of captured_substrings array is enough to 86 | * hold all captures. The caller function must make sure it is! So, the 87 | * array_size = number_of_round_bracket_pairs + 1 88 | */ 89 | int slre_match(const struct slre *, const char *buf, int buf_len, 90 | struct cap *captured_substrings); 91 | 92 | #endif /* SLRE_HEADER_DEFINED */ -------------------------------------------------------------------------------- /client/apihook/asm/apc32.asm: -------------------------------------------------------------------------------- 1 | ;-----------------------------------------------------------------------------; 2 | ; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) 3 | ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4 4 | ; Architecture: x86 (but not wow64) 5 | ; Version: 2.0 (March 2010) 6 | ; Size: 244 bytes 7 | ; Build: >build.py apc 8 | ;-----------------------------------------------------------------------------; 9 | 10 | ; A small stub to be used for thread injection where we gain execution via an injected APC. See the 11 | ; file "\msf3\external\source\meterpreter\source\common\arch\win\i386\base_inject.c" for more details 12 | 13 | ;typedef struct _APCCONTEXT 14 | ;{ 15 | ; union 16 | ; { 17 | ; LPVOID lpStartAddress; 18 | ; BYTE bPadding1[8]; 19 | ; } s; 20 | ; union 21 | ; { 22 | ; LPVOID lpParameter; 23 | ; BYTE bPadding2[8]; 24 | ; } p; 25 | ; BYTE bExecuted; 26 | ;} APCCONTEXT, * LPAPCCONTEXT; 27 | 28 | [BITS 32] 29 | [ORG 0] 30 | 31 | cld ; Clear the direction flag. 32 | mov esi, [esp+4] ; ESI is a pointer to our apc stub context 33 | push ebp ; Prologue, save EBP... 34 | mov ebp, esp ; And create a new stack frame 35 | call start ; Call start, this pushes the address of 'api_call' onto the stack. 36 | delta: ; 37 | %include "./src/block/block_api.asm" ; 38 | start: ; 39 | pop ebx ; Pop off the address of 'api_call' for calling later. 40 | cmp byte [esi+16], 0 ; Has this context allready been injected 41 | jne cleanup ; If so just leave this APC 42 | mov byte [esi+16], 1 ; Otherwise mark the context as executed and proceed 43 | push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" ) 44 | call ebx ; GetVersion(); (AL will = major version and AH will = minor version) 45 | cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7 46 | jl short continue ; then continue to CreateThread... otherwise we must create a dummy thread ActivationContext 47 | xor ecx, ecx ; zero ECX 48 | mov eax, [fs:ecx+24] ; Get the current TEB 49 | cmp dword [eax+424], ecx ; Is the TEB ActivationContextStackPointer pointer NULL? 50 | jne continue ; If there already is an ActivationContext structure setup, just continue 51 | lea edx, [ebx+context-delta] ; calculate the address of our dummy ActivationContext 52 | mov dword [eax+424], edx ; and set the address of our dummy ActivationContext in the current TEB 53 | continue: 54 | xor ecx, ecx ; Clear ECX 55 | push ecx ; lpThreadId 56 | push ecx ; dwCreationFlags 57 | push dword [esi+8] ; ctx->lpParameter 58 | push dword [esi] ; ctx->lpStartAddress 59 | push ecx ; dwStackSize 60 | push ecx ; lpThreadAttributes 61 | push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" ) 62 | call ebx ; CreateThread( NULL, 0, ctx->lpStartAddress, ctx->lpParameter, 0, NULL ); 63 | cleanup: 64 | leave ; epilogue 65 | retn 12 ; Return (cleaning up stack params) and finish our APC routine. 66 | context: 67 | TIMES 0x18 db 0 ; An empty ntdll!_ACTIVATION_CONTEXT_STACK structure -------------------------------------------------------------------------------- /client/apihook/asm/remotethread.asm: -------------------------------------------------------------------------------- 1 | ;-----------------------------------------------------------------------------; 2 | ; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) 3 | ; Compatible: Windows 7, 2008R2, 2008, 2003, XP 4 | ; Architecture: x64 5 | ; Version: 1.0 (Jan 2010) 6 | ; Size: 296 bytes 7 | ; Build: >build.py remotethread 8 | ;-----------------------------------------------------------------------------; 9 | 10 | ; Function to create a remote thread via ntdll!RtlCreateUserThread, used with the x86 executex64 stub. 11 | 12 | ; This function is in the form (where the param is a pointer to a WOW64CONTEXT): 13 | ; typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter ); 14 | 15 | ;typedef struct _WOW64CONTEXT 16 | ;{ 17 | ; union 18 | ; { 19 | ; HANDLE hProcess; 20 | ; BYTE bPadding2[8]; 21 | ; } h; 22 | ; union 23 | ; { 24 | ; LPVOID lpStartAddress; 25 | ; BYTE bPadding1[8]; 26 | ; } s; 27 | ; union 28 | ; { 29 | ; LPVOID lpParameter; 30 | ; BYTE bPadding2[8]; 31 | ; } p; 32 | ; union 33 | ; { 34 | ; HANDLE hThread; 35 | ; BYTE bPadding2[8]; 36 | ; } t; 37 | ;} WOW64CONTEXT, * LPWOW64CONTEXT; 38 | 39 | [BITS 64] 40 | [ORG 0] 41 | cld ; Clear the direction flag. 42 | mov rsi, rcx ; RCX is a pointer to our WOW64CONTEXT parameter 43 | mov rdi, rsp ; save RSP to RDI so we can restore it later, we do this as we are going to force alignment below... 44 | and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned (as we originate from a wow64 (x86) process we cant guarantee alignment) 45 | call start ; Call start, this pushes the address of 'api_call' onto the stack. 46 | delta: ; 47 | %include "./src/block/block_api.asm" 48 | start: ; 49 | pop rbp ; Pop off the address of 'api_call' for calling later. 50 | ; setup the parameters for RtlCreateUserThread... 51 | xor r9, r9 ; StackZeroBits = 0 52 | push r9 ; ClientID = NULL 53 | lea rax, [rsi+24] ; RAX is now a pointer to ctx->t.hThread 54 | push rax ; ThreadHandle = &ctx->t.hThread 55 | push qword [rsi+16] ; StartParameter = ctx->p.lpParameter 56 | push qword [rsi+8] ; StartAddress = ctx->s.lpStartAddress 57 | push r9 ; StackCommit = NULL 58 | push r9 ; StackReserved = NULL 59 | mov r8, 1 ; CreateSuspended = TRUE 60 | xor rdx, rdx ; SecurityDescriptor = NULL 61 | mov rcx, [rsi] ; ProcessHandle = ctx->h.hProcess 62 | ; perform the call to RtlCreateUserThread... 63 | mov r10d, 0x40A438C8 ; hash( "ntdll.dll", "RtlCreateUserThread" ) 64 | call rbp ; RtlCreateUserThread( ctx->h.hProcess, NULL, TRUE, 0, NULL, NULL, ctx->s.lpStartAddress, ctx->p.lpParameter, &ctx->t.hThread, NULL ) 65 | test rax, rax ; check the NTSTATUS return value 66 | jz success ; if its zero we have successfully created the thread so we should return TRUE 67 | mov rax, 0 ; otherwise we should return FALSE 68 | jmp cleanup ; 69 | success: 70 | mov rax, 1 ; return TRUE 71 | cleanup: 72 | add rsp, (32 + (8*6)) ; fix up stack (32 bytes for the single call to api_call, and 6*8 bytes for the six params we pushed). 73 | mov rsp, rdi ; restore the stack 74 | ret ; and return to caller 75 | -------------------------------------------------------------------------------- /client/config/config.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 27 | 30 | 33 | 36 | 39 | 42 | 53 | 56 | 59 | 62 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 94 | 95 | 96 | 97 | 98 | 103 | 106 | 107 | 110 | 111 | 112 | 117 | 120 | 121 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /server/app/controllers/alerts_controller.rb: -------------------------------------------------------------------------------- 1 | class AlertsController < ApplicationController 2 | before_filter :login_required, :except => :create 3 | 4 | # GET /alerts 5 | # GET /alerts.json 6 | def index 7 | @offset = (params[:offset] || 0).to_i 8 | @limit = (params[:limit] || 100).to_i 9 | if params[:time] 10 | @alerts = Alert.where('updated_at >= ?', Time.at(params[:time].to_f)).order('updated_at DESC') 11 | else 12 | @alerts = Alert.order('updated_at DESC').offset(@offset).limit(@limit) 13 | end 14 | 15 | respond_to do |format| 16 | format.html # index.html.erb 17 | format.json { 18 | if params[:raw] == 'true' 19 | render json: @alerts 20 | else 21 | rows = '' 22 | remove = {} 23 | @alerts.each do |alert| 24 | rows << alert.row(true) 25 | remove['a'+alert.id.to_s] = 1 if alert.created_at <= Time.at(params[:time].to_f) 26 | end 27 | render json: {:rows => rows, :lastUpdate => Time.now.to_f, :remove => remove } 28 | end 29 | } 30 | end 31 | end 32 | 33 | # GET /alerts/1 34 | # GET /alerts/1.json 35 | def show 36 | @alert = Alert.find(params[:id]) 37 | 38 | respond_to do |format| 39 | format.html # show.html.erb 40 | format.json { render json: @alert } 41 | end 42 | end 43 | 44 | # GET /alerts/clear 45 | def clear 46 | Alert.destroy_all 47 | respond_to do |format| 48 | format.html { redirect_to '/alerts', notice: 'Alerts have been cleared.' } 49 | format.json { redirect_to '/alerts', notice: 'Alerts have been cleared.' } 50 | end 51 | end 52 | 53 | # POST /alerts 54 | # POST /alerts.json 55 | def create 56 | count = request.body.read(4).unpack('V')[0] 57 | 1.upto(count) do 58 | #put together alert 59 | @alert = Alert.new 60 | size = request.body.read(4).unpack('V')[0] 61 | message = request.body.read(size - 4) 62 | begin 63 | aid, @alert.pid, @alert.count, argcount = message.slice!(0, 16).unpack('VVVV') 64 | act = Action.find(aid) 65 | @alert.action = act 66 | @alert.ip = request.remote_ip 67 | @alert.save 68 | 69 | #save parameters 70 | act.available_function.parameters.all(:order => 'num').each do |param| 71 | aa = AlertArg.new(@alert, message, param) 72 | end 73 | 74 | #get info about user/computer/process 75 | userlen = message.slice!(0, 4).unpack('V')[0] 76 | @alert.user = message.slice!(0, userlen).force_encoding("UTF-16LE").encode('UTF-8') 77 | computerlen = message.slice!(0, 4).unpack('V')[0] 78 | @alert.computer = message.slice!(0, computerlen).force_encoding("UTF-16LE").encode('UTF-8') 79 | proclen = message.slice!(0, 4).unpack('V')[0] 80 | @alert.process = message.slice!(0, proclen).force_encoding("UTF-16LE").encode('UTF-8') 81 | modlen = message.slice!(0, 4).unpack('V')[0] 82 | @alert.module = message.slice!(0, modlen).force_encoding("UTF-16LE").encode('UTF-8') 83 | 84 | #report to log aggregator if necessary 85 | @alert.action.signature_set.sendSyslog(@alert.toSyslog) 86 | 87 | #check for dups 88 | lastAlert = Alert.where(:pid => @alert.pid, :user => @alert.user, :action_id => aid, :ip => @alert.ip, 89 | :computer => @alert.computer).where('created_at > ?', Time.current - 3600).first 90 | if lastAlert and lastAlert.display == @alert.display 91 | lastAlert.count += @alert.count 92 | lastAlert.save 93 | @alert.destroy 94 | else 95 | @alert.save 96 | end 97 | rescue Exception => e 98 | Rails.logger.error e.message 99 | Rails.logger.error e.backtrace 100 | end 101 | end 102 | send_data '' 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /client/apihook/NCodeHook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "udis/types.h" 7 | #include "udis/extern.h" 8 | #include "udis/itab.h" 9 | 10 | typedef unsigned char * opcodeAddr; 11 | class ArchitectureCommon{ 12 | public: 13 | ArchitectureCommon() {}; 14 | ~ArchitectureCommon() {}; 15 | 16 | template 17 | int getMinOffset(opcodeAddr codePtr, unsigned int jumpPatchSize); 18 | virtual bool requiresAbsJump(opcodeAddr from, opcodeAddr to) { 19 | size_t jmpDistance = from > to ? from - to : to - from; 20 | return jmpDistance <= 0x7FFF0000 ? false : true; 21 | }; 22 | 23 | virtual void writeJump(opcodeAddr from, opcodeAddr to){ 24 | if (requiresAbsJump(from, to)) writeAbsJump(from, to); 25 | else writeNearJump(from, to); 26 | } 27 | 28 | virtual void writeNearJump(opcodeAddr from, opcodeAddr to) =0; 29 | virtual void writeAbsJump(opcodeAddr from, opcodeAddr to) =0; 30 | }; 31 | 32 | class ArchitectureIA32 : public ArchitectureCommon{ 33 | public: 34 | ArchitectureIA32() {}; 35 | ~ArchitectureIA32() {}; 36 | 37 | static const int DisasmMode = 32; 38 | static const unsigned int NearJumpPatchSize = sizeof(int) + 1; 39 | static const unsigned int AbsJumpPatchSize = sizeof(opcodeAddr) * 2 + 2; 40 | // max trampoline size = longest instruction (6) starting 1 byte before jump patch boundary 41 | static const unsigned int MaxTrampolineSize = AbsJumpPatchSize - 1 + 6; 42 | 43 | void writeNearJump(opcodeAddr from, opcodeAddr to) 44 | { 45 | unsigned char opcodes[NearJumpPatchSize]; 46 | int offset = (int)(to - from - NearJumpPatchSize); 47 | opcodes[0] = 0xE9; 48 | *((int*)&opcodes[1]) = offset; 49 | memcpy((void*)from, opcodes, NearJumpPatchSize); 50 | } 51 | 52 | void writeAbsJump(opcodeAddr from, opcodeAddr to) 53 | { 54 | unsigned char opcodes[AbsJumpPatchSize]; 55 | opcodes[0] = 0xFF; 56 | opcodes[1] = 0x25; 57 | *((opcodeAddr*)&opcodes[2]) = from + 6; 58 | *((opcodeAddr*)&opcodes[6]) = to; 59 | memcpy((void*)from, opcodes, AbsJumpPatchSize); 60 | } 61 | }; 62 | 63 | class ArchitectureX64 : public ArchitectureIA32{ 64 | public: 65 | ArchitectureX64() {}; 66 | ~ArchitectureX64() {}; 67 | 68 | static const int DisasmMode = 64; 69 | static const unsigned int NearJumpPatchSize = sizeof(int) + 1; 70 | static const unsigned int AbsJumpPatchSize = sizeof(int) + sizeof(opcodeAddr) + 2; 71 | static const unsigned int MaxTrampolineSize = AbsJumpPatchSize - 1 + 6; 72 | 73 | void writeAbsJump(opcodeAddr from, opcodeAddr to){ 74 | unsigned char opcodes[AbsJumpPatchSize]; 75 | opcodes[0] = 0xFF; 76 | opcodes[1] = 0x25; 77 | *((int*)&opcodes[2]) = 0; 78 | *((opcodeAddr*)&opcodes[2 + sizeof(int)]) = to; 79 | memcpy((void*)from, opcodes, AbsJumpPatchSize); 80 | }; 81 | }; 82 | 83 | template 84 | class NCodeHook{ 85 | public: 86 | 87 | NCodeHook(HANDLE rwxHeap = NULL); 88 | ~NCodeHook(); 89 | 90 | template bool createHook(U originalFunc, U hookFunc, U* hookFunctionAddr); 91 | 92 | private: 93 | // get rid of useless compiler warning C4512 by making operator= private 94 | NCodeHook& operator=(const NCodeHook&); 95 | 96 | opcodeAddr getPatchSite(opcodeAddr codePtr, unsigned int* patchSize, bool* useAbsJump, 97 | opcodeAddr hookFunc, opcodeAddr& nextBlock, int& branchOffset, int& branchSize, 98 | opcodeAddr& branchTarget, opcodeAddr*& swapAddr, unsigned short *& winapiPatchPoint); 99 | HANDLE trampolineHeap; 100 | const unsigned int MaxTotalTrampolineSize; 101 | ArchT architecture_; 102 | }; -------------------------------------------------------------------------------- /client/config/logparser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../apihook/signatures.h" 5 | #include "../apihook/apihook.h" 6 | using namespace std; 7 | 8 | void dumpLog(HANDLE inputHandle){ 9 | //First get time 10 | SYSTEMTIME systime; 11 | FILETIME filetime; 12 | DWORD read; 13 | if(ReadFile(inputHandle, &filetime, sizeof(filetime), &read, NULL) == FALSE || read != sizeof(filetime)){ 14 | cerr << "Invalid file - cannot read" << endl; 15 | return; 16 | } 17 | if(FileTimeToSystemTime(&filetime, &systime)) 18 | wcout << systime.wYear << "-" << systime.wMonth << "-" << systime.wDay << " " << systime.wHour 19 | << ":" << systime.wMinute << ":" << systime.wSecond << "." << systime.wMilliseconds; //get time 20 | 21 | // Then get full message 22 | HOOKAPI_MESSAGE message; 23 | if(ReadFile(inputHandle, &message, sizeof(message), &read, NULL) == FALSE || read != sizeof(message)){ 24 | cerr << "Invalid file - cannot read" << endl; 25 | return; 26 | } 27 | PBYTE contents = new BYTE[message.length + 2]; 28 | memcpy(contents, &message, sizeof(message)); 29 | // if length > size - position it will overflow 30 | if(message.length - sizeof(message) > GetFileSize(inputHandle, NULL) - SetFilePointer(inputHandle, 0, NULL, FILE_CURRENT)){ 31 | cerr << "Error! Invalid message length: " << message.length << endl; 32 | return; 33 | } 34 | if(ReadFile(inputHandle, contents + sizeof(message), message.length - sizeof(message), &read, NULL) == FALSE 35 | || read != message.length - sizeof(message)){ 36 | cerr << "Invalid file - cannot read" << endl; 37 | return; 38 | } 39 | wcout << " Type " << message.type << " pid " << message.pid << " count " << message.count << " numargs " << message.numArgs; 40 | 41 | //Handle string messages (error/start) 42 | PBYTE data = contents + sizeof(message); 43 | if(((int)message.type) < 0){ 44 | contents[message.length] = 0; 45 | contents[message.length + 1] = 0; 46 | if(message.type == START_INFO) 47 | wcout << " Process start"; 48 | else if(message.type == ERROR_INFO) 49 | wcout << " ERROR"; 50 | wcout << " " << (PWCHAR)data << endl; 51 | dumpLog(inputHandle); 52 | return; 53 | } 54 | 55 | //Now get args 56 | for(unsigned int i = 0; i < message.numArgs; i++){ 57 | //get value 58 | DWORD totallen = *((PDWORD)data); 59 | //Check length against total message length 60 | if(totallen + (data - contents) > message.length || (data - contents) < sizeof(DWORD)*2){ 61 | cerr << "Error! Invalid argument size" << endl; 62 | return; 63 | } 64 | DWORD datalen = totallen - sizeof(DWORD)*2; 65 | DWORD type = ((PDWORD)data)[1]; 66 | PCHAR val = (PCHAR)(data + sizeof(DWORD)*2); 67 | switch(type){ 68 | case DWORD_HOOK: 69 | wcout << " " << *((PDWORD)val); 70 | break; 71 | case CSTRING: 72 | { 73 | string valstring(val, datalen); 74 | cout << valstring << " "; 75 | break; 76 | } 77 | case WCSTRING: 78 | { 79 | wstring wvalstring((PWCHAR)val, datalen / sizeof(WCHAR)); 80 | wcout << wvalstring << " "; 81 | break; 82 | } 83 | case BLOB_HOOK: 84 | { 85 | string valstring(val, datalen); 86 | cout << valstring << " "; 87 | break; 88 | } 89 | } 90 | data = data + ((PDWORD)data)[0]; 91 | } 92 | 93 | //Get username, computername, exename, modname 94 | for(int i = 0; i < 4; i++){ 95 | DWORD wstringsize = ((PDWORD)data)[0]; 96 | //Check length against total message length 97 | if(wstringsize + (data - contents) > message.length || (data - contents) < sizeof(DWORD)){ 98 | cerr << "Error! Invalid wstring size" << endl; 99 | return; 100 | } 101 | data = data + sizeof(DWORD); 102 | wstring wstr((PWCHAR)data, wstringsize / sizeof(WCHAR)); 103 | wcout << " " << wstr; 104 | data = data + wstringsize; 105 | } 106 | delete [] contents; 107 | wcout << endl; 108 | dumpLog(inputHandle); //Recurse to go on 109 | } -------------------------------------------------------------------------------- /exampleSignatureSet.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1.01 3 | procblacklist: C:\\Users\\.*\\AppData\\Local\\Google\\Chrome\\Application\\chrome\.exe 4 | actions: 5 | - name: Break most shellcode - LoadLib 6 | action: block 7 | function: LoadLibraryA 8 | dll: Kernel32.dll 9 | arguments: 10 | - type: ignore 11 | retval: 0 12 | severity: high 13 | retprotectMode: PAGE_EXECUTE_READWRITE 14 | - name: WinExec 15 | action: alert 16 | function: WinExec 17 | dll: Kernel32.dll 18 | arguments: 19 | - type: ignore 20 | - type: ignore 21 | severity: medium 22 | - name: DEP Policy Disable 23 | action: alert 24 | function: SetProcessDEPPolicy 25 | dll: Kernel32.dll 26 | arguments: 27 | - type: integer 28 | val: 0 29 | severity: medium 30 | - name: Process Injection - WPM 31 | action: alert 32 | function: WriteProcessMemory 33 | dll: Kernel32.dll 34 | arguments: 35 | - type: not 36 | val: -1 37 | - type: ignore 38 | - type: ignore 39 | - type: ignore 40 | - type: ignore 41 | severity: medium 42 | - name: Stager - Wininet 43 | action: alert 44 | function: InternetReadFile 45 | dll: Wininet.dll 46 | arguments: 47 | - type: ignore 48 | - type: pointer 49 | mask type: any 50 | mask: 64 51 | - type: ignore 52 | - type: ignore 53 | severity: medium 54 | - name: Process Injection - Remote Thread 55 | action: alert 56 | function: CreateRemoteThread 57 | dll: Kernel32.dll 58 | arguments: 59 | - type: not 60 | val: -1 61 | - type: ignore 62 | - type: ignore 63 | - type: ignore 64 | - type: ignore 65 | - type: ignore 66 | - type: ignore 67 | severity: medium 68 | - name: Down/exec URL download 69 | action: block 70 | function: URLDownloadToFileA 71 | dll: Urlmon.dll 72 | arguments: 73 | - type: ignore 74 | name: pCaller 75 | paramtype: integer 76 | - type: ignore 77 | name: szURL 78 | paramtype: c string 79 | - type: ignore 80 | name: szFileName 81 | paramtype: c string 82 | - type: ignore 83 | name: dwReserved 84 | paramtype: integer 85 | - type: ignore 86 | name: lpfnCB 87 | paramtype: integer 88 | retval: 0 89 | severity: medium 90 | - name: Stager - Winsock 91 | action: alert 92 | function: recv 93 | dll: Ws2_32.dll 94 | arguments: 95 | - type: ignore 96 | name: s 97 | paramtype: integer 98 | - type: pointer 99 | mask type: any 100 | mask: 64 101 | name: buf 102 | paramtype: pointer 103 | - type: ignore 104 | name: len 105 | paramtype: integer 106 | - type: ignore 107 | name: flags 108 | paramtype: integer 109 | severity: medium 110 | - name: Hook W 111 | action: alert 112 | function: SetWindowsHookExW 113 | dll: User32.dll 114 | arguments: 115 | - type: ignore 116 | - type: ignore 117 | - type: ignore 118 | - type: integer 119 | val: 0 120 | procblacklist: C:\\Program Files \(x86\)\\Internet Explorer\\iexplore.exe 121 | severity: medium 122 | - name: Hook A 123 | action: alert 124 | function: SetWindowsHookExA 125 | dll: User32.dll 126 | arguments: 127 | - type: ignore 128 | - type: ignore 129 | - type: ignore 130 | - type: integer 131 | val: 0 132 | severity: medium 133 | - name: ! 'Open Remote ' 134 | action: alert 135 | function: OpenSCManagerA 136 | dll: Advapi32.dll 137 | arguments: 138 | - type: c string 139 | expression: ^..*$ 140 | - type: ignore 141 | - type: ignore 142 | severity: low 143 | - name: Process Injection - Alloc RWX 144 | action: alert 145 | function: VirtualAllocEx 146 | dll: Kernel32.dll 147 | arguments: 148 | - type: not 149 | val: -1 150 | - type: ignore 151 | - type: ignore 152 | - type: ignore 153 | - type: integer 154 | val: 64 155 | severity: medium 156 | - name: Process Injection - Open Proc 157 | action: alert 158 | function: OpenProcess 159 | dll: Kernel32.dll 160 | arguments: 161 | - type: bitmask 162 | mask type: any 163 | mask: 540673 164 | - type: ignore 165 | - type: ignore 166 | severity: medium -------------------------------------------------------------------------------- /server/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20120328233442) do 15 | 16 | create_table "actions", :force => true do |t| 17 | t.string "name" 18 | t.integer "action" 19 | t.integer "severity" 20 | t.integer "retval" 21 | t.integer "signature_set_id" 22 | t.integer "available_function_id" 23 | t.integer "retprotectType" 24 | t.integer "retprotectMode" 25 | t.integer "actiontype" 26 | t.text "notes" 27 | t.text "modblacklist" 28 | t.text "modwhitelist" 29 | t.text "procblacklist" 30 | t.text "procwhitelist" 31 | end 32 | 33 | create_table "alert_args", :force => true do |t| 34 | t.binary "data" 35 | t.integer "parameter_id" 36 | t.integer "alert_id" 37 | end 38 | 39 | add_index "alert_args", ["alert_id"], :name => "index_alert_args_on_alert_id" 40 | add_index "alert_args", ["parameter_id", "alert_id"], :name => "index_alert_args_on_parameter_id_and_alert_id", :unique => true 41 | add_index "alert_args", ["parameter_id"], :name => "index_alert_args_on_parameter_id" 42 | 43 | create_table "alerts", :force => true do |t| 44 | t.integer "action_id" 45 | t.datetime "created_at" 46 | t.datetime "updated_at" 47 | t.string "user" 48 | t.string "process" 49 | t.integer "pid" 50 | t.string "computer" 51 | t.string "ip" 52 | t.integer "count" 53 | t.string "module" 54 | end 55 | 56 | add_index "alerts", ["action_id"], :name => "index_alerts_on_action_id" 57 | 58 | create_table "arguments", :force => true do |t| 59 | t.integer "argtype" 60 | t.string "regExp" 61 | t.integer "val1" 62 | t.integer "val2" 63 | t.integer "parameter_id" 64 | t.integer "action_id" 65 | end 66 | 67 | create_table "available_dlls", :force => true do |t| 68 | t.string "name" 69 | end 70 | 71 | add_index "available_dlls", ["name"], :name => "index_available_dlls_on_name", :unique => true 72 | 73 | create_table "available_functions", :force => true do |t| 74 | t.string "name" 75 | t.text "decl" 76 | t.integer "available_dll_id" 77 | end 78 | 79 | add_index "available_functions", ["available_dll_id"], :name => "index_available_functions_on_available_dll_id" 80 | 81 | create_table "parameters", :force => true do |t| 82 | t.string "name" 83 | t.integer "paramtype" 84 | t.integer "num" 85 | t.integer "size" 86 | t.integer "arg" 87 | t.integer "available_function_id" 88 | end 89 | 90 | add_index "parameters", ["available_function_id", "name"], :name => "index_parameters_on_available_function_id_and_name", :unique => true 91 | add_index "parameters", ["available_function_id"], :name => "index_parameters_on_available_function_id" 92 | 93 | create_table "signature_sets", :force => true do |t| 94 | t.float "version" 95 | t.string "report" 96 | t.integer "serial" 97 | t.datetime "created_at" 98 | t.datetime "updated_at" 99 | t.string "name" 100 | t.string "procblacklist" 101 | t.string "aggregator" 102 | t.integer "aggregator_port" 103 | end 104 | 105 | add_index "signature_sets", ["serial", "version"], :name => "index_signature_sets_on_serial_and_version", :unique => true 106 | 107 | create_table "users", :force => true do |t| 108 | t.string "username" 109 | t.string "password_hash" 110 | t.string "password_salt" 111 | t.datetime "created_at" 112 | t.datetime "updated_at" 113 | end 114 | 115 | end 116 | -------------------------------------------------------------------------------- /client/apihook/base_inject.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | #ifndef _BASE_INJECT_H 3 | #define _BASE_INJECT_H 4 | //===============================================================================================// 5 | #include 6 | #include "apihook.h" 7 | 8 | #define PROCESS_ARCH_UNKNOWN 0 9 | #define PROCESS_ARCH_X86 1 10 | #define PROCESS_ARCH_X64 2 11 | #define PROCESS_ARCH_IA64 3 12 | 13 | // The three injection techniques currently supported. 14 | #define INJECT_TECHNIQUE_REMOTETHREAD 0 15 | #define INJECT_TECHNIQUE_REMOTETHREADWOW64 1 16 | #define INJECT_TECHNIQUE_APCQUEUE 2 17 | 18 | //===============================================================================================// 19 | 20 | // Definition of ntdll!NtQueueApcThread 21 | typedef NTSTATUS (NTAPI * NTQUEUEAPCTHREAD)( HANDLE hThreadHandle, LPVOID lpApcRoutine, LPVOID lpApcRoutineContext, LPVOID lpApcStatusBlock, LPVOID lpApcReserved ); 22 | 23 | // Definitions used for running native x64 code from a wow64 process (see executex64.asm) 24 | typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter ); 25 | typedef DWORD (WINAPI * EXECUTEX64)( X64FUNCTION pFunction, DWORD dwParameter ); 26 | 27 | typedef DWORD (WINAPI * GETMODULEFILENAMEEXA)( HANDLE hProcess, HMODULE hModule, LPTSTR lpExeName, DWORD dwSize ); 28 | typedef DWORD (WINAPI * GETPROCESSIMAGEFILENAMEA)( HANDLE hProcess, LPTSTR lpExeName, DWORD dwSize ); 29 | typedef BOOL (WINAPI * QUERYFULLPROCESSIMAGENAMEA)( HANDLE hProcess, DWORD dwFlags, LPTSTR lpExeName, PDWORD lpdwSize ); 30 | typedef HANDLE (WINAPI * CREATETOOLHELP32SNAPSHOT)( DWORD dwFlags, DWORD th32ProcessID ); 31 | typedef BOOL (WINAPI * PROCESS32FIRST)( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ); 32 | typedef BOOL (WINAPI * PROCESS32NEXT)( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ); 33 | typedef void (WINAPI * GETNATIVESYSTEMINFO)( LPSYSTEM_INFO lpSystemInfo ); 34 | typedef BOOL (WINAPI * ISWOW64PROCESS)( HANDLE hProcess, PBOOL Wow64Process ); 35 | 36 | typedef NTSTATUS (WINAPI * NTQUERYINFORMATIONPROCESS)( HANDLE ProcessHandle, DWORD ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength ); 37 | 38 | typedef BOOL (WINAPI * ENUMPROCESSES)( DWORD * pProcessIds, DWORD cb, DWORD * pBytesReturned ); 39 | typedef BOOL (WINAPI * ENUMPROCESSMODULES)( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ); 40 | typedef DWORD (WINAPI * GETMODULEBASENAMEA)( HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName, DWORD nSize ); 41 | 42 | 43 | //===============================================================================================// 44 | 45 | // The context used for injection via inject_via_apcthread 46 | typedef struct _APCCONTEXT 47 | { 48 | union 49 | { 50 | LPVOID lpStartAddress; 51 | BYTE bPadding1[8]; 52 | } s; 53 | 54 | union 55 | { 56 | LPVOID lpParameter; 57 | BYTE bPadding2[8]; 58 | } p; 59 | 60 | BYTE bExecuted; 61 | 62 | } APCCONTEXT, * LPAPCCONTEXT; 63 | 64 | // The context used for injection via inject_via_remotethread_wow64 65 | typedef struct _WOW64CONTEXT 66 | { 67 | union 68 | { 69 | HANDLE hProcess; 70 | BYTE bPadding2[8]; 71 | } h; 72 | 73 | union 74 | { 75 | LPVOID lpStartAddress; 76 | BYTE bPadding1[8]; 77 | } s; 78 | 79 | union 80 | { 81 | LPVOID lpParameter; 82 | BYTE bPadding2[8]; 83 | } p; 84 | union 85 | { 86 | HANDLE hThread; 87 | BYTE bPadding2[8]; 88 | } t; 89 | } WOW64CONTEXT, * LPWOW64CONTEXT; 90 | 91 | //===============================================================================================// 92 | 93 | DWORD inject_via_apcthread(HANDLE hProcess, HANDLE hThread, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress ); 94 | 95 | DWORD inject_via_remotethread(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress ); 96 | 97 | BOOL inject_dll( HANDLE hProcess, HANDLE hThread, DWORD pidArch, LPVOID lpBuffer, DWORD dwLength ); 98 | 99 | DWORD dll_inject_load( HANDLE hProcess, HANDLE hThread ); 100 | 101 | //===============================================================================================// 102 | #endif 103 | //===============================================================================================// -------------------------------------------------------------------------------- /server/app/controllers/signature_sets_controller.rb: -------------------------------------------------------------------------------- 1 | class SignatureSetsController < ApplicationController 2 | protect_from_forgery 3 | before_filter :login_required, :except => [:compiled, :signature, :installer_sig] 4 | respond_to :json 5 | respond_to :html 6 | 7 | # GET /signature_sets 8 | # GET /signature_sets.json 9 | def index 10 | @signature_sets = SignatureSet.all 11 | respond_to do |format| 12 | format.html # index.html.erb 13 | format.json { render json: @signature_sets } 14 | end 15 | end 16 | 17 | # GET /signature_sets/1/compiled 18 | def compiled 19 | @signature_set = SignatureSet.find(params[:id]) 20 | send_data @signature_set.compiled 21 | end 22 | 23 | # GET /signature_sets/1/yaml 24 | def yaml 25 | require 'yaml' 26 | send_data SignatureSet.find(params[:id]).to_yaml, { :type => 'text/plain'.freeze, :disposition => 'inline'.freeze } 27 | end 28 | 29 | # GET /signature_sets/1/signature 30 | def signature 31 | @signature_set = SignatureSet.find(params[:id]) 32 | send_data @signature_set.signature 33 | end 34 | 35 | # GET /installer_sig 36 | def installer_sig 37 | send_data SignatureSet.installer_sig 38 | end 39 | 40 | # GET /signature_sets/1/adm 41 | def adm 42 | @signature_set = SignatureSet.find(params[:id]) 43 | headers['Content-Disposition'] = "attachment; filename=\"ambush.adm\"" 44 | respond_to do |format| 45 | format.html { render :layout => false, :content_type => 'text/plain' } 46 | format.json { render json: @signature_set } 47 | end 48 | end 49 | 50 | # GET /signature_sets/1/regcmddm 51 | def regcmd 52 | @signature_set = SignatureSet.find(params[:id]) 53 | headers['Content-Disposition'] = "attachment; filename=\"ambush.cmd\"" 54 | respond_to do |format| 55 | format.html { render :layout => false, :content_type => 'text/plain' } 56 | format.json { render json: @signature_set } 57 | end 58 | end 59 | 60 | # GET /signature_sets/1 61 | # GET /signature_sets/1.json 62 | def show 63 | @signature_set = SignatureSet.find(params[:id]) 64 | respond_to do |format| 65 | format.html # show.html.erb 66 | format.json { render json: @signature_set } 67 | end 68 | end 69 | 70 | # GET /signature_sets/new 71 | # GET /signature_sets/new.json 72 | def new 73 | @signature_set = SignatureSet.new(params[:signature_set]) 74 | respond_to do |format| 75 | format.html # new.html.erb 76 | format.json { render json: @signature_set } 77 | end 78 | end 79 | 80 | # GET /signature_sets/1/edit 81 | def edit 82 | @signature_set = SignatureSet.find(params[:id]) 83 | end 84 | 85 | # POST /signature_sets 86 | # POST /signature_sets.json 87 | def create 88 | if params[:imported] 89 | fin = params[:imported].tempfile 90 | contents = fin.read fin.stat.size 91 | fin.close 92 | @signature_set = SignatureSet.from_simplified(YAML::load(contents), params[:id]) 93 | redirect_to @signature_set 94 | return 95 | end 96 | @signature_set = SignatureSet.new(params[:signature_set]) 97 | @signature_set.save 98 | ids = @signature_set.id.to_s 99 | respond_with({:message => 'Signature successfully created!', 100 | :row => '' + ids + '' + 101 | @signature_set.name + 'View/Edit SignaturesDelete Signature Set'}, :location => nil) 104 | end 105 | 106 | # PUT /signature_sets/1 107 | # PUT /signature_sets/1.json 108 | def update 109 | @signature_set = SignatureSet.find(params[:id]) 110 | respond_to do |format| 111 | if @signature_set.update_attributes(params[:signature_set]) 112 | @signature_set.markchanged 113 | format.html { redirect_to @signature_set, notice: 'Signature set was successfully updated.' } 114 | format.json { head :ok } 115 | else 116 | format.html { render action: "edit" } 117 | format.json { render json: @signature_set.errors, status: :unprocessable_entity } 118 | end 119 | end 120 | end 121 | 122 | # DELETE /signature_sets/1 123 | # DELETE /signature_sets/1.json 124 | def destroy 125 | @signature_set = SignatureSet.find(params[:id]) 126 | @signature_set.destroy 127 | respond_with({:message => 'Signature Set successfully destroyed!'}, :location => nil) 128 | end 129 | 130 | # GET /documentation/regex 131 | def regexinfo 132 | respond_to do |format| 133 | format.html # regexinfo.html.erb 134 | end 135 | end 136 | end 137 | -------------------------------------------------------------------------------- /client/apihook/apihook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "signatures.h" 3 | #ifdef _M_X64 4 | #include "apihookx64.h" 5 | #else 6 | #include "apihookx86.h" 7 | #endif 8 | 9 | extern HANDLE rwHeap; 10 | extern HMODULE myDllHandle; 11 | extern HOOKAPI_CONF * apiConf; 12 | 13 | //Alert enabling/disabling 14 | extern DWORD enableAlertsSlot; 15 | inline void disableAlerts(){ 16 | TlsSetValue(enableAlertsSlot, (PVOID)-1); 17 | } 18 | inline void enableAlerts(){ 19 | TlsSetValue(enableAlertsSlot, NULL); 20 | } 21 | inline bool alertsEnabled(){ 22 | return TlsGetValue(enableAlertsSlot) == NULL; 23 | } 24 | inline void setupAlertsDisabled(){ 25 | enableAlertsSlot = TlsAlloc(); 26 | disableAlerts(); 27 | } 28 | 29 | #define LOCAL_REPORT_PIPE "\\\\.\\pipe\\FunctionFilterReport" 30 | #define REPORT_FILE "FFlog.txt" 31 | #define MAX_ARGS 64 // should be enough for anybody - 32 | //note this simply ignores arguments past MAX_ARGS not crashes or overflows 33 | 34 | #define NO_PROC_MATCH (wslre*)-2 35 | #define PROC_MATCH (wslre*)-1 36 | 37 | #ifdef _M_X64 38 | #pragma pack(push,8) 39 | #else 40 | #pragma pack(push,4) 41 | #endif 42 | typedef struct sHOOKAPI_MESSAGE 43 | { 44 | DWORD length; // of entire message 45 | DWORD type; // what action is firing 46 | DWORD pid; 47 | DWORD count; 48 | DWORD numArgs; 49 | } HOOKAPI_MESSAGE, *PHOOKAPI_MESSAGE; 50 | //tests whether messages are equal other than the count 51 | inline bool messageEqual(PHOOKAPI_MESSAGE first, PHOOKAPI_MESSAGE second){ 52 | DWORD firstCount = first->count; //Save counts 53 | first->count = second->count; //Make counts the same 54 | //Do the compare 55 | bool retval = first->length == second->length && memcmp(first, second, first->length) == 0; 56 | first->count = firstCount; //Reset the count 57 | return retval; 58 | } 59 | 60 | //Functions 61 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); 62 | bool hookDllApi(HMODULE dllHandle); 63 | 64 | //Types for dynamic function definitions 65 | typedef void* (WINAPI *NoArgFunc)(); 66 | typedef HMODULE (WINAPI *OneArgFunc)(void*); //For setEax 67 | typedef HMODULE (WINAPI *ThreeArgFunc)(void*,void*,void*); //For callApi 68 | typedef void** (WINAPI *hookArgFunc)(); 69 | typedef NTSTATUS (NTAPI *LdrLoadDllHookFunc)(PWCHAR, PVOID, PVOID, PHANDLE); 70 | 71 | //MICROSOFT DEFINES from MSDN - because win SDK does not have a complete set 72 | /* 73 | typedef struct _LIST_ENTRY { 74 | struct _LIST_ENTRY *Flink; 75 | struct _LIST_ENTRY *Blink; 76 | } LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY; 77 | */ 78 | typedef struct _LSA_UNICODE_STRING { 79 | USHORT Length; 80 | USHORT MaximumLength; 81 | PWSTR Buffer; 82 | } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING; 83 | typedef struct _LDR_DATA_TABLE_ENTRY { 84 | PVOID Reserved1[2]; 85 | LIST_ENTRY InMemoryOrderLinks; 86 | PVOID Reserved2[2]; 87 | PVOID DllBase; 88 | PVOID EntryPoint; 89 | PVOID Reserved3; 90 | UNICODE_STRING FullDllName; 91 | BYTE Reserved4[8]; 92 | PVOID Reserved5[3]; 93 | union { 94 | ULONG CheckSum; 95 | PVOID Reserved6; 96 | }; 97 | ULONG TimeDateStamp; 98 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 99 | 100 | typedef struct _PEB_LDR_DATA { 101 | BYTE Reserved1[8]; 102 | PVOID Reserved2[3]; 103 | LIST_ENTRY InMemoryOrderModuleList; 104 | } PEB_LDR_DATA, *PPEB_LDR_DATA; 105 | 106 | typedef struct _PEB { 107 | BYTE Reserved1[2]; 108 | BYTE BeingDebugged; 109 | BYTE Reserved2[1]; 110 | PVOID Reserved3[2]; 111 | PPEB_LDR_DATA Ldr; 112 | PVOID ProcessParameters; 113 | BYTE Reserved4[104]; 114 | PVOID Reserved5[52]; 115 | PVOID PostProcessInitRoutine; 116 | BYTE Reserved6[128]; 117 | PVOID Reserved7[1]; 118 | ULONG SessionId; 119 | } PEB, *PPEB; 120 | 121 | typedef struct _PROCESS_BASIC_INFORMATION { 122 | PVOID Reserved1; 123 | PPEB PebBaseAddress; 124 | PVOID Reserved2[2]; 125 | ULONG_PTR UniqueProcessId; 126 | PVOID Reserved3; 127 | } PROCESS_BASIC_INFORMATION; 128 | 129 | typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunc)( 130 | __in HANDLE ProcessHandle, 131 | __in DWORD ProcessInformationClass, 132 | __out PVOID ProcessInformation, 133 | __in ULONG ProcessInformationLength, 134 | __out_opt PULONG ReturnLength 135 | ); 136 | 137 | #pragma pack(pop) 138 | -------------------------------------------------------------------------------- /client/hookTester/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool quiet = false; 7 | bool thread = false; 8 | typedef HANDLE (WINAPI *URLDownloadToFileWFunc)( 9 | LPUNKNOWN pCaller, 10 | LPCWSTR szURL, 11 | LPCWSTR szFileName, 12 | DWORD dwReserved, 13 | LPBINDSTATUSCALLBACK lpfnCB 14 | ); 15 | typedef int (WINAPI * recvfunc)(int s, char *buf, int len, int flags); 16 | DWORD WINAPI ThreadProc(LPVOID arg){ 17 | thread = true; 18 | if(!quiet) 19 | MessageBoxA(NULL,"I am in a new thread!","Ambush tester",0); 20 | return 0; 21 | } 22 | bool ask(const char* message){ 23 | return quiet || MessageBoxA(NULL, message, "Ambush tester", MB_YESNO) == IDYES; 24 | } 25 | void error(const char* message){ 26 | if(quiet) 27 | MessageBoxA(NULL, message, "ERROR - Ambush test", MB_ICONERROR); 28 | } 29 | int CALLBACK WinMain(HINSTANCE,HINSTANCE,LPSTR,int){ 30 | quiet = strstr(GetCommandLineA(), "quiet") != NULL; 31 | 32 | //Change directory to binary directory 33 | char filename[MAX_PATH]; 34 | DWORD size = GetModuleFileNameA(NULL, filename, sizeof(filename)); 35 | for(size -= 1; filename[size] != '\\' && size != 0; size--) 36 | filename[size] = 0; 37 | SetCurrentDirectoryA(filename); 38 | 39 | if(ask("Update signatures?")) 40 | system("config.exe update"); 41 | 42 | if(ask("Manually load library?")) 43 | #ifdef _M_X64 44 | if(LoadLibraryA("apihook64.dll") == NULL) 45 | #else 46 | if(LoadLibraryA("apihook.dll") == NULL) 47 | #endif 48 | MessageBoxA(NULL,"Load failed!","Hook Tester",0); 49 | 50 | //ALLOW TEST 51 | clock_t one=clock(); 52 | if(ask("Test starting. SleepEx 1000...")) 53 | SleepEx(1000, FALSE); 54 | if(quiet && clock() - one < CLOCKS_PER_SEC / 2) 55 | error("SleepEx(1000, 0) exited early"); 56 | 57 | //BLOCK AND AGGREGATION TEST 58 | one=clock(); 59 | if(ask("SleepEx 1001 quad")) 60 | for(int i = 0; i < 4; i++) 61 | SleepEx(1001, FALSE); 62 | if(ask("SleepEx 1001 quad")) 63 | for(int i = 0; i < 4; i++) 64 | SleepEx(1001, FALSE); 65 | if(quiet && clock() - one > CLOCKS_PER_SEC * 5) 66 | error("SleepEx(1001, 0) was not blocked"); 67 | 68 | //URLDOWNLOADTOFILEW TEST 69 | //Test LoadLibrary, GetProcAddress, WC string regex 70 | DeleteFileA("deleteme.txt"); 71 | URLDownloadToFileWFunc URLDownloadToFileW = (URLDownloadToFileWFunc) 72 | GetProcAddress(LoadLibraryA("urlmon"), "URLDownloadToFileW"); 73 | if(ask("URLDownloadToFileW http://www.yahoo.com/")) 74 | if(URLDownloadToFileW(NULL, L"http://www.yahoo.com/", L"deleteme.txt", 0, NULL) != (HANDLE)73) 75 | error("URLDOWNLOADTOFILEW wrong return value"); 76 | 77 | //RECV TEST 78 | //Test LoadLibrary, GetProcAddress, Pointer, and Integer range 79 | recvfunc myrecv = (recvfunc)GetProcAddress(LoadLibraryA("ws2_32.dll"), "recv"); 80 | PVOID rwx = VirtualAlloc(NULL, 1021, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 81 | if(ask("winsock recv")) 82 | if(myrecv(0, (char*)rwx, 1021, 0) != 0) 83 | error("Ws2_32 recv did not return the correct value"); 84 | 85 | //INJECT TEST - ensures library is loaded into all new processes 86 | STARTUPINFOA start; 87 | PROCESS_INFORMATION proc; 88 | memset(&start,0,sizeof(start)); 89 | memset(&proc,0,sizeof(proc)); 90 | start.cb = sizeof(start); 91 | char cmdline[100]; 92 | lstrcpyA(cmdline,"cmd.exe"); 93 | if(ask("Start cmd")){ 94 | CreateProcessA(NULL,cmdline,NULL,NULL,0,0,NULL,NULL,&start,&proc); 95 | HMODULE hmods[100]; 96 | DWORD bytes = sizeof(hmods); 97 | CHAR modname[MAX_PATH]; 98 | bool found = false; 99 | if(EnumProcessModules(proc.hProcess, hmods, sizeof(hmods), &bytes)) 100 | for(int i = 0; i < (bytes / sizeof(HMODULE)); i++) 101 | if(GetModuleFileNameExA(proc.hProcess, hmods[i], modname, MAX_PATH)) 102 | if(strstr(modname, "apihook") != NULL) 103 | found = true; 104 | if(found == false) 105 | error("Process injection failed!"); 106 | TerminateProcess(proc.hProcess, 0); 107 | } 108 | 109 | //TEST NOT 110 | if(ask("Non-remote CreateRemoteThread")){ 111 | WaitForSingleObject(CreateRemoteThread(GetCurrentProcess(),NULL,0,&ThreadProc,NULL,0,NULL), 500); 112 | if(thread != true) 113 | error("Thread did not run!"); 114 | } 115 | 116 | //Test killproc with sleepEx 1002 117 | if(ask("Read PE")){ 118 | GetModuleFileNameA(NULL, filename, sizeof(filename)); 119 | HANDLE h = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 120 | NULL, OPEN_EXISTING, NULL, NULL); 121 | char readbuf[1000]; 122 | DWORD dontcare; 123 | ReadFile(h,readbuf,sizeof(readbuf),&dontcare,NULL); 124 | CloseHandle(h); 125 | } 126 | error("Read PE Kill process failed!"); 127 | } 128 | -------------------------------------------------------------------------------- /server/app/controllers/actions_controller.rb: -------------------------------------------------------------------------------- 1 | class ActionsController < ApplicationController 2 | protect_from_forgery 3 | before_filter :login_required 4 | respond_to :json 5 | @@memmodes = {'PAGE_EXECUTE' => 0x10, 'PAGE_EXECUTE_READ' => 0x20, 6 | 'PAGE_EXECUTE_READWRITE' => 0x40, 'PAGE_EXECUTE_WRITECOPY' => 0x80, 7 | 'PAGE_NOACCESS' => 0x1, 'PAGE_READONLY' => 0x2, 8 | 'PAGE_READWRITE' => 0x4, 'PAGE_WRITECOPY' => 0x8} 9 | # DELETE /actions/1.json 10 | def destroy 11 | action = Action.find(params[:id]) 12 | func = action.available_function 13 | func.destroy if func.decl == nil # non-imported function 14 | action.signature_set.markchanged 15 | action.destroy 16 | respond_with({:message => 'Action successfully destroyed!'}, :location => nil) 17 | end 18 | 19 | # GET /actions/1 20 | # GET /actions/1.json 21 | def show 22 | @action = Action.find(params[:id]) 23 | funct = @action.available_function 24 | respond_to do |format| 25 | format.json { render json: {:action => @action, :func => funct.name, 26 | :dll => funct.available_dll.name, :params => funct.parameters, 27 | :arguments => @action.arguments } } 28 | end 29 | end 30 | 31 | # POST /actions.json 32 | # Makes a new signature 33 | def create 34 | #Get or create DLL 35 | dll = AvailableDll.find_or_create(params[:dllCustom]) 36 | 37 | #Get or create function 38 | funcparams = [] 39 | currentParam = 0 40 | while params["name#{currentParam}"] 41 | funcparams << {'name' => params["name#{currentParam}"], 'paramtype' => params["type#{currentParam}"], 42 | 'type' => params["subtype#{currentParam}"], 'blobval' => params["blobval#{currentParam}"]} 43 | currentParam += 1 44 | end 45 | func = AvailableFunction.find_or_create(params[:functionCustom], funcparams, dll) 46 | 47 | #Create action 48 | a = Action.new(params[:act]) 49 | a.retval = params[:act][:retval].to_i(16) if params[:act][:retval][0..1] == '0x' 50 | a.signature_set = SignatureSet.find(params[:signature_set_id]) 51 | a.available_function = func 52 | a.setAction params[:act][:action] 53 | 54 | #Return address conditions 55 | if params[:retprotectType] != 'ignore' 56 | modeParam = params["subval-1"] 57 | a.retprotectMode = @@memmodes[modeParam] || modeParam.to_i 58 | a.retprotectMode = modeParam.to_i(16) if modeParam[0..1] == '0x' # handle 0xabc style 59 | else 60 | a.retprotectMode = 0 61 | end 62 | a.retprotectType = 0 63 | a.save 64 | 65 | #Create args 66 | types = ['ignore', 'integer', 'range', 'c string', 'wide-char string', 'pointer', 'bitmask', 'blob', 'not'] 67 | parameters = func.parameters.all(:order => 'num') 68 | currentParam = 0 69 | while params["name#{currentParam}"] != nil 70 | arg = Argument.new(:parameter_id => parameters[currentParam].id, :action => a) 71 | 72 | #get type 73 | givenType = params["subtype#{currentParam}"] 74 | arg.argtype = types.index(givenType) 75 | arg.argtype = types.index(params["type#{currentParam}"]) if arg.argtype == nil 76 | raise "Error - invalid argument type; try one of these:\n#{types.inspect}" if arg.argtype == nil 77 | 78 | #get val 79 | arg.regExp = params["val#{currentParam}"] if ['c string', 'wide-char string', 'blob'].index(types[arg.argtype]) 80 | arg.setval1(params["val#{currentParam}"]) if ['integer', 'range', 'pointer', 'bitmask', 'not'].index(givenType) 81 | arg.setval2(params["subval#{currentParam}"]) if ['range', 'bitmask'].index(givenType) 82 | if(givenType == 'pointer') 83 | modeParam = params["subval#{currentParam}"] 84 | arg.setval2(@@memmodes[modeParam] || modeParam.to_i) 85 | arg.setval2(modeParam.to_i(16)) if modeParam[0..1] == '0x' 86 | end 87 | 88 | #must give blob length 89 | if params["subtype#{currentParam}"] == 'ARG' 90 | arg.setval1(params["blobval#{currentParam}"]) 91 | arg.val2 = 0 92 | elsif params["subtype#{currentParam}"] == 'VAL' 93 | arg.val1 = -1 94 | arg.setval2(params["blobval#{currentParam}"]) 95 | end 96 | arg.save 97 | currentParam += 1 98 | end 99 | 100 | #we changed the sig set 101 | a.signature_set.markchanged 102 | 103 | #we're done 104 | respond_with({:message => 'Signature successfully created!', 105 | :row => '' + 107 | ActionController::Base.helpers.strip_tags(a.name) + '' + 108 | ActionController::Base.helpers.strip_tags(a.available_function.available_dll.name) + 109 | '' + ActionController::Base.helpers.strip_tags(a.available_function.name) + 110 | '' + a.actionStr + '' + 111 | ActionController::Base.helpers.strip_tags(a.arg_str) + ''}, :location => nil) 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /client/apihook/udis/udis86.c: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * udis86.c 3 | * 4 | * Copyright (c) 2004, 2005, 2006, Vivek Mohan 5 | * All rights reserved. See LICENSE 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "input.h" 14 | #include "extern.h" 15 | 16 | /* ============================================================================= 17 | * ud_init() - Initializes ud_t object. 18 | * ============================================================================= 19 | */ 20 | extern void 21 | ud_init(struct ud* u) 22 | { 23 | memset((void*)u, 0, sizeof(struct ud)); 24 | ud_set_mode(u, 16); 25 | u->mnemonic = UD_Iinvalid; 26 | ud_set_pc(u, 0); 27 | #ifndef __UD_STANDALONE__ 28 | ud_set_input_file(u, stdin); 29 | #endif /* __UD_STANDALONE__ */ 30 | } 31 | 32 | /* ============================================================================= 33 | * ud_disassemble() - disassembles one instruction and returns the number of 34 | * bytes disassembled. A zero means end of disassembly. 35 | * ============================================================================= 36 | */ 37 | extern unsigned int 38 | ud_disassemble(struct ud* u) 39 | { 40 | if (ud_input_end(u)) 41 | return 0; 42 | 43 | 44 | u->insn_buffer[0] = u->insn_hexcode[0] = 0; 45 | 46 | 47 | if (ud_decode(u) == 0) 48 | return 0; 49 | if (u->translator) 50 | u->translator(u); 51 | return ud_insn_len(u); 52 | } 53 | 54 | /* ============================================================================= 55 | * ud_set_mode() - Set Disassemly Mode. 56 | * ============================================================================= 57 | */ 58 | extern void 59 | ud_set_mode(struct ud* u, uint8_t m) 60 | { 61 | switch(m) { 62 | case 16: 63 | case 32: 64 | case 64: u->dis_mode = m ; return; 65 | default: u->dis_mode = 16; return; 66 | } 67 | } 68 | 69 | /* ============================================================================= 70 | * ud_set_vendor() - Set vendor. 71 | * ============================================================================= 72 | */ 73 | extern void 74 | ud_set_vendor(struct ud* u, unsigned v) 75 | { 76 | switch(v) { 77 | case UD_VENDOR_INTEL: 78 | u->vendor = v; 79 | break; 80 | default: 81 | u->vendor = UD_VENDOR_AMD; 82 | } 83 | } 84 | 85 | /* ============================================================================= 86 | * ud_set_pc() - Sets code origin. 87 | * ============================================================================= 88 | */ 89 | extern void 90 | ud_set_pc(struct ud* u, uint64_t o) 91 | { 92 | u->pc = o; 93 | } 94 | 95 | /* ============================================================================= 96 | * ud_set_syntax() - Sets the output syntax. 97 | * ============================================================================= 98 | */ 99 | extern void 100 | ud_set_syntax(struct ud* u, void (*t)(struct ud*)) 101 | { 102 | u->translator = t; 103 | } 104 | 105 | /* ============================================================================= 106 | * ud_insn() - returns the disassembled instruction 107 | * ============================================================================= 108 | */ 109 | extern char* 110 | ud_insn_asm(struct ud* u) 111 | { 112 | return u->insn_buffer; 113 | } 114 | 115 | /* ============================================================================= 116 | * ud_insn_offset() - Returns the offset. 117 | * ============================================================================= 118 | */ 119 | extern uint64_t 120 | ud_insn_off(struct ud* u) 121 | { 122 | return u->insn_offset; 123 | } 124 | 125 | 126 | /* ============================================================================= 127 | * ud_insn_hex() - Returns hex form of disassembled instruction. 128 | * ============================================================================= 129 | */ 130 | extern char* 131 | ud_insn_hex(struct ud* u) 132 | { 133 | return u->insn_hexcode; 134 | } 135 | 136 | /* ============================================================================= 137 | * ud_insn_ptr() - Returns code disassembled. 138 | * ============================================================================= 139 | */ 140 | extern uint8_t* 141 | ud_insn_ptr(struct ud* u) 142 | { 143 | return u->inp_sess; 144 | } 145 | 146 | /* ============================================================================= 147 | * ud_insn_len() - Returns the count of bytes disassembled. 148 | * ============================================================================= 149 | */ 150 | extern unsigned int 151 | ud_insn_len(struct ud* u) 152 | { 153 | return u->inp_ctr; 154 | } 155 | -------------------------------------------------------------------------------- /client/hookTester/hookTester.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 30 | 33 | 36 | 39 | 42 | 45 | 56 | 59 | 62 | 65 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 96 | 97 | 105 | 108 | 111 | 114 | 117 | 121 | 132 | 135 | 138 | 141 | 151 | 154 | 157 | 160 | 163 | 166 | 169 | 172 | 173 | 174 | 175 | 176 | 177 | 182 | 185 | 186 | 187 | 192 | 193 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /server/app/models/argument.rb: -------------------------------------------------------------------------------- 1 | class Argument < ActiveRecord::Base 2 | belongs_to :action 3 | belongs_to :parameter 4 | @@types = ['ignore', 'integer', 'range', 'c string', 'wide-char string', 'pointer', 'bitmask', 'blob', 'not'] 5 | @@masktypes = ['any','all','exact','none'] 6 | 7 | def to_s 8 | begin 9 | typestr = @@types[self.argtype].dup 10 | case typestr 11 | when 'integer' 12 | typestr = "= #{self.val1.to_s}" 13 | when 'not' 14 | typestr << " #{self.val1.to_s}" 15 | when 'range' 16 | typestr << " #{self.val1.to_s}-#{self.val2.to_s}" 17 | when 'bitmask' 18 | typestr << " {#{@@masktypes[self.val1]} 0x#{self.val2.to_s(16)}}" 19 | when 'c string' 20 | typestr << " #{self.regExp}" 21 | when 'wide-char string' 22 | typestr << " #{self.regExp}" 23 | when 'pointer' 24 | typestr << " #{@@masktypes[self.val1]} 0x#{self.val2.to_s(16)}" 25 | end 26 | typestr 27 | rescue 28 | '' 29 | end 30 | end 31 | 32 | def setval1(str) 33 | if str[0..1] == '0x' 34 | self.val1 = str[2..-1].to_i(16) 35 | else 36 | self.val1 = str.to_i 37 | end 38 | end 39 | 40 | def setval2(str) 41 | if String === str and str[0..1] == '0x' 42 | self.val2 = str[2..-1].to_i(16) 43 | else 44 | self.val2 = str.to_i 45 | end 46 | end 47 | 48 | # simplified converts the object to a simple array/map/string/int form 49 | # that can be easily exported/imported to or from formats like YAML 50 | def simplified(defined) 51 | simple = {'type' => @@types[self.argtype]} 52 | case @@types[self.argtype] 53 | when 'ignore' 54 | when 'integer', 'not' 55 | simple['val'] = self.val1 56 | when 'range' 57 | simple['from'] = self.val1 58 | simple['to'] = self.val2 59 | when 'c string', 'wide-char string' 60 | simple['expression'] = self.regExp 61 | when 'pointer', 'bitmask' 62 | simple['mask type'] = @@masktypes[self.val1] 63 | simple['mask'] = self.val2 64 | when 'blob' 65 | simple['size argument'] = self.val1 if self.val2 = -1 or self.val2 == nil 66 | simple['size'] = self.val2 if self.val1 == nil 67 | simple['expression'] = self.regExp 68 | else 69 | raise "Error - type #{self.argtype} not supported" 70 | end 71 | if not defined 72 | simple['name'] = self.parameter.name 73 | simple['paramtype'] = @@types[self.parameter.paramtype] 74 | end 75 | simple 76 | end 77 | 78 | def self.from_simplified(simple, parameter, action) 79 | arg = Argument.new(:parameter_id => parameter.id, :action => action) 80 | 81 | #get type 82 | arg.argtype = @@types.index(simple['type']) 83 | raise Exception.new("Error - invalid argument type; try one of these:\n#{@@types.inspect}") if arg.argtype == nil 84 | 85 | case simple['type'].downcase 86 | when 'ignore' 87 | when 'integer', 'not' 88 | arg.val1 = simple["val"] 89 | when 'range' 90 | arg.sval1 = simple["from"] 91 | arg.sval2 = simple["to"] 92 | when 'c string', 'wide-char string' 93 | arg.regExp = simple["expression"] 94 | when 'pointer', 'bitmask' 95 | arg.val1 = @@masktypes.index simple['mask type'] 96 | arg.val2 = simple['mask'] 97 | when 'blob' 98 | arg.regExp = simple["expression"] 99 | if simple.has_key? 'size argument' 100 | arg.val1 = simple['size argument'] 101 | arg.val2 = -1 102 | elsif simple.has_key? 'size' 103 | arg.val2 = simple['size'] 104 | arg.val1 = 0 105 | else 106 | raise Exception.new('Error - must provide blob argument or size') 107 | end 108 | else 109 | raise Exception.new("Error - type #{self.argtype} not supported") 110 | end 111 | arg.save 112 | arg 113 | end 114 | 115 | def compiled 116 | out = [self.argtype].pack("V") 117 | case @@types[self.argtype] 118 | when 'ignore' 119 | when 'integer', 'not' 120 | raise 'Error - invalid integer' if self.val1 == nil 121 | out << [self.val1].pack("Q") 122 | when 'range' 123 | raise 'Error - invalid range' if self.val1 == nil or self.val2 == nil 124 | out << [self.val1, self.val2].pack("QQ") 125 | when 'c string' 126 | raise 'Error - invalid C string' if self.regExp == nil 127 | stringVal = self.regExp+("\x00"*(4-(self.regExp.length % 4))) 128 | out << [stringVal.length].pack("V*") + stringVal 129 | when 'wide-char string' 130 | raise 'Error - invalid wide char string' if self.regExp == nil 131 | binaryVal = (self.regExp + "\x00").encode("UTF-16LE").force_encoding('binary') 132 | stringVal = binaryVal + ("\x00" * (4 - (self.regExp.length % 4))) 133 | out << [stringVal.length].pack("V*") + stringVal 134 | when 'pointer' 135 | self.val1 = 0 if self.val1 == nil 136 | raise "Error - invalid argument type for Pointer mode argument" if self.val2 == nil 137 | out << [self.val1, self.val2].pack("V*") 138 | when 'bitmask' 139 | self.val1 = 0 if self.val1 == nil 140 | raise "Error - invalid argument type for Bitmask mask argument" if self.val2 == nil 141 | out << [self.val1, self.val2].pack("VQ") 142 | when 'blob' 143 | if (self.val1 == -1 and self.val2 == 0) or self.val1 == nil or self.val2 == nil #insufficient info 144 | out = [0].pack("V") # ignore 145 | else 146 | # if not a number, must be a ref 147 | self.val1 = -1 if self.val1 == nil 148 | self.val2 = 0 if self.val2 == nil 149 | stringVal = self.regExp+("\x00"*(4-(self.regExp.length % 4))) 150 | out << [self.val1, self.val2, stringVal.length].pack("V*") + stringVal 151 | end 152 | else 153 | raise "Error - type #{self.argtype} not supported" 154 | end 155 | # size, type, value 156 | [out.size + 4].pack("V*") + out 157 | end 158 | end 159 | -------------------------------------------------------------------------------- /client/apihook/signatures.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define HOOKAPI_SIG_VERSION 1.01f 4 | 5 | enum ArgType { DONTCARE, DWORD_HOOK, DWORDRANGE, CSTRING, WCSTRING, MEM, BITMASK, BLOB_HOOK, DWORD_NEQ }; 6 | 7 | #pragma pack(push,4) 8 | typedef struct sHOOKAPI_BLOB_ARG 9 | { 10 | unsigned int argument; 11 | unsigned int size; 12 | unsigned int valSize; 13 | char value; 14 | } HOOKAPI_BLOB_ARG, *PHOOKAPI_BLOB_ARG; 15 | 16 | typedef struct sHOOKAPI_CSTRING_ARG 17 | { 18 | unsigned int size; 19 | char value; 20 | } HOOKAPI_CSTRING_ARG, *PHOOKAPI_CSTRING_ARG; 21 | 22 | typedef struct sHOOKAPI_WCSTRING_ARG 23 | { 24 | unsigned int size; 25 | wchar_t value; 26 | } HOOKAPI_WCSTRING_ARG, *PHOOKAPI_WCSTRING_ARG; 27 | 28 | typedef struct sHOOKAPI_BITMASK_ARG 29 | { 30 | unsigned int maskType; 31 | unsigned long long mask; 32 | } HOOKAPI_BITMASK_ARG, *PHOOKAPI_BITMASK_ARG; 33 | 34 | typedef struct sHOOKAPI_MEM_ARG 35 | { 36 | unsigned int memType; 37 | unsigned int memMode; 38 | } HOOKAPI_MEM_ARG, *PHOOKAPI_MEM_ARG; 39 | 40 | typedef struct sHOOKAPI_ARG_CONF 41 | { 42 | unsigned int size; 43 | unsigned int type; 44 | unsigned long long value[1]; 45 | } HOOKAPI_ARG_CONF, *PHOOKAPI_ARG_CONF; 46 | inline PHOOKAPI_ARG_CONF nextArgConf(PHOOKAPI_ARG_CONF conf){ 47 | return (PHOOKAPI_ARG_CONF) ((PBYTE)conf + conf->size); 48 | } 49 | 50 | enum ActionType { PRE, POST }; 51 | 52 | enum BitmaskMode { ANY, ALL, ONE, NONE }; 53 | 54 | typedef struct sHOOKAPI_ACTION_CONF 55 | { 56 | unsigned int size; 57 | unsigned int id; 58 | unsigned int action; 59 | unsigned int severity; 60 | unsigned long long retval; 61 | unsigned int type; 62 | unsigned int numArgs; 63 | unsigned int exeBlackLen; 64 | unsigned int exeWhiteLen; 65 | unsigned int modBlackLen; 66 | unsigned int modWhiteLen; 67 | unsigned int retAddrMemType; 68 | unsigned int retAddrMemMode; 69 | wchar_t exeBlack[4]; 70 | //HOOKAPI_CONDITION_CONF conditions[1]; 71 | } HOOKAPI_ACTION_CONF, *PHOOKAPI_ACTION_CONF; 72 | 73 | //Get Functions 74 | inline PWCHAR actionConfExeBlack(PHOOKAPI_ACTION_CONF conf){ 75 | return conf->exeBlack; 76 | } 77 | inline PWCHAR actionConfExeWhite(PHOOKAPI_ACTION_CONF conf){ 78 | return (PWCHAR) (((PBYTE)actionConfExeBlack(conf)) + conf->exeBlackLen); 79 | } 80 | inline PWCHAR actionConfModBlack(PHOOKAPI_ACTION_CONF conf){ 81 | return (PWCHAR) (((PBYTE)actionConfExeWhite(conf)) + conf->exeWhiteLen); 82 | } 83 | inline PWCHAR actionConfModWhite(PHOOKAPI_ACTION_CONF conf){ 84 | return (PWCHAR) (((PBYTE)actionConfModBlack(conf)) + conf->modBlackLen); 85 | } 86 | inline PHOOKAPI_ARG_CONF actionConfArgs(PHOOKAPI_ACTION_CONF conf){ 87 | return (PHOOKAPI_ARG_CONF) (((PBYTE)actionConfModWhite(conf)) + conf->modWhiteLen); 88 | } 89 | inline PHOOKAPI_ACTION_CONF nextActionConf(PHOOKAPI_ACTION_CONF conf){ 90 | return (PHOOKAPI_ACTION_CONF) ((PBYTE)conf + conf->size); 91 | } 92 | 93 | //Actions 94 | enum HookAction { ALERT, BLOCK, KILLPROC, KILLTHREAD }; 95 | 96 | #define START_INFO (DWORD)-1 97 | #define ERROR_INFO (DWORD)-2 98 | 99 | typedef struct sHOOKAPI_FUNC_CONF 100 | { 101 | unsigned int size; 102 | unsigned int numArgs; 103 | unsigned int numActions; 104 | unsigned int nameLen; 105 | char name[1]; 106 | //HOOKAPI_ACTION_CONF actions[1]; 107 | } HOOKAPI_FUNC_CONF, *PHOOKAPI_FUNC_CONF; 108 | 109 | //Get Functions 110 | inline PHOOKAPI_ACTION_CONF functionConfActions(PHOOKAPI_FUNC_CONF conf){ 111 | return (PHOOKAPI_ACTION_CONF) ((PBYTE)conf + sizeof(unsigned int) * 4 + conf->nameLen); 112 | } 113 | inline PHOOKAPI_ARG_CONF functionConfParameters(PHOOKAPI_FUNC_CONF conf){ 114 | PHOOKAPI_ACTION_CONF actions = functionConfActions(conf); 115 | for(unsigned int i = 0; i < conf->numActions; i++) 116 | actions = nextActionConf(actions); 117 | return (PHOOKAPI_ARG_CONF) actions; 118 | } 119 | inline PHOOKAPI_FUNC_CONF nextFunctionConf(PHOOKAPI_FUNC_CONF conf){ 120 | return (PHOOKAPI_FUNC_CONF) ((PBYTE)conf + conf->size); 121 | } 122 | 123 | typedef struct sHOOKAPI_DLL_CONF 124 | { 125 | unsigned int size; 126 | unsigned int numFunctions; 127 | unsigned int nameLen; 128 | char name[1]; 129 | //HOOKAPI_FUNC_CONF functions[1]; 130 | } HOOKAPI_DLL_CONF, *PHOOKAPI_DLL_CONF; 131 | 132 | //Get Functions 133 | inline PHOOKAPI_FUNC_CONF dllConfFunctions(PHOOKAPI_DLL_CONF conf){ 134 | return (PHOOKAPI_FUNC_CONF) ((PBYTE)conf + sizeof(unsigned int) * 3 + conf->nameLen); 135 | } 136 | inline PHOOKAPI_DLL_CONF nextDllConf(PHOOKAPI_DLL_CONF conf){ 137 | return (PHOOKAPI_DLL_CONF) ((PBYTE)conf + conf->size); 138 | } 139 | 140 | typedef struct sHOOKAPI_CONF 141 | { 142 | float version; 143 | unsigned int serial; 144 | unsigned int numdlls; 145 | unsigned int reserved; // deprecated 146 | unsigned int procBlacklistLen; 147 | //HOOKAPI_DLL_CONF dlls[1]; 148 | } HOOKAPI_CONF, *PHOOKAPI_CONF; 149 | 150 | //Get DLLs 151 | inline PHOOKAPI_DLL_CONF apiConfDlls(PHOOKAPI_CONF conf){ 152 | return (PHOOKAPI_DLL_CONF) ((PBYTE)conf + sizeof(unsigned int) * 4 + sizeof(float) + conf->reserved 153 | + conf->procBlacklistLen); 154 | } 155 | 156 | //Get blacklist 157 | inline PWCHAR apiConfProcBlacklist(PHOOKAPI_CONF conf){ 158 | return (PWCHAR) ((PBYTE)conf + sizeof(unsigned int) * 4 + sizeof(float) + conf->reserved); 159 | } 160 | 161 | #pragma pack(pop) 162 | -------------------------------------------------------------------------------- /server/app/models/action.rb: -------------------------------------------------------------------------------- 1 | class Action < ActiveRecord::Base 2 | belongs_to :available_function 3 | belongs_to :signature_set 4 | has_many :arguments, :dependent => :destroy 5 | has_many :alerts, :dependent => :destroy 6 | @@actions = ['alert', 'block', 'kill process', 'kill thread'] 7 | @@memconstants = {0x10 => 'PAGE_EXECUTE', 0x20 => 'PAGE_EXECUTE_READ', 8 | 0x40 => 'PAGE_EXECUTE_READWRITE', 0x80 => 'PAGE_EXECUTE_WRITECOPY', 9 | 0x1 => 'PAGE_NOACCESS', 0x2 => 'PAGE_READONLY', 10 | 0x4 => 'PAGE_READWRITE', 0x8 => 'PAGE_WRITECOPY'} 11 | @@memmodes = {'PAGE_EXECUTE' => 0x10, 'PAGE_EXECUTE_READ' => 0x20, 12 | 'PAGE_EXECUTE_READWRITE' => 0x40, 'PAGE_EXECUTE_WRITECOPY' => 0x80, 13 | 'PAGE_NOACCESS' => 0x1, 'PAGE_READONLY' => 0x2, 14 | 'PAGE_READWRITE' => 0x4, 'PAGE_WRITECOPY' => 0x8} 15 | @@severityConstants = {0 => 'none', 1000 => 'low', 2000 => 'medium', 3000 => 'high', 4000 => 'critical'} 16 | @@severityStrings = {'none' => 0, 'low' => 1000, 'medium' => 2000, 'high' => 3000, 'critical' => 4000} 17 | 18 | def actionStr 19 | @@actions[self.action] 20 | end 21 | 22 | def arg_str 23 | arguments.map{ |arg| arg.to_s }.join(', ') 24 | end 25 | 26 | def setAction(actstr) 27 | self.action = @@actions.index(actstr) 28 | end 29 | 30 | def simplified 31 | defined = self.available_function.decl != nil 32 | simple = {'name' => self.name, 'action' => @@actions[self.action], 33 | 'function' => self.available_function.name, 'dll' => self.available_function.available_dll.name, 34 | 'arguments' => self.arguments.map{|a| a.simplified(defined)} } 35 | simple['modblacklist'] = self.modblacklist if self.modblacklist != nil and self.modblacklist.length > 0 36 | simple['modwhitelist'] = self.modwhitelist if self.modwhitelist != nil and self.modwhitelist.length > 0 37 | simple['procblacklist'] = self.procblacklist if self.procblacklist != nil and self.procblacklist.length > 0 38 | simple['procwhitelist'] = self.procwhitelist if self.procwhitelist != nil and self.procwhitelist.length > 0 39 | simple['retval'] = self.retval if self.action == 1 40 | if @@severityConstants.has_key? self.severity 41 | simple['severity'] = @@severityConstants[self.severity] 42 | else 43 | simple['severity'] = self.severity 44 | end 45 | if self.retprotectMode != 0 46 | if @@memconstants.has_key? self.retprotectMode 47 | simple['retprotectMode'] = @@memconstants[self.retprotectMode] 48 | else 49 | simple['retprotectMode'] = self.retprotectMode 50 | end 51 | end 52 | simple 53 | end 54 | 55 | def self.from_simplified(simple, set) 56 | #Get or create DLL 57 | dll = AvailableDll.find_or_create(simple['dll']) 58 | 59 | #Get or create function 60 | func = AvailableFunction.find_or_create(simple['function'], simple['arguments'], dll) 61 | 62 | #Create action 63 | act = Action.new(:action => @@actions.index(simple['action'].downcase), :available_function_id => func.id, 64 | :name => simple['name'], :signature_set_id => set.id, 65 | :modblacklist => simple['modblacklist'], :modwhitelist => simple['modwhitelist'], 66 | :procblacklist => simple['procblacklist'], :procwhitelist => simple['procwhitelist']) 67 | act.retval = simple['retval'] || 0 68 | 69 | #Severity 70 | if @@severityStrings.has_key? simple['severity'].downcase 71 | act.severity = @@severityStrings[simple['severity'].downcase] 72 | else 73 | act.severity = simple['severity'].to_i 74 | end 75 | 76 | #Return address conditions 77 | if simple['retprotectMode'] 78 | memmode = @@memmodes[simple['retprotectMode']] 79 | memmode = simple['retprotectMode'].to_i if memmode == nil 80 | act.retprotectMode = memmode 81 | else 82 | act.retprotectMode = 0 83 | end 84 | act.retprotectType = 0 85 | act.save 86 | 87 | #Create args 88 | parameters = func.parameters.all(:order => 'num') 89 | simple['arguments'].each_with_index do |simplearg, index| 90 | Argument.from_simplified(simplearg, parameters[index], act) 91 | end 92 | #we changed the sig set 93 | act.signature_set.markchanged 94 | end 95 | 96 | def compiled 97 | # action - required 98 | raise 'Error - must define an action' if self.action == nil 99 | # default type (PRE/POST) is PRE 100 | self.actiontype = 0 if self.actiontype == nil 101 | # default severity - Medium 102 | self.severity = 2000 if self.severity == nil 103 | # default retval - 0 104 | self.retval = 0 if self.retval == nil 105 | # args - required 106 | args = self.arguments.order('id') 107 | raise 'Error - no args' if args.length == 0 108 | # executable path black/white lists 109 | exeblack = ApplicationHelper.splitregex(self.procblacklist) 110 | exewhite = ApplicationHelper.splitregex(self.procwhitelist) 111 | # module black/white lists 112 | modblack = ApplicationHelper.splitregex(self.modblacklist) 113 | modwhite = ApplicationHelper.splitregex(self.modwhitelist) 114 | # put together output 115 | out = [self.id, self.action, self.severity, self.retval, self.actiontype, args.length, 116 | exeblack.length, exewhite.length, modblack.length, modwhite.length].pack("VVVQVVVVVV") 117 | # default retAddress - {} 118 | if self.retprotectMode == nil 119 | out << [0,0].pack('V*') 120 | else 121 | out << [self.retprotectType, self.retprotectMode].pack("V*") 122 | end 123 | # white/black lists 124 | out << exeblack + exewhite + modblack + modwhite 125 | # arguments 126 | args.each do |arg| 127 | out << arg.compiled 128 | end 129 | # size, id, action, severity, retval, type, numargs, exePathLen, retprotectType, retprotectMode, modPathLen, exePath[], modPath[], args[] 130 | [out.size + 4].pack("V*") + out 131 | end 132 | end 133 | -------------------------------------------------------------------------------- /HOWTO_setup_server.txt: -------------------------------------------------------------------------------- 1 | Ambush Server Setup 2 | 3 | ############################ 4 | The easy way with a rails VM 5 | ############################ 6 | 7 | If you do not have VMware, download and install the free player from http://www.vmware.com/products/player/ 8 | 9 | Then download the bitnami rubystack appliance (the version with ruby 1.9 and rails 3): 10 | http://bitnami.org/stack/rubystack#virtualMachine 11 | Start the VM and login 12 | 13 | Use these two commands to install Ambush: 14 | wget http://www.ambuships.com/files/installbitnami.sh 15 | sudo bash installbitnami.sh 16 | 17 | Go to the webpage at http://your.vm.ip:3000/ enter what you want your admin credentials to be, and then on the next screen, log in. 18 | You can then create a signature set and add signatures, and setup your clients; see HOWTO_setup_clients.txt 19 | 20 | 21 | ############################ 22 | Standalone - Windows 23 | ############################ 24 | If you do not have the Visual C++ 2008 Redistributable Package, install from http://www.microsoft.com/en-us/download/confirmation.aspx?id=29 25 | Download and install OpenSSL from http://slproweb.com/products/Win32OpenSSL.html 26 | The light installer will work fine; use the "Copy OpenSSL DLLs to:" "The Windows system directory" option. 27 | Important! Add C:\OpenSSL-Win32\bin\ to your system path. Run sysdm.cpl then go to Advanced->Environment Variables. Under System Variables, select Path then click Edit. Add C:\OpenSSL-Win32\bin\ 28 | Download and install the latest rails installer from http://railsinstaller.org/ including git 29 | (not the ruby 1.8.x) 30 | Open the railsinstaller command prompt with ruby and rails and change to the C:\sites directory and run these commands: 31 | git clone https://github.com/scriptjunkie/Ambush.git 32 | cd Ambush\server 33 | 34 | since this is a local development setup using sqlite3, you will need to add sqlite3 to your gemfile: 35 | echo gem "sqlite3", ">= 1.3.1" >> Gemfile 36 | bundle install 37 | rake db:setup 38 | 39 | You could start Ambush now with "rails server" and begin creating signatures. 40 | But, if you want Ambush to keep working on reboot, you need to install it as a service. 41 | Download https://github.com/downloads/luislavena/service_wrapper/service_wrapper-0.1.1-win32.zip 42 | Extract service_wrapper.exe from the bin directory in the zip file to C:\Sites\ 43 | and create a conf file C:\Sites\service_wrapper.conf containing the following five lines: 44 | [service] 45 | executable = C:\RailsInstaller\Ruby1.9.3\bin\ruby.exe 46 | arguments = C:\Sites\Ambush\server\script\rails s 47 | directory = C:\Sites\Ambush\ 48 | logfile = C:\Sites\Ambush\log\service_wrapper.log 49 | 50 | Then run these commands as administrator to create and run the project: 51 | sc create railsapp binPath= "C:\Sites\service_wrapper.exe C:\Sites\service_wrapper.conf" start= auto 52 | sc start railsapp 53 | 54 | Then go to http://localhost:3000/ 55 | Follow instructions to enter a user/pass for the admin 56 | Add a signature set and configure signatures 57 | Install C:\Sites\Ambush\client\Release\installer.msi 58 | Run: 59 | "C:\Program Files (x86)\Scriptjunkie Software\Ambush\config.exe" server localhost 1 60 | 61 | Where 1 is the number of your signature set. (drop the " (x86)" if on a 32 bit system) then run: 62 | "C:\Program Files (x86)\Scriptjunkie Software\Ambush\config.exe" update 63 | 64 | And you are all set up! 65 | 66 | ################################### 67 | The hard way with a manual VM setup 68 | ################################### 69 | 70 | # copy Ambush to the system 71 | cd /opt/bitnami/projects 72 | rm -rf * 73 | git clone https://github.com/scriptjunkie/Ambush.git . 74 | cd server 75 | chmod 777 app/assets/sigs 76 | chmod 777 public 77 | mkdir tmp 78 | chmod 777 tmp/ 79 | # setup your database information in /opt/bitnami/projects/server/config/database.yml 80 | # such as changing 'host: localhost' to 'socket: /opt/bitnami/mysql/tmp/mysql.sock' 81 | 82 | # get dependencies 83 | RAILS_ENV=production 84 | export RAILS_ENV 85 | bundle install 86 | 87 | #setup the database 88 | rake db:setup 89 | #restart apache 90 | /opt/bitnami/apache2/scripts/ctl.sh stop 91 | /opt/bitnami/apache2/scripts/ctl.sh start 92 | 93 | # setup autoupdate 94 | cd /tmp 95 | echo $(( $RANDOM % 60 )) $(( $RANDOM % 4 )) '* * * cd /opt/bitnami/projects/ && git pull origin master' > schedtemp 96 | crontab -u root schedtemp 97 | 98 | 99 | 100 | ###################################################### 101 | A local development setup with JRuby 102 | ###################################################### 103 | 104 | # Other configurations with ruby 1.9 should also be possible. 105 | 106 | #0. Ensure OpenSSL is installed and in your path. 107 | openssl -h 108 | # If not, download it from openssl.org or your distro. 109 | 110 | #1. Download and extract JRuby 111 | wget http://jruby.org.s3.amazonaws.com/downloads/1.6.5.1/jruby-bin-1.6.5.1.tar.gz 112 | tar -xvzf jruby-bin-1.6.5.1.tar.gz 113 | cd jruby-1.6.5.1/bin/ 114 | 115 | #1.5 Install rails 116 | ./jruby --1.9 gem install rails 117 | 118 | #1.5.1 Wait a while. Ho hum. Go get some coffee. 119 | 120 | #2. Check out the Ambush source 121 | cd ../.. 122 | git clone ssh://the.url.to.ambush.scriptjunkie/ambush.git 123 | cd ambush/server 124 | 125 | #3. Set up the gems and database (assuming the path to your jruby folder is ../../jruby-1.6.5.1/) 126 | ../../jruby-1.6.5.1/bin/jruby --1.9 ../../jruby-1.6.5.1/bin/bundle install 127 | ../../jruby-1.6.5.1/bin/jruby --1.9 ../../jruby-1.6.5.1/bin/rake db:setup 128 | 129 | #3.1 Wait a long time. Like go rent "Gettysburg" long time. Decent movie anyway. 130 | 131 | #4. Start your server 132 | ../../jruby-1.6.5.1/bin/jruby --1.9 script/rails server 133 | 134 | #5. Go to http://localhost:3000/ 135 | xdg-open http://localhost:3000/ 136 | 137 | #6. Follow instructions to enter a user/pass for the admin 138 | -------------------------------------------------------------------------------- /client/apihook/udis/syn-att.c: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * syn-att.c 3 | * 4 | * Copyright (c) 2004, 2005, 2006 Vivek Mohan 5 | * All rights reserved. See (LICENSE) 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "types.h" 10 | #include "extern.h" 11 | #include "decode.h" 12 | #include "itab.h" 13 | #include "syn.h" 14 | 15 | /* ----------------------------------------------------------------------------- 16 | * opr_cast() - Prints an operand cast. 17 | * ----------------------------------------------------------------------------- 18 | */ 19 | static void 20 | opr_cast(struct ud* u, struct ud_operand* op) 21 | { 22 | switch(op->size) { 23 | case 16 : case 32 : 24 | mkasm(u, "*"); break; 25 | default: break; 26 | } 27 | } 28 | 29 | /* ----------------------------------------------------------------------------- 30 | * gen_operand() - Generates assembly output for each operand. 31 | * ----------------------------------------------------------------------------- 32 | */ 33 | static void 34 | gen_operand(struct ud* u, struct ud_operand* op) 35 | { 36 | switch(op->type) { 37 | case UD_OP_REG: 38 | mkasm(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]); 39 | break; 40 | 41 | case UD_OP_MEM: 42 | if (u->br_far) opr_cast(u, op); 43 | if (u->pfx_seg) 44 | mkasm(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); 45 | if (op->offset == 8) { 46 | if (op->lval.sbyte < 0) 47 | mkasm(u, "-0x%x", (-op->lval.sbyte) & 0xff); 48 | else mkasm(u, "0x%x", op->lval.sbyte); 49 | } 50 | else if (op->offset == 16) 51 | mkasm(u, "0x%x", op->lval.uword); 52 | else if (op->offset == 32) 53 | mkasm(u, "0x%lx", op->lval.udword); 54 | else if (op->offset == 64) 55 | mkasm(u, "0x" FMT64 "x", op->lval.uqword); 56 | 57 | if (op->base) 58 | mkasm(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]); 59 | if (op->index) { 60 | if (op->base) 61 | mkasm(u, ","); 62 | else mkasm(u, "("); 63 | mkasm(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]); 64 | } 65 | if (op->scale) 66 | mkasm(u, ",%d", op->scale); 67 | if (op->base || op->index) 68 | mkasm(u, ")"); 69 | break; 70 | 71 | case UD_OP_IMM: 72 | switch (op->size) { 73 | case 8: mkasm(u, "$0x%x", op->lval.ubyte); break; 74 | case 16: mkasm(u, "$0x%x", op->lval.uword); break; 75 | case 32: mkasm(u, "$0x%lx", op->lval.udword); break; 76 | case 64: mkasm(u, "$0x" FMT64 "x", op->lval.uqword); break; 77 | default: break; 78 | } 79 | break; 80 | 81 | case UD_OP_JIMM: 82 | switch (op->size) { 83 | case 8: 84 | mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sbyte); 85 | break; 86 | case 16: 87 | mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sword); 88 | break; 89 | case 32: 90 | mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sdword); 91 | break; 92 | default:break; 93 | } 94 | break; 95 | 96 | case UD_OP_PTR: 97 | switch (op->size) { 98 | case 32: 99 | mkasm(u, "$0x%x, $0x%x", op->lval.ptr.seg, 100 | op->lval.ptr.off & 0xFFFF); 101 | break; 102 | case 48: 103 | mkasm(u, "$0x%x, $0x%lx", op->lval.ptr.seg, 104 | op->lval.ptr.off); 105 | break; 106 | } 107 | break; 108 | 109 | default: return; 110 | } 111 | } 112 | 113 | /* ============================================================================= 114 | * translates to AT&T syntax 115 | * ============================================================================= 116 | */ 117 | extern void 118 | ud_translate_att(struct ud *u) 119 | { 120 | int size = 0; 121 | 122 | /* check if P_OSO prefix is used */ 123 | if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) { 124 | switch (u->dis_mode) { 125 | case 16: 126 | mkasm(u, "o32 "); 127 | break; 128 | case 32: 129 | case 64: 130 | mkasm(u, "o16 "); 131 | break; 132 | } 133 | } 134 | 135 | /* check if P_ASO prefix was used */ 136 | if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) { 137 | switch (u->dis_mode) { 138 | case 16: 139 | mkasm(u, "a32 "); 140 | break; 141 | case 32: 142 | mkasm(u, "a16 "); 143 | break; 144 | case 64: 145 | mkasm(u, "a32 "); 146 | break; 147 | } 148 | } 149 | 150 | if (u->pfx_lock) 151 | mkasm(u, "lock "); 152 | if (u->pfx_rep) 153 | mkasm(u, "rep "); 154 | if (u->pfx_repne) 155 | mkasm(u, "repne "); 156 | 157 | /* special instructions */ 158 | switch (u->mnemonic) { 159 | case UD_Iretf: 160 | mkasm(u, "lret "); 161 | break; 162 | case UD_Idb: 163 | mkasm(u, ".byte 0x%x", u->operand[0].lval.ubyte); 164 | return; 165 | case UD_Ijmp: 166 | case UD_Icall: 167 | if (u->br_far) mkasm(u, "l"); 168 | mkasm(u, "%s", ud_lookup_mnemonic(u->mnemonic)); 169 | break; 170 | case UD_Ibound: 171 | case UD_Ienter: 172 | if (u->operand[0].type != UD_NONE) 173 | gen_operand(u, &u->operand[0]); 174 | if (u->operand[1].type != UD_NONE) { 175 | mkasm(u, ","); 176 | gen_operand(u, &u->operand[1]); 177 | } 178 | return; 179 | default: 180 | mkasm(u, "%s", ud_lookup_mnemonic(u->mnemonic)); 181 | } 182 | 183 | if (u->c1) 184 | size = u->operand[0].size; 185 | else if (u->c2) 186 | size = u->operand[1].size; 187 | else if (u->c3) 188 | size = u->operand[2].size; 189 | 190 | if (size == 8) 191 | mkasm(u, "b"); 192 | else if (size == 16) 193 | mkasm(u, "w"); 194 | else if (size == 64) 195 | mkasm(u, "q"); 196 | 197 | mkasm(u, " "); 198 | 199 | if (u->operand[2].type != UD_NONE) { 200 | gen_operand(u, &u->operand[2]); 201 | mkasm(u, ", "); 202 | } 203 | 204 | if (u->operand[1].type != UD_NONE) { 205 | gen_operand(u, &u->operand[1]); 206 | mkasm(u, ", "); 207 | } 208 | 209 | if (u->operand[0].type != UD_NONE) 210 | gen_operand(u, &u->operand[0]); 211 | } 212 | -------------------------------------------------------------------------------- /server/app/models/signature_set.rb: -------------------------------------------------------------------------------- 1 | require 'socket' 2 | class SignatureSet < ActiveRecord::Base 3 | has_many :actions, :dependent => :destroy 4 | # if the signature_version does not match what the client agents were built for, it 5 | # will trigger an update 6 | @@signature_version = 1.01 7 | 8 | def cachepath 9 | File.join(File.dirname(__FILE__), '..', 'assets', 'sigs', self.id.to_s + '_compiled') 10 | end 11 | 12 | def signaturepath 13 | File.join(File.dirname(__FILE__), '..', 'assets', 'sigs', self.id.to_s + '_signature') 14 | end 15 | 16 | def self.installerpath 17 | File.join(File.dirname(__FILE__), '..', '..', 'public', 'installer.msi') 18 | end 19 | 20 | def self.installersigpath 21 | File.join(File.dirname(__FILE__), '..', 'assets', 'sigs', 'installer_sig') 22 | end 23 | 24 | # provides a signature for an arbitrary block of data, cached with a file path 25 | def self.get_signature(sigpath) 26 | # use cached if present 27 | if File.file? sigpath 28 | fin = File.open(sigpath, 'rb') 29 | data = fin.read fin.stat.size 30 | fin.close 31 | return data 32 | end 33 | # otherwise generate and save 34 | data = sign(yield) 35 | fout = File.open(sigpath, 'wb') 36 | fout.write data 37 | fout.close 38 | data 39 | end 40 | 41 | # provides a signature for the compiled signature set 42 | def signature 43 | SignatureSet.get_signature(signaturepath){ self.compiled } 44 | end 45 | 46 | # provides a signature for the client binary installer 47 | def self.installer_sig 48 | self.get_signature(self.installersigpath) do 49 | fin = File.open(self.installerpath, 'rb') 50 | data = fin.read fin.stat.size 51 | fin.close 52 | data 53 | end 54 | end 55 | 56 | def markchanged 57 | File.unlink self.signaturepath if File.exists? self.signaturepath 58 | File.unlink self.cachepath if File.exists? self.cachepath 59 | end 60 | 61 | def compiled 62 | if File.file? self.cachepath 63 | fin = File.open(self.cachepath, 'rb') 64 | data = fin.read fin.stat.size 65 | fin.close 66 | return data 67 | end 68 | 69 | self.serial = 1 if self.serial == nil 70 | out = [@@signature_version, self.serial].pack('eV') 71 | reserved = '' # not currently used 72 | blist = ApplicationHelper.splitregex(self.procblacklist.to_s) # handles regex formatting, encoding and padding 73 | 74 | dlls = AvailableDll.find(:all,:joins => "INNER JOIN available_functions ON available_functions.available_dll_id = available_dlls.id INNER JOIN actions ON available_functions.id = actions.available_function_id",:select => 'DISTINCT(available_dlls.name),available_dlls.*') 75 | numdlls = 0 76 | temp = '' 77 | dlls.each do |dll| 78 | dlcompiled = dll.compiled(self.id) 79 | if(dlcompiled.length > 0) 80 | temp << dlcompiled 81 | numdlls += 1 82 | end 83 | end 84 | 85 | out << [numdlls, reserved.length, blist.length].pack("V*") + reserved + blist + temp 86 | # version, serialNumber, numdlls, pipeNameLen, pipeName, dlls[] 87 | fout = File.open(self.cachepath, 'wb') 88 | fout.write out 89 | fout.close 90 | out 91 | end 92 | 93 | # Key mgmt functions 94 | #Generate a new key pair 95 | def self.genkeys 96 | privkey = `openssl genrsa 2048` 97 | 98 | f = open(self.privpath, 'wb') 99 | f.write(privkey) 100 | f.close 101 | 102 | proc = IO.popen('openssl rsa -pubout','w+') 103 | proc.write(privkey) 104 | proc.close_write 105 | pubkey = proc.read 106 | proc.close 107 | 108 | f = open(self.pubpath, 'wb') 109 | f.write(pubkey) 110 | f.close 111 | end 112 | 113 | def self.pubpath 114 | File.join(File.dirname(__FILE__), '..', '..', 'public', 'public.key') 115 | end 116 | 117 | def self.privpath 118 | File.join(File.dirname(__FILE__), '..', 'assets', 'sigs', 'private.key') 119 | end 120 | 121 | def self.pubkey 122 | genkeys if not File.file? self.pubpath 123 | return IO.read(self.pubpath) 124 | end 125 | 126 | def self.sign(data) 127 | genkeys if not File.file? self.privpath 128 | proc = IO.popen('openssl dgst -sha1 -sign "' + self.privpath + '"','wb+') 129 | proc.write(data) 130 | proc.close_write 131 | dgst = proc.read 132 | proc.close 133 | dgst 134 | end 135 | 136 | def simplified 137 | {'version' => @@signature_version, 'procblacklist' => self.procblacklist, 'actions' => self.actions.map{|a| a.simplified} } 138 | end 139 | 140 | def self.from_simplified(simple, setid) 141 | # This is where we could do version checks with simple['version'] if the format changes 142 | if setid 143 | @signature_set = SignatureSet.find(setid) 144 | else 145 | @signature_set = SignatureSet.new() 146 | if simple['procblacklist'] 147 | @signature_set.procblacklist = simple['procblacklist'] 148 | end 149 | @signature_set.save 150 | end 151 | simple['actions'].each do |act| 152 | begin 153 | Action.from_simplified(act, @signature_set) 154 | rescue Exception => e 155 | Rails.logger.error e 156 | Rails.logger.error e.backtrace 157 | end 158 | end 159 | @signature_set 160 | end 161 | 162 | def to_yaml 163 | self.simplified.to_yaml 164 | end 165 | 166 | def getDefaultIp 167 | begin 168 | sock = UDPSocket.open 169 | sock.connect('1.2.3.4', 1234) 170 | add = sock.addr.last 171 | sock.close 172 | rescue ::Exception 173 | return '127.0.0.1' 174 | end 175 | add 176 | end 177 | 178 | # sends message to the aggregator 179 | def sendSyslog(message) 180 | return if self.aggregator == nil or self.aggregator.length == 0 181 | self.aggregator_port = 514 if self.aggregator_port == nil or self.aggregator_port == 0 182 | begin 183 | s = UDPSocket.new 184 | s.send message, 0, self.aggregator, self.aggregator_port 185 | s.close 186 | rescue Exception => e 187 | Rails.logger.error e 188 | Rails.logger.error e.backtrace 189 | end 190 | end 191 | end 192 | -------------------------------------------------------------------------------- /client/apihook/udis/syn-intel.c: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * syn-intel.c 3 | * 4 | * Copyright (c) 2002, 2003, 2004 Vivek Mohan 5 | * All rights reserved. See (LICENSE) 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "types.h" 10 | #include "extern.h" 11 | #include "decode.h" 12 | #include "itab.h" 13 | #include "syn.h" 14 | 15 | /* ----------------------------------------------------------------------------- 16 | * opr_cast() - Prints an operand cast. 17 | * ----------------------------------------------------------------------------- 18 | */ 19 | static void 20 | opr_cast(struct ud* u, struct ud_operand* op) 21 | { 22 | switch(op->size) { 23 | case 8: mkasm(u, "byte " ); break; 24 | case 16: mkasm(u, "word " ); break; 25 | case 32: mkasm(u, "dword "); break; 26 | case 64: mkasm(u, "qword "); break; 27 | case 80: mkasm(u, "tword "); break; 28 | default: break; 29 | } 30 | if (u->br_far) 31 | mkasm(u, "far "); 32 | else if (u->br_near) 33 | mkasm(u, "near "); 34 | } 35 | 36 | /* ----------------------------------------------------------------------------- 37 | * gen_operand() - Generates assembly output for each operand. 38 | * ----------------------------------------------------------------------------- 39 | */ 40 | static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast) 41 | { 42 | switch(op->type) { 43 | case UD_OP_REG: 44 | mkasm(u, ud_reg_tab[op->base - UD_R_AL]); 45 | break; 46 | 47 | case UD_OP_MEM: { 48 | 49 | int op_f = 0; 50 | 51 | if (syn_cast) 52 | opr_cast(u, op); 53 | 54 | mkasm(u, "["); 55 | 56 | if (u->pfx_seg) 57 | mkasm(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); 58 | 59 | if (op->base) { 60 | mkasm(u, "%s", ud_reg_tab[op->base - UD_R_AL]); 61 | op_f = 1; 62 | } 63 | 64 | if (op->index) { 65 | if (op_f) 66 | mkasm(u, "+"); 67 | mkasm(u, "%s", ud_reg_tab[op->index - UD_R_AL]); 68 | op_f = 1; 69 | } 70 | 71 | if (op->scale) 72 | mkasm(u, "*%d", op->scale); 73 | 74 | if (op->offset == 8) { 75 | if (op->lval.sbyte < 0) 76 | mkasm(u, "-0x%x", -op->lval.sbyte); 77 | else mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.sbyte); 78 | } 79 | else if (op->offset == 16) 80 | mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.uword); 81 | else if (op->offset == 32) { 82 | if (u->adr_mode == 64) { 83 | if (op->lval.sdword < 0) 84 | mkasm(u, "-0x%x", -op->lval.sdword); 85 | else mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.sdword); 86 | } 87 | else mkasm(u, "%s0x%lx", (op_f) ? "+" : "", op->lval.udword); 88 | } 89 | else if (op->offset == 64) 90 | mkasm(u, "%s0x" FMT64 "x", (op_f) ? "+" : "", op->lval.uqword); 91 | 92 | mkasm(u, "]"); 93 | break; 94 | } 95 | 96 | case UD_OP_IMM: 97 | if (syn_cast) opr_cast(u, op); 98 | switch (op->size) { 99 | case 8: mkasm(u, "0x%x", op->lval.ubyte); break; 100 | case 16: mkasm(u, "0x%x", op->lval.uword); break; 101 | case 32: mkasm(u, "0x%lx", op->lval.udword); break; 102 | case 64: mkasm(u, "0x" FMT64 "x", op->lval.uqword); break; 103 | default: break; 104 | } 105 | break; 106 | 107 | case UD_OP_JIMM: 108 | if (syn_cast) opr_cast(u, op); 109 | switch (op->size) { 110 | case 8: 111 | mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sbyte); 112 | break; 113 | case 16: 114 | mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sword); 115 | break; 116 | case 32: 117 | mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sdword); 118 | break; 119 | default:break; 120 | } 121 | break; 122 | 123 | case UD_OP_PTR: 124 | switch (op->size) { 125 | case 32: 126 | mkasm(u, "word 0x%x:0x%x", op->lval.ptr.seg, 127 | op->lval.ptr.off & 0xFFFF); 128 | break; 129 | case 48: 130 | mkasm(u, "dword 0x%x:0x%lx", op->lval.ptr.seg, 131 | op->lval.ptr.off); 132 | break; 133 | } 134 | break; 135 | 136 | case UD_OP_CONST: 137 | if (syn_cast) opr_cast(u, op); 138 | mkasm(u, "%d", op->lval.udword); 139 | break; 140 | 141 | default: return; 142 | } 143 | } 144 | 145 | /* ============================================================================= 146 | * translates to intel syntax 147 | * ============================================================================= 148 | */ 149 | extern void ud_translate_intel(struct ud* u) 150 | { 151 | /* -- prefixes -- */ 152 | 153 | /* check if P_OSO prefix is used */ 154 | if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) { 155 | switch (u->dis_mode) { 156 | case 16: 157 | mkasm(u, "o32 "); 158 | break; 159 | case 32: 160 | case 64: 161 | mkasm(u, "o16 "); 162 | break; 163 | } 164 | } 165 | 166 | /* check if P_ASO prefix was used */ 167 | if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) { 168 | switch (u->dis_mode) { 169 | case 16: 170 | mkasm(u, "a32 "); 171 | break; 172 | case 32: 173 | mkasm(u, "a16 "); 174 | break; 175 | case 64: 176 | mkasm(u, "a32 "); 177 | break; 178 | } 179 | } 180 | 181 | if (u->pfx_lock) 182 | mkasm(u, "lock "); 183 | if (u->pfx_rep) 184 | mkasm(u, "rep "); 185 | if (u->pfx_repne) 186 | mkasm(u, "repne "); 187 | if (u->implicit_addr && u->pfx_seg) 188 | mkasm(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]); 189 | 190 | /* print the instruction mnemonic */ 191 | mkasm(u, "%s ", ud_lookup_mnemonic(u->mnemonic)); 192 | 193 | /* operand 1 */ 194 | if (u->operand[0].type != UD_NONE) { 195 | gen_operand(u, &u->operand[0], u->c1); 196 | } 197 | /* operand 2 */ 198 | if (u->operand[1].type != UD_NONE) { 199 | mkasm(u, ", "); 200 | gen_operand(u, &u->operand[1], u->c2); 201 | } 202 | 203 | /* operand 3 */ 204 | if (u->operand[2].type != UD_NONE) { 205 | mkasm(u, ", "); 206 | gen_operand(u, &u->operand[2], u->c3); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /client/apihook/udis/types.h: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * types.h 3 | * 4 | * Copyright (c) 2006, Vivek Mohan 5 | * All rights reserved. See LICENSE 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | #ifndef UD_TYPES_H 9 | #define UD_TYPES_H 10 | 11 | #include 12 | 13 | #ifdef _MSC_VER 14 | # define FMT64 "%I64" 15 | typedef unsigned __int8 uint8_t; 16 | typedef unsigned __int16 uint16_t; 17 | typedef unsigned __int32 uint32_t; 18 | typedef unsigned __int64 uint64_t; 19 | typedef __int8 int8_t; 20 | typedef __int16 int16_t; 21 | typedef __int32 int32_t; 22 | typedef __int64 int64_t; 23 | #else 24 | # define FMT64 "%ll" 25 | # include 26 | #endif 27 | 28 | #include "itab.h" 29 | 30 | /* ----------------------------------------------------------------------------- 31 | * All possible "types" of objects in udis86. Order is Important! 32 | * ----------------------------------------------------------------------------- 33 | */ 34 | enum ud_type 35 | { 36 | UD_NONE, 37 | 38 | /* 8 bit GPRs */ 39 | UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL, 40 | UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH, 41 | UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL, 42 | UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B, 43 | UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B, 44 | 45 | /* 16 bit GPRs */ 46 | UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX, 47 | UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI, 48 | UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W, 49 | UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W, 50 | 51 | /* 32 bit GPRs */ 52 | UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX, 53 | UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI, 54 | UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D, 55 | UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D, 56 | 57 | /* 64 bit GPRs */ 58 | UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX, 59 | UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI, 60 | UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11, 61 | UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15, 62 | 63 | /* segment registers */ 64 | UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS, 65 | UD_R_FS, UD_R_GS, 66 | 67 | /* control registers*/ 68 | UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3, 69 | UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7, 70 | UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11, 71 | UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15, 72 | 73 | /* debug registers */ 74 | UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3, 75 | UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7, 76 | UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11, 77 | UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15, 78 | 79 | /* mmx registers */ 80 | UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3, 81 | UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7, 82 | 83 | /* x87 registers */ 84 | UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3, 85 | UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7, 86 | 87 | /* extended multimedia registers */ 88 | UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3, 89 | UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7, 90 | UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11, 91 | UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15, 92 | 93 | UD_R_RIP, 94 | 95 | /* Operand Types */ 96 | UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM, 97 | UD_OP_JIMM, UD_OP_CONST 98 | }; 99 | 100 | /* ----------------------------------------------------------------------------- 101 | * struct ud_operand - Disassembled instruction Operand. 102 | * ----------------------------------------------------------------------------- 103 | */ 104 | struct ud_operand 105 | { 106 | enum ud_type type; 107 | uint8_t size; 108 | union { 109 | int8_t sbyte; 110 | uint8_t ubyte; 111 | int16_t sword; 112 | uint16_t uword; 113 | int32_t sdword; 114 | uint32_t udword; 115 | int64_t sqword; 116 | uint64_t uqword; 117 | 118 | struct { 119 | uint16_t seg; 120 | uint32_t off; 121 | } ptr; 122 | } lval; 123 | 124 | enum ud_type base; 125 | enum ud_type index; 126 | uint8_t offset; 127 | uint8_t scale; 128 | }; 129 | 130 | /* ----------------------------------------------------------------------------- 131 | * struct ud - The udis86 object. 132 | * ----------------------------------------------------------------------------- 133 | */ 134 | struct ud 135 | { 136 | int (*inp_hook) (struct ud*); 137 | uint8_t inp_curr; 138 | uint8_t inp_fill; 139 | FILE* inp_file; 140 | uint8_t inp_ctr; 141 | uint8_t* inp_buff; 142 | uint8_t* inp_buff_end; 143 | uint8_t inp_end; 144 | void (*translator)(struct ud*); 145 | uint64_t insn_offset; 146 | char insn_hexcode[32]; 147 | char insn_buffer[64]; 148 | unsigned int insn_fill; 149 | uint8_t dis_mode; 150 | uint64_t pc; 151 | uint8_t vendor; 152 | struct map_entry* mapen; 153 | enum ud_mnemonic_code mnemonic; 154 | struct ud_operand operand[3]; 155 | uint8_t error; 156 | uint8_t pfx_rex; 157 | uint8_t pfx_seg; 158 | uint8_t pfx_opr; 159 | uint8_t pfx_adr; 160 | uint8_t pfx_lock; 161 | uint8_t pfx_rep; 162 | uint8_t pfx_repe; 163 | uint8_t pfx_repne; 164 | uint8_t pfx_insn; 165 | uint8_t default64; 166 | uint8_t opr_mode; 167 | uint8_t adr_mode; 168 | uint8_t br_far; 169 | uint8_t br_near; 170 | uint8_t implicit_addr; 171 | uint8_t c1; 172 | uint8_t c2; 173 | uint8_t c3; 174 | uint8_t inp_cache[256]; 175 | uint8_t inp_sess[64]; 176 | struct ud_itab_entry * itab_entry; 177 | }; 178 | 179 | /* ----------------------------------------------------------------------------- 180 | * Type-definitions 181 | * ----------------------------------------------------------------------------- 182 | */ 183 | typedef enum ud_type ud_type_t; 184 | typedef enum ud_mnemonic_code ud_mnemonic_code_t; 185 | 186 | typedef struct ud ud_t; 187 | typedef struct ud_operand ud_operand_t; 188 | 189 | #define UD_SYN_INTEL ud_translate_intel 190 | #define UD_SYN_ATT ud_translate_att 191 | #define UD_EOI -1 192 | #define UD_INP_CACHE_SZ 32 193 | #define UD_VENDOR_AMD 0 194 | #define UD_VENDOR_INTEL 1 195 | 196 | #define bail_out(ud,error_code) longjmp( (ud)->bailout, error_code ) 197 | #define try_decode(ud) if ( setjmp( (ud)->bailout ) == 0 ) 198 | #define catch_error() else 199 | 200 | #endif 201 | -------------------------------------------------------------------------------- /client/apihook/udis/input.c: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | * input.c 3 | * 4 | * Copyright (c) 2004, 2005, 2006, Vivek Mohan 5 | * All rights reserved. See LICENSE 6 | * ----------------------------------------------------------------------------- 7 | */ 8 | #include "extern.h" 9 | #include "types.h" 10 | #include "input.h" 11 | 12 | /* ----------------------------------------------------------------------------- 13 | * inp_buff_hook() - Hook for buffered inputs. 14 | * ----------------------------------------------------------------------------- 15 | */ 16 | static int 17 | inp_buff_hook(struct ud* u) 18 | { 19 | if (u->inp_buff < u->inp_buff_end) 20 | return *u->inp_buff++; 21 | else return -1; 22 | } 23 | 24 | #ifndef __UD_STANDALONE__ 25 | /* ----------------------------------------------------------------------------- 26 | * inp_file_hook() - Hook for FILE inputs. 27 | * ----------------------------------------------------------------------------- 28 | */ 29 | static int 30 | inp_file_hook(struct ud* u) 31 | { 32 | return fgetc(u->inp_file); 33 | } 34 | #endif /* __UD_STANDALONE__*/ 35 | 36 | /* ============================================================================= 37 | * ud_inp_set_hook() - Sets input hook. 38 | * ============================================================================= 39 | */ 40 | extern void 41 | ud_set_input_hook(register struct ud* u, int (*hook)(struct ud*)) 42 | { 43 | u->inp_hook = hook; 44 | inp_init(u); 45 | } 46 | 47 | /* ============================================================================= 48 | * ud_inp_set_buffer() - Set buffer as input. 49 | * ============================================================================= 50 | */ 51 | extern void 52 | ud_set_input_buffer(register struct ud* u, uint8_t* buf, size_t len) 53 | { 54 | u->inp_hook = inp_buff_hook; 55 | u->inp_buff = buf; 56 | u->inp_buff_end = buf + len; 57 | inp_init(u); 58 | } 59 | 60 | #ifndef __UD_STANDALONE__ 61 | /* ============================================================================= 62 | * ud_input_set_file() - Set buffer as input. 63 | * ============================================================================= 64 | */ 65 | extern void 66 | ud_set_input_file(register struct ud* u, FILE* f) 67 | { 68 | u->inp_hook = inp_file_hook; 69 | u->inp_file = f; 70 | inp_init(u); 71 | } 72 | #endif /* __UD_STANDALONE__ */ 73 | 74 | /* ============================================================================= 75 | * ud_input_skip() - Skip n input bytes. 76 | * ============================================================================= 77 | */ 78 | extern void 79 | ud_input_skip(struct ud* u, size_t n) 80 | { 81 | while (n--) { 82 | u->inp_hook(u); 83 | } 84 | } 85 | 86 | /* ============================================================================= 87 | * ud_input_end() - Test for end of input. 88 | * ============================================================================= 89 | */ 90 | extern int 91 | ud_input_end(struct ud* u) 92 | { 93 | return (u->inp_curr == u->inp_fill) && u->inp_end; 94 | } 95 | 96 | /* ----------------------------------------------------------------------------- 97 | * inp_next() - Loads and returns the next byte from input. 98 | * 99 | * inp_curr and inp_fill are pointers to the cache. The program is written based 100 | * on the property that they are 8-bits in size, and will eventually wrap around 101 | * forming a circular buffer. So, the size of the cache is 256 in size, kind of 102 | * unnecessary yet optimized. 103 | * 104 | * A buffer inp_sess stores the bytes disassembled for a single session. 105 | * ----------------------------------------------------------------------------- 106 | */ 107 | extern uint8_t inp_next(struct ud* u) 108 | { 109 | int c = -1; 110 | /* if current pointer is not upto the fill point in the 111 | * input cache. 112 | */ 113 | if ( u->inp_curr != u->inp_fill ) { 114 | c = u->inp_cache[ ++u->inp_curr ]; 115 | /* if !end-of-input, call the input hook and get a byte */ 116 | } else if ( u->inp_end || ( c = u->inp_hook( u ) ) == -1 ) { 117 | /* end-of-input, mark it as an error, since the decoder, 118 | * expected a byte more. 119 | */ 120 | u->error = 1; 121 | /* flag end of input */ 122 | u->inp_end = 1; 123 | return 0; 124 | } else { 125 | /* increment pointers, we have a new byte. */ 126 | u->inp_curr = ++u->inp_fill; 127 | /* add the byte to the cache */ 128 | u->inp_cache[ u->inp_fill ] = c; 129 | } 130 | /* record bytes input per decode-session. */ 131 | u->inp_sess[ u->inp_ctr++ ] = c; 132 | /* return byte */ 133 | return ( uint8_t ) c; 134 | } 135 | 136 | /* ----------------------------------------------------------------------------- 137 | * inp_back() - Move back a single byte in the stream. 138 | * ----------------------------------------------------------------------------- 139 | */ 140 | extern void 141 | inp_back(struct ud* u) 142 | { 143 | if ( u->inp_ctr > 0 ) { 144 | --u->inp_curr; 145 | --u->inp_ctr; 146 | } 147 | } 148 | 149 | /* ----------------------------------------------------------------------------- 150 | * inp_peek() - Peek into the next byte in source. 151 | * ----------------------------------------------------------------------------- 152 | */ 153 | extern uint8_t 154 | inp_peek(struct ud* u) 155 | { 156 | uint8_t r = inp_next(u); 157 | if ( !u->error ) inp_back(u); /* Don't backup if there was an error */ 158 | return r; 159 | } 160 | 161 | /* ----------------------------------------------------------------------------- 162 | * inp_move() - Move ahead n input bytes. 163 | * ----------------------------------------------------------------------------- 164 | */ 165 | extern void 166 | inp_move(struct ud* u, size_t n) 167 | { 168 | while (n--) 169 | inp_next(u); 170 | } 171 | 172 | /*------------------------------------------------------------------------------ 173 | * inp_uintN() - return uintN from source. 174 | *------------------------------------------------------------------------------ 175 | */ 176 | extern uint8_t 177 | inp_uint8(struct ud* u) 178 | { 179 | return inp_next(u); 180 | } 181 | 182 | extern uint16_t 183 | inp_uint16(struct ud* u) 184 | { 185 | uint16_t r, ret; 186 | 187 | ret = inp_next(u); 188 | r = inp_next(u); 189 | return ret | (r << 8); 190 | } 191 | 192 | extern uint32_t 193 | inp_uint32(struct ud* u) 194 | { 195 | uint32_t r, ret; 196 | 197 | ret = inp_next(u); 198 | r = inp_next(u); 199 | ret = ret | (r << 8); 200 | r = inp_next(u); 201 | ret = ret | (r << 16); 202 | r = inp_next(u); 203 | return ret | (r << 24); 204 | } 205 | 206 | extern uint64_t 207 | inp_uint64(struct ud* u) 208 | { 209 | uint64_t r, ret; 210 | 211 | ret = inp_next(u); 212 | r = inp_next(u); 213 | ret = ret | (r << 8); 214 | r = inp_next(u); 215 | ret = ret | (r << 16); 216 | r = inp_next(u); 217 | ret = ret | (r << 24); 218 | r = inp_next(u); 219 | ret = ret | (r << 32); 220 | r = inp_next(u); 221 | ret = ret | (r << 40); 222 | r = inp_next(u); 223 | ret = ret | (r << 48); 224 | r = inp_next(u); 225 | return ret | (r << 56); 226 | } 227 | -------------------------------------------------------------------------------- /client/apihook/apihook.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 30 | 33 | 36 | 39 | 42 | 45 | 59 | 62 | 65 | 68 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 98 | 99 | 105 | 108 | 111 | 114 | 117 | 120 | 128 | 131 | 134 | 137 | 142 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | 173 | 176 | 177 | 180 | 181 | 184 | 185 | 188 | 189 | 192 | 193 | 196 | 197 | 200 | 203 | 204 | 207 | 208 | 211 | 212 | 215 | 216 | 219 | 220 | 223 | 224 | 227 | 228 | 229 | 230 | 235 | 238 | 239 | 242 | 243 | 246 | 247 | 250 | 251 | 254 | 255 | 258 | 259 | 262 | 263 | 266 | 267 | 270 | 271 | 274 | 275 | 278 | 281 | 282 | 285 | 286 | 289 | 290 | 293 | 294 | 297 | 298 | 301 | 302 | 303 | 304 | 309 | 312 | 315 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | --------------------------------------------------------------------------------