├── README.md ├── pe-clj ├── resources │ └── fixtures │ │ └── kernel32.dll ├── .gitignore ├── src │ └── pe │ │ └── macros.clj ├── project.clj ├── README.md ├── test │ └── pe │ │ └── core_test.clj └── LICENSE ├── capstone-clj ├── doc │ └── intro.md ├── .gitignore ├── README.md ├── CHANGELOG.md ├── src │ └── capstone_clj │ │ └── core.clj ├── test │ └── capstone_clj │ │ └── core_test.clj ├── project.clj └── LICENSE ├── unicorn-clj ├── doc │ └── intro.md ├── .gitignore ├── project.clj ├── README.md ├── CHANGELOG.md ├── test │ └── unicorn_clj │ │ └── core_test.clj ├── src │ └── unicorn_clj │ │ └── core.clj └── LICENSE ├── lancelot-clj ├── resources │ ├── fixtures │ │ └── kernel32.dll │ ├── api-schema.edn │ └── public │ │ ├── graphiql │ │ └── index.html │ │ └── client │ │ └── index.html ├── src │ ├── lancelot_cljs │ │ ├── config.cljs │ │ ├── devtools.cljs │ │ ├── db.cljs │ │ ├── utils.cljs │ │ ├── common.cljs │ │ ├── core.cljs │ │ ├── subs.cljs │ │ ├── layout │ │ │ ├── dagre.cljs │ │ │ └── klay.cljs │ │ ├── api.cljs │ │ ├── events.cljs │ │ └── views.cljs │ ├── log4j.properties │ └── lancelot_clj │ │ ├── interactive.clj │ │ ├── core.clj │ │ ├── dis.clj │ │ ├── api.clj │ │ ├── schema.clj │ │ ├── workspace.clj │ │ └── anal.clj ├── .gitignore ├── README.md ├── test │ └── lancelot_clj │ │ ├── testutils.clj │ │ ├── test_workspace.clj │ │ ├── dis_test.clj │ │ └── anal_test.clj ├── dev-resources │ └── user.clj ├── project.clj └── LICENSE ├── construct-clj ├── .gitignore ├── project.clj ├── README.md ├── DESIGN.md ├── test │ └── construct_clj │ │ └── core_test.clj └── LICENSE ├── .gitignore ├── Dockerfile └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # clojure-re 2 | messing around writing reversing tools in clojure 3 | -------------------------------------------------------------------------------- /pe-clj/resources/fixtures/kernel32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williballenthin/reversing-clj/HEAD/pe-clj/resources/fixtures/kernel32.dll -------------------------------------------------------------------------------- /capstone-clj/doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to capstone-clj 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /unicorn-clj/doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to unicorn-clj 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /lancelot-clj/resources/fixtures/kernel32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williballenthin/reversing-clj/HEAD/lancelot-clj/resources/fixtures/kernel32.dll -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/config.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot_cljs.config) 2 | 3 | ;; resource prefix for the binary analysis API 4 | (def api-base-url "/api/cmd") 5 | 6 | -------------------------------------------------------------------------------- /pe-clj/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /capstone-clj/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /unicorn-clj/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /construct-clj/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /lancelot-clj/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | resources/public/client/js/ 13 | -------------------------------------------------------------------------------- /lancelot-clj/src/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=WARN, console 2 | log4j.appender.console=org.apache.log4j.ConsoleAppender 3 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 4 | log4j.appender.console.layout.ConversionPattern=%-5p %c: %m%n -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/devtools.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot_cljs.devtools 2 | (:require [devtools.core :as devtools])) 3 | 4 | (devtools/set-pref! :fn-symbol "F") 5 | (devtools/set-pref! :print-config-overrides true) 6 | (devtools/install! [:formatters :hints]) 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | pom.xml.asc 3 | *.jar 4 | *.class 5 | /lib/ 6 | /classes/ 7 | /target/ 8 | /checkouts/ 9 | .lein-deps-sum 10 | .lein-repl-history 11 | .lein-plugins/ 12 | .lein-failures 13 | .nrepl-port 14 | *~ 15 | *' 16 | /lancelot-clj/resources/public/client/js/cfg/api.js 17 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/db.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot-cljs.db) 2 | 3 | ;; client db schema: 4 | ;; 5 | ;; { 6 | ;; :samples [{:md5 "" :sha1 ""} ...] 7 | ;; :sample "" 8 | ;; :functions [{:va int} ...] 9 | ;; :function int 10 | ;; :blocks 11 | ;; :edges 12 | ;; :insns 13 | ;; } 14 | -------------------------------------------------------------------------------- /construct-clj/project.clj: -------------------------------------------------------------------------------- 1 | (defproject construct-clj "0.1.0-SNAPSHOT" 2 | :description "FIXME: write description" 3 | :url "http://example.com/FIXME" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.8.0"]] 7 | :main ^:skip-aot construct-clj.core 8 | :target-path "target/%s" 9 | :profiles {:uberjar {:aot :all}}) 10 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/utils.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot-cljs.utils) 2 | 3 | (defn index-by 4 | " 5 | create a map indexed by the given key of the given collection. 6 | like `group-by`, except its assumed there's only one value per key. 7 | 8 | example:: 9 | 10 | (index-by [{:a 1 :b 2} {:a 3 :b 4}] :a) 11 | => {1 {:a 1 :b 2} 12 | 3 {:a 3 :b 4}} 13 | " 14 | [f col] 15 | (into {} (map #(vector (apply f [%]) %) col))) 16 | 17 | -------------------------------------------------------------------------------- /pe-clj/src/pe/macros.clj: -------------------------------------------------------------------------------- 1 | (ns pe.macros) 2 | 3 | 4 | (defmacro with-position 5 | " 6 | temporarily work with the given byte buffer at the given position. 7 | restores the position to its original value upon leaving this block. 8 | " 9 | [byte-buffer pos & body] 10 | `(let [orig-position# (.position ~byte-buffer)] 11 | (.position ~byte-buffer ~pos) 12 | (let [res# (do ~@body)] 13 | (.position ~byte-buffer orig-position#) 14 | res#))) 15 | 16 | 17 | -------------------------------------------------------------------------------- /unicorn-clj/project.clj: -------------------------------------------------------------------------------- 1 | (defproject unicorn-clj "0.1.0-SNAPSHOT" 2 | :description "FIXME: write description" 3 | :url "http://example.com/FIXME" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.8.0"] 7 | [net.java.dev.jna/jna "4.1.0"]] 8 | :resource-paths ["resources/unicorn.jar"] 9 | :main ^:skip-aot unicorn-clj.core 10 | :target-path "target/%s" 11 | :profiles {:uberjar {:aot :all}}) 12 | -------------------------------------------------------------------------------- /pe-clj/project.clj: -------------------------------------------------------------------------------- 1 | (defproject com.williballenthin/pe "0.1.0-SNAPSHOT" 2 | :description "A library for parsing Microsoft PE/COFF files." 3 | :url "https://github.com/williballenthin/reversing-clj/tree/master/pe-clj" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :source-paths ["src"] 7 | :dependencies [[org.clojure/clojure "1.8.0"] 8 | [clojurewerkz/buffy "1.1.0"] 9 | [org.clojure/tools.logging "0.4.0"]] 10 | :target-path "target/%s" 11 | :profiles {:uberjar {:aot :all}}) 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM clojure 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y make gcc libjna-java 5 | 6 | # build capstone 7 | RUN git clone https://github.com/aquynh/capstone.git /tmp/capstone 8 | RUN cd /tmp/capstone && ./make.sh && ./make.sh install 9 | # build capstone-java bindings 10 | RUN cd /tmp/capstone/bindings/java && make 11 | 12 | # build unicorn 13 | RUN git clone https://github.com/unicorn-engine/unicorn.git /tmp/unicorn 14 | RUN cd /tmp/unicorn && ./make.sh && ./make.sh install 15 | # build unicorn-java bindings 16 | RUN cd /tmp/unicorn/bindings/java && make install && make samples 17 | 18 | 19 | -------------------------------------------------------------------------------- /pe-clj/README.md: -------------------------------------------------------------------------------- 1 | # pe-clj 2 | 3 | FIXME: description 4 | 5 | ## Installation 6 | 7 | Download from http://example.com/FIXME. 8 | 9 | ## Usage 10 | 11 | FIXME: explanation 12 | 13 | $ java -jar pe-clj-0.1.0-standalone.jar [args] 14 | 15 | ## Options 16 | 17 | FIXME: listing of options this app accepts. 18 | 19 | ## Examples 20 | 21 | ... 22 | 23 | ### Bugs 24 | 25 | ... 26 | 27 | ### Any Other Sections 28 | ### That You Think 29 | ### Might be Useful 30 | 31 | ## License 32 | 33 | Copyright © 2017 FIXME 34 | 35 | Distributed under the Eclipse Public License either version 1.0 or (at 36 | your option) any later version. 37 | -------------------------------------------------------------------------------- /unicorn-clj/README.md: -------------------------------------------------------------------------------- 1 | # unicorn-clj 2 | 3 | FIXME: description 4 | 5 | ## Installation 6 | 7 | Download from http://example.com/FIXME. 8 | 9 | ## Usage 10 | 11 | FIXME: explanation 12 | 13 | $ java -jar unicorn-clj-0.1.0-standalone.jar [args] 14 | 15 | ## Options 16 | 17 | FIXME: listing of options this app accepts. 18 | 19 | ## Examples 20 | 21 | ... 22 | 23 | ### Bugs 24 | 25 | ... 26 | 27 | ### Any Other Sections 28 | ### That You Think 29 | ### Might be Useful 30 | 31 | ## License 32 | 33 | Copyright © 2017 FIXME 34 | 35 | Distributed under the Eclipse Public License either version 1.0 or (at 36 | your option) any later version. 37 | -------------------------------------------------------------------------------- /construct-clj/README.md: -------------------------------------------------------------------------------- 1 | # construct-clj 2 | 3 | FIXME: description 4 | 5 | ## Installation 6 | 7 | Download from http://example.com/FIXME. 8 | 9 | ## Usage 10 | 11 | FIXME: explanation 12 | 13 | $ java -jar construct-clj-0.1.0-standalone.jar [args] 14 | 15 | ## Options 16 | 17 | FIXME: listing of options this app accepts. 18 | 19 | ## Examples 20 | 21 | ... 22 | 23 | ### Bugs 24 | 25 | ... 26 | 27 | ### Any Other Sections 28 | ### That You Think 29 | ### Might be Useful 30 | 31 | ## License 32 | 33 | Copyright © 2017 FIXME 34 | 35 | Distributed under the Eclipse Public License either version 1.0 or (at 36 | your option) any later version. 37 | -------------------------------------------------------------------------------- /lancelot-clj/README.md: -------------------------------------------------------------------------------- 1 | # lancelot-clj 2 | 3 | Lancelot is a binary analysis framework. 4 | 5 | ## Installation 6 | 7 | requirements: 8 | 9 | - capstone-clj (make available native library & `lein install`) 10 | - pe-clj (`lein install`) 11 | 12 | ## Building 13 | 14 | ### analyzer/server 15 | 16 | $ lein uberjar 17 | 18 | ### client 19 | 20 | $ lein cljsbuild once client-dev 21 | 22 | for figwheel: 23 | 24 | $ lein figwheel 25 | 26 | ## Tests 27 | 28 | lein test 29 | 30 | ## Usage 31 | 32 | FIXME: explanation 33 | 34 | $ java -jar lancelot-clj-0.1.0-standalone.jar [args] 35 | 36 | ## License 37 | 38 | Copyright © 2017 William Ballenthin 39 | 40 | Distributed under the Eclipse Public License either version 1.0 or (at 41 | your option) any later version. 42 | -------------------------------------------------------------------------------- /capstone-clj/README.md: -------------------------------------------------------------------------------- 1 | # capstone-clj 2 | 3 | This is a Clojure wrapper library for the Capstone disassembly engine. 4 | 5 | ## Installation 6 | 7 | Dependencies: 8 | 9 | - capstone native library 10 | - on linux: install capstone from apt or source 11 | - on windows: consider placing this in your $PATH 12 | 13 | ## Usage 14 | 15 | This is a library for disassembling bytes into instructions. 16 | It doesn't do much as a standalone executable. 17 | See the unit tests for examples of how to invoke its routines. 18 | 19 | ## Examples 20 | 21 | #### test 22 | ``` 23 | $ lein test 24 | ``` 25 | 26 | #### build uberjar: 27 | ``` 28 | $ lein uberjar 29 | ``` 30 | 31 | ## License 32 | 33 | Copyright © 2017 Willi Ballenthin 34 | 35 | Distributed under the Eclipse Public License either version 1.0 or (at 36 | your option) any later version. 37 | -------------------------------------------------------------------------------- /unicorn-clj/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## [Unreleased] 5 | ### Changed 6 | - Add a new arity to `make-widget-async` to provide a different widget shape. 7 | 8 | ## [0.1.1] - 2017-05-30 9 | ### Changed 10 | - Documentation on how to make the widgets. 11 | 12 | ### Removed 13 | - `make-widget-sync` - we're all async, all the time. 14 | 15 | ### Fixed 16 | - Fixed widget maker to keep working when daylight savings switches over. 17 | 18 | ## 0.1.0 - 2017-05-30 19 | ### Added 20 | - Files from the new template. 21 | - Widget maker public API - `make-widget-sync`. 22 | 23 | [Unreleased]: https://github.com/your-name/unicorn-clj/compare/0.1.1...HEAD 24 | [0.1.1]: https://github.com/your-name/unicorn-clj/compare/0.1.0...0.1.1 25 | -------------------------------------------------------------------------------- /capstone-clj/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## [Unreleased] 5 | ### Changed 6 | - Add a new arity to `make-widget-async` to provide a different widget shape. 7 | 8 | ## [0.1.1] - 2017-05-30 9 | ### Changed 10 | - Documentation on how to make the widgets. 11 | 12 | ### Removed 13 | - `make-widget-sync` - we're all async, all the time. 14 | 15 | ### Fixed 16 | - Fixed widget maker to keep working when daylight savings switches over. 17 | 18 | ## 0.1.0 - 2017-05-30 19 | ### Added 20 | - Files from the new template. 21 | - Widget maker public API - `make-widget-sync`. 22 | 23 | [Unreleased]: https://github.com/your-name/capstone-clj/compare/0.1.1...HEAD 24 | [0.1.1]: https://github.com/your-name/capstone-clj/compare/0.1.0...0.1.1 25 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_clj/interactive.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.interactive 2 | (:require 3 | [pe.core :as pe] 4 | [pe.macros :as pe-macros] 5 | [lancelot-clj.dis :refer :all] 6 | [lancelot-clj.anal :refer :all] 7 | [lancelot-clj.core :refer :all] 8 | [clojure.java.io :as io] 9 | [clojure.set :as set] 10 | [clojure.tools.logging :as log] 11 | [lancelot-clj.schema :as s] 12 | [com.walmartlabs.lacinia.util :as util] 13 | [com.walmartlabs.lacinia.schema :as schema] 14 | [com.walmartlabs.lacinia :as lacinia] 15 | [com.walmartlabs.lacinia.pedestal :as lp] 16 | [io.pedestal.http :as http] 17 | [io.pedestal.http.route :as route] 18 | [io.pedestal.http.route.definition.table :as table] 19 | [io.pedestal.http.ring-middlewares :as middlewares] 20 | [io.pedestal.http.secure-headers :as secure-headers] 21 | [clojure.java.browse :refer [browse-url]] 22 | [clojure.tools.logging :as log])) 23 | -------------------------------------------------------------------------------- /lancelot-clj/test/lancelot_clj/testutils.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.testutils 2 | (:require[clojure.java.io :as io]) 3 | (:import (java.nio ByteBuffer ByteOrder)) 4 | (:import [capstone.Capstone]) 5 | (:import [capstone.X86_const])) 6 | 7 | 8 | (defn make-byte-buffer 9 | [byte-list] 10 | (let [bytes (byte-array byte-list) 11 | byte-buffer (ByteBuffer/allocate (count bytes)) 12 | _ (.put byte-buffer bytes) 13 | _ (.order byte-buffer ByteOrder/LITTLE_ENDIAN)] 14 | byte-buffer)) 15 | 16 | 17 | ;; via: https://stackoverflow.com/a/29587909 18 | (defn boolean? [x] 19 | (instance? Boolean x)) 20 | 21 | 22 | (defn make-capstone 23 | ([arch mode detail] 24 | (let [cs (capstone.Capstone. arch mode) 25 | _ (.setSyntax cs capstone.Capstone/CS_OPT_SYNTAX_INTEL) 26 | _ (.setDetail cs (if (boolean? detail) 27 | (if detail 1 0) 28 | detail))] 29 | cs)) 30 | ([arch mode] 31 | (make-capstone arch mode 1))) 32 | 33 | 34 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_clj/core.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.core 2 | (:gen-class) 3 | (:require 4 | [io.pedestal.http :as http] 5 | [lancelot-clj.api :as api] 6 | [lancelot-clj.anal :as analysis] 7 | [lancelot-clj.schema :as schema] 8 | [lancelot-clj.workspace :as workspace] 9 | ) 10 | (:import (ch.qos.logback.classic Logger Level))) 11 | 12 | #_(defmethod print-method Number 13 | [n ^java.io.Writer w] 14 | (.write w (format "0x%X" n))) 15 | 16 | (defn -main 17 | [& args] 18 | ;; logging level should really be set by some configuration file, 19 | ;; but i can't figure out how to get this to respect log4j.properties, 20 | ;; so, we'll just do it with code. 21 | (.setLevel 22 | (org.slf4j.LoggerFactory/getLogger (Logger/ROOT_LOGGER_NAME)) Level/INFO) 23 | (let [input-path (first args) 24 | ws (analysis/analyze-workspace (workspace/load-binary input-path)) 25 | schema (schema/load-schema ws) 26 | service-map (api/make-service-map schema)] 27 | (http/start (http/create-server service-map)))) 28 | -------------------------------------------------------------------------------- /lancelot-clj/test/lancelot_clj/test_workspace.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.test-workspace 2 | (:require [clojure.test :refer :all] 3 | [lancelot-clj.anal :as analysis] 4 | [lancelot-clj.core :as core] 5 | [lancelot-clj.workspace :as workspace] 6 | [clojure.java.io :as io])) 7 | 8 | 9 | (def fixtures (.getPath (clojure.java.io/resource "fixtures"))) 10 | (def kern32 (io/file fixtures "kernel32.dll")) 11 | 12 | 13 | (deftest pe32-test 14 | (let [workspace (workspace/load-binary kern32) 15 | nop-va 0x68901000 16 | call-va 0x68901032 17 | mov-va 0x68901010 18 | jnz-va 0x6890102b] 19 | (testing "check loader" 20 | (is (= :pe32 (:loader workspace)))) 21 | (testing "fetch bytes") 22 | ;; TODO: figure out how to get this equality working 23 | ;;(is (= (seq (into [] (get-bytes workspace 0x68901000 0x8))) (seq [0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90])))) 24 | (testing "disassemble" 25 | (is (= (.-mnemonic (workspace/disassemble workspace 0x68901000)) "nop"))))) 26 | -------------------------------------------------------------------------------- /capstone-clj/src/capstone_clj/core.clj: -------------------------------------------------------------------------------- 1 | (ns capstone-clj.core 2 | (:gen-class) 3 | (:import [capstone.Capstone])) 4 | 5 | 6 | 7 | (defn -main 8 | "I don't do a whole lot ... yet." 9 | [& args] 10 | (println "Hello, World!") 11 | (let [arch capstone.Capstone/CS_ARCH_X86 12 | mode capstone.Capstone/CS_MODE_64 13 | flavor capstone.Capstone/CS_OPT_SYNTAX_INTEL 14 | cs (capstone.Capstone. arch mode) 15 | _ (.setSyntax cs flavor) 16 | _ (.setDetail cs 1)] 17 | (let [code (byte-array [0x55 18 | 0x48 19 | 0x8b 20 | 0x05 21 | 0xb8 22 | 0x13 23 | 0x00 24 | 0x00]) 25 | insns (.disasm cs code 0x1000)] 26 | (doseq [[i insn] (map-indexed vector insns)] 27 | (let [addr (.-address insn) 28 | mnem (.-mnemonic insn) 29 | op (.-opStr insn)] 30 | (printf "0x%x:\t%s\t%s\n" addr mnem op))))) 31 | (println "Goodbye, World!")) 32 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/common.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot_cljs.common 2 | (:require 3 | [cljs.pprint] 4 | )) 5 | 6 | (defn pp 7 | "via: http://stackoverflow.com/a/32108640/87207" 8 | [s] 9 | (with-out-str (cljs.pprint/pprint s))) 10 | 11 | (defn d 12 | " 13 | Log a debug message to the console. 14 | With cljs-devtools installed, things are formatted nicely. 15 | " 16 | [msg] 17 | (.log js/console msg)) 18 | 19 | 20 | (defn update-values 21 | " 22 | apply a function to update all the values in the given map. 23 | 24 | via: http://blog.jayfields.com/2011/08/clojure-apply-function-to-each-value-of.html 25 | " 26 | [m f & args] 27 | (reduce (fn [r [k v]] (assoc r k (apply f v args))) {} m)) 28 | 29 | 30 | (defn update-keys 31 | " 32 | apply a function to update all the keys in the given map. 33 | " 34 | [m f & args] 35 | (reduce (fn [r [k v]] (assoc r (apply f k args) v)) {} m)) 36 | 37 | 38 | (defn index-by 39 | " 40 | create a map from the given sequence, using `key` to extract the key. 41 | the value is the first element with the extracted key. 42 | " 43 | [key col] 44 | (update-values (group-by key col) first)) 45 | 46 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/core.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot_cljs.core 2 | (:require [goog.events :as events] 3 | [reagent.core :as reagent] 4 | [re-frame.core :refer [dispatch dispatch-sync subscribe]] 5 | [lancelot_cljs.events] 6 | [lancelot_cljs.subs] 7 | [lancelot_cljs.views] 8 | [devtools.core :as devtools])) 9 | 10 | (devtools/install!) 11 | (enable-console-print!) 12 | 13 | ;; -- Entry Point ------------------------------------------------------------- 14 | ;; Within ../../resources/public/client/index.html you'll see this code 15 | ;; window.onload = function () { 16 | ;; lancelot_cljs.core.main(); 17 | ;; } 18 | ;; So this is the entry function that kicks off the app once the HTML is loaded. 19 | ;; 20 | (defn ^:export main 21 | [] 22 | (when (not @(subscribe [:initialized?])) 23 | (dispatch-sync [:initialize-db]) 24 | (dispatch [:load-samples])) 25 | ;; Render the UI into the HTML's
element 26 | ;; The view function `lancelot_cljs.views/dis-app` is the 27 | ;; root view for the entire UI. 28 | (reagent/render [lancelot_cljs.views/dis-app] 29 | (.getElementById js/document "app"))) 30 | -------------------------------------------------------------------------------- /capstone-clj/test/capstone_clj/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns capstone-clj.core-test 2 | (:require [clojure.test :refer :all] 3 | [capstone-clj.core :refer :all]) 4 | (:import [capstone.Capstone])) 5 | 6 | 7 | (deftest basic-capstone 8 | " 9 | this is the example from: 10 | http://www.capstone-engine.org/lang_java.html 11 | " 12 | (testing "basic capstone" 13 | (let [arch capstone.Capstone/CS_ARCH_X86 14 | mode capstone.Capstone/CS_MODE_64 15 | flavor capstone.Capstone/CS_OPT_SYNTAX_INTEL 16 | cs (capstone.Capstone. arch mode) 17 | _ (.setSyntax cs flavor) 18 | _ (.setDetail cs 1) 19 | code (byte-array [0x55 20 | 0x48 21 | 0x8b 22 | 0x05 23 | 0xb8 24 | 0x13 25 | 0x00 26 | 0x00]) 27 | insns (.disasm cs code 0x1000)] 28 | (testing "disassemble" 29 | (is (= (alength insns) 2)) 30 | (doseq [[i insn] (map-indexed vector insns)] 31 | (let [addr (.-address insn) 32 | mnem (.-mnemonic insn) 33 | op (.-opStr insn)] 34 | (printf "0x%x:\t%s\t%s\n" addr mnem op) 35 | (condp = i 36 | 0 (testing "first opcode" 37 | (is (= addr 0x1000)) 38 | (is (= mnem "push"))) 39 | 1 (testing "second opcode" 40 | (is (= addr 0x1001)) 41 | (is (= mnem "mov")))))))))) 42 | -------------------------------------------------------------------------------- /capstone-clj/project.clj: -------------------------------------------------------------------------------- 1 | (defproject com.williballenthin/capstone-clj "0.1.0-SNAPSHOT" 2 | :description "A library for disassembling bytes into instructions" 3 | :url "https://github.com/williballenthin/reversing-clj/tree/master/capstone-clj" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.8.0"] 7 | [net.java.dev.jna/jna "4.1.0"] 8 | ;; first, build java capstone bindings: 9 | ;; linux: 10 | ;; $ git clone https://github.com/aquynh/capstone.git 11 | ;; $ cd capstone 12 | ;; $ ./make.sh 13 | ;; $ cd bindings/java 14 | ;; $ sudo dnf install jna # fedora 15 | ;; $ sudo apt-get install libjna-java # ubuntu 16 | ;; $ make 17 | ;; windows: 18 | ;; see: https://github.com/aquynh/capstone/issues/1043 19 | ;; to install capstone into the local maven repository: 20 | ;; $ mvn install:install-file -Dfile=$(pwd)/capstone.jar 21 | ;; -DgroupId=capstone 22 | ;; -DartifactId=capstone 23 | ;; -Dversion=3.5.0-rc3 24 | ;; -Dpackaging=jar 25 | ;; via: https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html 26 | [capstone/capstone "3.5.0-rc3"]] 27 | :main ^:skip-aot capstone-clj.core 28 | :target-path "target/%s" 29 | :profiles {:uberjar {:aot :all}}) 30 | -------------------------------------------------------------------------------- /lancelot-clj/dev-resources/user.clj: -------------------------------------------------------------------------------- 1 | (ns user 2 | (:require 3 | [clojure.java.io :as io] 4 | [clojure.tools.logging :as log] 5 | [lancelot-clj.api :as api] 6 | [lancelot-clj.anal :as analysis] 7 | [lancelot-clj.schema :as schema] 8 | [lancelot-clj.workspace :as workspace] 9 | [com.walmartlabs.lacinia :as lacinia] 10 | [io.pedestal.http :as http]) 11 | (:import (ch.qos.logback.classic Logger Level))) 12 | 13 | (.setLevel 14 | (org.slf4j.LoggerFactory/getLogger (Logger/ROOT_LOGGER_NAME)) Level/INFO) 15 | 16 | (defonce ws (atom nil)) 17 | (defonce schema (atom nil)) 18 | (defonce service-map (atom nil)) 19 | (defonce server (atom nil)) 20 | 21 | (defn load-ws [] 22 | (reset! ws 23 | (analysis/analyze-workspace 24 | (workspace/load-binary (.getPath (clojure.java.io/resource "helloworld.exe"))))) 25 | "ok") 26 | 27 | (defn load-schema [] 28 | (reset! schema (schema/load-schema @ws)) 29 | "ok") 30 | 31 | (defn load-service-map [] 32 | (reset! service-map (api/make-service-map @schema)) 33 | "ok") 34 | 35 | #_(defn q 36 | [query-string] 37 | (-> (lacinia/execute schema query-string nil nil) 38 | s/simplify)) 39 | 40 | (defn start-http [] 41 | (reset! server 42 | (http/start (http/create-server 43 | (assoc @service-map 44 | ::http/join? false)))) 45 | @server) 46 | 47 | (defn stop-http [] 48 | (http/stop @server)) 49 | 50 | (defn restart-http [] 51 | (stop-http) 52 | (start-http)) 53 | 54 | ;;(load-ws) 55 | ;;(load-schema) 56 | ;;(load-service-map) 57 | ;;(start-http) 58 | ;;(restart-http) 59 | ;;(stop-http) 60 | 61 | #_(defmethod print-method Number 62 | [n ^java.io.Writer w] 63 | (.write w (format "0x%X" n))) 64 | 65 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/subs.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot-cljs.subs 2 | (:require [re-frame.core :refer [reg-sub subscribe]] 3 | )) 4 | 5 | (reg-sub 6 | :initialized? 7 | (fn [db _] 8 | (or (some? (:samples db))))) 9 | 10 | (reg-sub 11 | :samples-loaded? 12 | (fn [db _] 13 | (some? (:samples db)))) 14 | 15 | (reg-sub 16 | :sample-selected? 17 | (fn [db _] 18 | (some? (:sample db)))) 19 | 20 | ;; Returns: 21 | ;; [{:md5 str :sha1 str} ...] 22 | (reg-sub 23 | :samples 24 | (fn [db _] 25 | (:samples db))) 26 | 27 | ;; Returns: 28 | ;; 29 | ;; {:md5 str :sha1 str} 30 | (reg-sub 31 | :sample 32 | (fn [db _] 33 | (:sample db))) 34 | 35 | (reg-sub 36 | :functions-loaded? 37 | (fn [db _] 38 | (prn "functions-loaded?" (some? (:functions db))) 39 | (some? (:functions db)))) 40 | 41 | (reg-sub 42 | :function-selected? 43 | (fn [db _] 44 | (prn "function-selected?" (some? (:functions db))) 45 | (some? (:function db)))) 46 | 47 | ;; Returns: 48 | ;; 49 | ;; [{:va int}] 50 | (reg-sub 51 | :functions 52 | (fn [db _] 53 | (:functions db))) 54 | 55 | ;; Returns: 56 | ;; 57 | ;; int 58 | (reg-sub 59 | :function 60 | (fn [db _] 61 | (:function db))) 62 | 63 | (reg-sub 64 | :block-addresses 65 | (fn [db _] 66 | (keys (:blocks db)))) 67 | 68 | ;; Returns: 69 | ;; 70 | ;; [{:va int 71 | ;; :insns [{:va :mnem ...}]}] 72 | (reg-sub 73 | :blocks 74 | (fn [db _] 75 | (vals (:blocks db)))) 76 | 77 | (reg-sub 78 | :edges 79 | (fn [db _] 80 | (:edges db))) 81 | 82 | (reg-sub 83 | :insns 84 | (fn [db _] 85 | (:insns db))) 86 | 87 | (reg-sub 88 | :function-loaded? 89 | (fn [db _] 90 | (some? (:insns db)))) 91 | 92 | (reg-sub 93 | :basic-block 94 | (fn [db [_ va]] 95 | (get-in db [:blocks va]))) 96 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/layout/dagre.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot_cljs.layout.dagre 2 | (:require [lancelot_cljs.common :as cmn])) 3 | 4 | 5 | (def dagre (js* "dagre")) 6 | 7 | 8 | (defn make 9 | [] 10 | (let [Graph (aget dagre "graphlib" "Graph") 11 | g (Graph.)] 12 | (.setGraph g #js{"nodesep" 5 13 | "edgesep" 10 14 | "ranksep" 10}) 15 | (.setDefaultEdgeLabel g (fn [x] #js{})) 16 | g)) 17 | 18 | 19 | (defn- cfg-bb->dagre 20 | [bb] 21 | #js{"width" (:width bb) 22 | "height" (:height bb) 23 | "label" (str (:addr bb))}) 24 | 25 | 26 | ;; TODO: push this indexing into a layout call, 27 | ;; to keep this immutable. 28 | ;; see the klay module as an example. 29 | (defn add-node! 30 | [g bb] 31 | (let [bb' (cfg-bb->dagre bb)] 32 | (.setNode g (aget bb' "label") bb'))) 33 | 34 | 35 | (defn add-edge! 36 | [g edge] 37 | (.setEdge g (str (:src edge)) (str (:dst edge)) #js{"type" (:type edge)})) 38 | 39 | 40 | (defn- dagre-bb->cfg 41 | [bb] 42 | (let [x (get bb "x") 43 | y (get bb "y") 44 | w (get bb "width") 45 | h (get bb "height")] 46 | { 47 | :x (- x (/ w 2)) 48 | :y (- y (/ h 2)) 49 | :height h 50 | :width w 51 | :id (js/parseInt (get bb "label"))})) 52 | 53 | 54 | (defn get-nodes 55 | [g] 56 | (map dagre-bb->cfg (vals (js->clj (aget g "_nodes"))))) 57 | 58 | 59 | (defn- dagre-point->cfg 60 | [point] 61 | {:x (get point "x") 62 | :y (get point "y")}) 63 | 64 | 65 | (defn- dagre-edge->cfg 66 | [edge] 67 | {:points (mapv dagre-point->cfg (get edge "points")) 68 | :type (get edge "type")}) 69 | 70 | 71 | (defn get-edges 72 | [g] 73 | (mapv dagre-edge->cfg (vals (js->clj (aget g "_edgeLabels"))))) 74 | 75 | 76 | (def layout! (aget dagre "layout")) 77 | -------------------------------------------------------------------------------- /lancelot-clj/test/lancelot_clj/dis_test.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.dis-test 2 | (:require [clojure.test :refer :all] 3 | [lancelot-clj.dis :as dis] 4 | [lancelot-clj.testutils :as testutils] 5 | [clojure.java.io :as io]) 6 | (:import (java.nio ByteBuffer ByteOrder)) 7 | (:import [capstone.Capstone]) 8 | (:import [capstone.X86_const])) 9 | 10 | (deftest dis-test 11 | (let [cs (testutils/make-capstone capstone.Capstone/CS_ARCH_X86 capstone.Capstone/CS_MODE_32) 12 | buf (testutils/make-byte-buffer [ 13 | 0x55 ;; push ebp 14 | 0x89 0xe5 ;; mov ebp,esp 15 | 0x83 0xec 0x1 0 ;; sub esp,0x10 16 | 0xb8 0x01 0x00 0x00 0x00 ;; mov eax,0x1 17 | 0x50])] ;; push eax 18 | 19 | (testing "disasm-one" 20 | (let [i0 (dis/disassemble-one cs buf 0x0)] 21 | (is (= (.-address i0) 0x0)) 22 | (is (= (.-mnemonic i0) "push")) 23 | (is (= (.-opStr i0) "ebp"))) 24 | (let [i1 (dis/disassemble-one cs buf 0x1 0x1)] 25 | (is (= (.-address i1) 0x1)) 26 | (is (= (.-mnemonic i1) "mov")) 27 | (is (= (.-opStr i1) "ebp, esp"))) 28 | ;; here's an overlapping instruction at offset 0x2 29 | (let [i2 (dis/disassemble-one cs buf 0x2 0x2)] 30 | (is (= (.-address i2) 0x2)) 31 | (is (= (.-mnemonic i2) "in")) 32 | (is (= (.-opStr i2) "eax, -0x7d")))) 33 | 34 | (testing "disasm-all" 35 | (let [insns (into [] (map dis/format-insn (dis/disassemble-all cs buf 0x0)))] 36 | (is (= (nth insns 0) "0x0 push ebp")) 37 | (is (= (nth insns 1) "0x1 mov ebp, esp")) 38 | ;; note this is overlapping the mov above 39 | (is (= (nth insns 2) "0x2 in eax, -0x7d")))))) 40 | -------------------------------------------------------------------------------- /unicorn-clj/test/unicorn_clj/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns unicorn-clj.core-test 2 | (:require [clojure.test :refer :all] 3 | [unicorn-clj.core :refer :all]) 4 | (:import [unicorn.Unicorn] 5 | [clojure.lang ILookup])) 6 | 7 | 8 | (deftest basic-unicorn 9 | " 10 | this is the example from: 11 | http://www.unicorn-engine.org/docs/tutorial.html 12 | " 13 | (testing "raw unicorn" 14 | (let [arch unicorn.Unicorn/UC_ARCH_X86 15 | mode unicorn.Unicorn/UC_MODE_32 16 | mu (unicorn.Unicorn. arch mode) 17 | code (byte-array [0x41 0x4a]) 18 | addr 0x1000000] 19 | (doto mu 20 | (.mem_map addr (* 2 1024 1024) unicorn.Unicorn/UC_PROT_EXEC) 21 | (.mem_write addr code) 22 | (.reg_write unicorn.Unicorn/UC_X86_REG_ECX 0x1234) 23 | (.reg_write unicorn.Unicorn/UC_X86_REG_EDX 0x7890) 24 | (.emu_start addr (+ addr (alength code)) 0 0)) 25 | ;; note: return from reg_read is always 64bit 26 | (let [ecx (bit-and 0xFFFFFFFF (.reg_read mu unicorn.Unicorn/UC_X86_REG_ECX)) 27 | edx (bit-and 0xFFFFFFFF (.reg_read mu unicorn.Unicorn/UC_X86_REG_EDX))] 28 | (testing "emulation" 29 | (is (= ecx 0x1235)) 30 | (is (= edx 0x788f))))))) 31 | 32 | (deftest unicorn-clj 33 | (testing "unicorn-clj" 34 | (let [arch unicorn.Unicorn/UC_ARCH_X86 35 | mode unicorn.Unicorn/UC_MODE_32 36 | mu (make-emulator arch mode) 37 | code (byte-array [0x41 0x4a]) 38 | addr 0x1000000] 39 | (doto mu 40 | (mem_map! addr (* 2 1024 1024) unicorn.Unicorn/UC_PROT_EXEC) 41 | (mem_write! addr code) 42 | ;; here are two equivalent ways to set register contents: 43 | (reg_write! unicorn.Unicorn/UC_X86_REG_ECX 0x1234) 44 | (reg_write! :edx 0x7890) 45 | ;; default timeout, count values are 0 46 | (emu_start! addr (+ addr (alength code)))) 47 | ;; here are two equivalent ways to fetch register contents: 48 | (testing "reg read" 49 | ;; note: in MODE_32, result is automatically 32 bits. 50 | (is (= (reg_read mu unicorn.Unicorn/UC_X86_REG_ECX) 0x1235)) 51 | (is (= (reg_read mu unicorn.Unicorn/UC_X86_REG_EDX) 0x788f))) 52 | (testing "reg lookup" 53 | (is (= (:ecx mu) 0x1235)) 54 | (is (= (:edx mu) 0x788f)))))) 55 | -------------------------------------------------------------------------------- /unicorn-clj/src/unicorn_clj/core.clj: -------------------------------------------------------------------------------- 1 | (ns unicorn-clj.core 2 | (:import [clojure.lang ILookup] 3 | [clojure.string] 4 | [unicorn.Unicorn]) 5 | (:gen-class)) 6 | 7 | 8 | (defn mem_map! 9 | ([emu addr length perms] 10 | (.mem_map (.uc emu) addr length perms)) 11 | ([emu addr length] 12 | (mem_map! emu addr length unicorn.Unicorn/UC_PROT_EXEC))) 13 | 14 | (defn mem_write! 15 | [emu addr buf] 16 | (.mem_write (.uc emu) addr buf)) 17 | 18 | (defn mem_read 19 | [emu addr addr length] 20 | (.mem_read (.uc emu) addr length)) 21 | 22 | (defn emu_start! 23 | ([emu addr until timeout count] 24 | (.emu_start (.uc emu) addr until timeout count)) 25 | ([emu addr until] 26 | (emu_start! emu addr until 0 0))) 27 | 28 | (defn- resolve-reg 29 | [emu key] 30 | (when (= (.arch emu) unicorn.Unicorn/UC_ARCH_X86) 31 | (let [regname (clojure.string/upper-case (subs (str key) 1)) 32 | uname (str "UC_X86_REG_" regname) 33 | ;; well, this is a hack. 34 | ;; access to static fields must be compiled ahead of time. 35 | ;; so we generate code to fetch the requested register. 36 | ;; ref: https://stackoverflow.com/questions/6630432/access-java-fields-dynamically-in-clojure 37 | ;; 38 | ;; TODO: cache the generated code? 39 | reg (eval (read-string (str "unicorn.Unicorn/" uname)))] 40 | reg))) 41 | 42 | (defn reg_write! 43 | [emu reg val] 44 | (if (keyword? reg) 45 | (.reg_write (.uc emu) (resolve-reg emu reg) val) 46 | (.reg_write (.uc emu) reg val))) 47 | 48 | (defn reg_read 49 | [emu reg] 50 | (let [reg' (if (keyword? reg) 51 | (resolve-reg emu reg) 52 | reg) 53 | val (.reg_read (.uc emu) reg')] 54 | ;; note: return from reg_read is always 64bit 55 | (if (= unicorn.Unicorn/UC_MODE_32) 56 | (bit-and 0xFFFFFFFF val) 57 | val))) 58 | 59 | (deftype Emulator [uc arch mode] 60 | ILookup 61 | (valAt [this key] 62 | (reg_read this (resolve-reg this key)))) 63 | 64 | (defn make-emulator 65 | ([arch mode] 66 | (Emulator. (unicorn.Unicorn. arch mode) arch mode))) 67 | 68 | (defn -main 69 | "I don't do a whole lot ... yet." 70 | [& args] 71 | (println "Hello, World!") 72 | (let [arch unicorn.Unicorn/UC_ARCH_X86 73 | mode unicorn.Unicorn/UC_MODE_32 74 | uc (unicorn.Unicorn. arch mode)] 75 | (println "a" (:eax uc))) 76 | (println "Goodbye, World!")) 77 | 78 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_clj/dis.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.dis 2 | (:gen-class) 3 | (:require [clojure.java.io :as io] 4 | [pantomime.mime :as panto] 5 | [pe.core :as pe] 6 | [clojure.tools.logging :as log] 7 | [clojure.set :as set]) 8 | (:import (java.io RandomAccessFile)) 9 | (:import (java.nio ByteBuffer ByteOrder)) 10 | (:import (java.nio.channels FileChannel FileChannel$MapMode)) 11 | (:import [capstone.Capstone]) 12 | (:import [capstone.X86_const])) 13 | 14 | (defn at-position 15 | [byte-buffer position] 16 | (let [byte-buffer' (.duplicate byte-buffer)] 17 | (.position byte-buffer' position) 18 | byte-buffer')) 19 | 20 | (defn disassemble-one 21 | " 22 | disassemble a single instruction from the given bytes at the given offset. 23 | 24 | example:: 25 | 26 | > (disassemble-one cs (get-section pe '.text') 0x401000 0x0) 27 | < #object[capstone.Capstone$CsInsn ...] 28 | " 29 | ([dis buf rva offset] 30 | (let [lim (.limit buf) 31 | remaining (- lim offset) 32 | arr (byte-array (min 0x10 remaining)) ;; assume each insn is at most 0x10 bytes long 33 | buf' (at-position buf offset)] 34 | (.get buf' arr) 35 | (first (.disasm dis arr rva 1)))) 36 | ([dis buf rva] 37 | (disassemble-one dis buf rva 0x0))) 38 | 39 | (defn chunked-pmap [f partition-size coll] 40 | ;; via: https://stackoverflow.com/a/19972453/87207 41 | (->> coll ; Start with original collection. 42 | 43 | (partition-all partition-size) ; Partition it into chunks. 44 | 45 | (pmap (comp doall ; Map f over each chunk, 46 | (partial map f))) ; and use doall to force it to be 47 | ; realized in the worker thread. 48 | 49 | (apply concat))) ; Concatenate the chunked results 50 | ; to form the return value. 51 | 52 | (defn disassemble-all 53 | " 54 | disassemble instructions at all offsets in the given bytes. 55 | note, this includes overlapping instructions. 56 | 57 | example:: 58 | 59 | > (disassemble-all cs (get-section pe '.text') 0x401000) 60 | < #object[capstone.Capstone$CsInsn ...] 61 | < #object[capstone.Capstone$CsInsn ...] 62 | < ... 63 | " 64 | [dis buf rva] 65 | (chunked-pmap (fn [offset] 66 | (disassemble-one dis buf (+ rva offset) offset)) 67 | 0x10000 68 | (range (.limit buf)))) 69 | 70 | (defn format-insn 71 | "format the given capstone instruction into a string" 72 | [insn] 73 | (when (some? insn) 74 | (let [addr (.-address insn) 75 | mnem (.-mnemonic insn) 76 | op (.-opStr insn)] 77 | (format "0x%x %s %s" addr mnem op)))) 78 | 79 | -------------------------------------------------------------------------------- /lancelot-clj/project.clj: -------------------------------------------------------------------------------- 1 | (defproject lancelot-clj "0.1.0-SNAPSHOT" 2 | :description "Binary analysis framework" 3 | :url "https://github.com/williballenthin/reversing-clj/tree/master/lancelot-clj" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.8.0"] 7 | ;; see install instructions for capstone shared library in capstone-clj repo. 8 | [com.williballenthin/capstone-clj "0.1.0-SNAPSHOT"] 9 | [capstone/capstone "3.5.0-rc3"] 10 | [com.williballenthin/pe "0.1.0-SNAPSHOT"] 11 | ;; for mime-type detection. pulls in lots of stuff. ripe for replacement. 12 | [com.novemberain/pantomime "2.9.0"] 13 | ;; for logging 14 | [org.clojure/tools.logging "0.4.0"] 15 | [ch.qos.logback/logback-classic "1.1.3"] 16 | ;; for graphql 17 | [com.walmartlabs/lacinia "0.22.0"] 18 | [com.walmartlabs/lacinia-pedestal "0.3.0"] 19 | 20 | ;; for web client 21 | [org.clojure/clojurescript "1.9.946"] 22 | [figwheel-sidecar "0.5.9-SNAPSHOT" :scope "test"] 23 | [binaryage/devtools "0.9.4"] 24 | [vincit/venia "0.2.4"] 25 | [re-frame "0.10.2"] 26 | [secretary "1.2.3"] 27 | [day8.re-frame/http-fx "0.1.4"] 28 | ] 29 | :plugins [[lein-cljsbuild "1.1.5"] 30 | [lein-figwheel "0.5.14"] 31 | [venantius/ultra "0.5.2"]] 32 | :main ^:skip-aot lancelot-clj.core 33 | :target-path "target/%s" 34 | :profiles {:uberjar {:aot :all} 35 | :dev {:dependencies [[re-frisk "0.5.0"]]}} 36 | 37 | ;; for web client 38 | :cljsbuild {:builds [{:id "client-dev" 39 | ;; The path to the top-level ClojureScript source directory: 40 | :source-paths ["src"] 41 | ;;:figwheel true 42 | ;; The standard ClojureScript compiler options: 43 | ;; (See the ClojureScript compiler documentation for details.) 44 | :compiler {:asset-path "js" ;; directory of `main.js` relative to `index.html` 45 | :output-to "resources/public/client/js/main.js" 46 | :output-dir "resources/public/client/js" 47 | :verbose true 48 | :source-map true 49 | :source-map-timestamp true 50 | :main lancelot_cljs.core 51 | :preloads [re-frisk.preload] 52 | :optimizations :none 53 | :pretty-print true} 54 | :figwheel {:on-jsload "lancelot_cljs.core/main"}}]}) 55 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/api.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot_cljs.api 2 | (:require [ajax.core :refer [GET POST PUT]] 3 | [clojure.string :as string] 4 | [cljs.core.async :refer [put! chan (lstrip 'foobar' 'foo') 25 | 'bar' 26 | 27 | => (lstrip 'foobar' 'baz') 28 | 'foobar' 29 | " 30 | [s w] 31 | (if (string/starts-with? s w) 32 | (subs s (count w)) 33 | s)) 34 | 35 | 36 | (defn strip-prefix 37 | "pedestal interceptor that re-writes the path-info to strip the given prefix string." 38 | [prefix] 39 | {:name ::strip-prefix 40 | :enter (fn [context] 41 | (update-in context [:request :path-info] #(lstrip % prefix)))}) 42 | 43 | 44 | (defn log-field 45 | "pedestal interceptor that logs the given context field to INFO." 46 | [field] 47 | {name ::log-field 48 | :enter (fn [context] 49 | (log/info "log field " (str field) " " (get-in context field)) 50 | context)}) 51 | 52 | (def ctx (atom {})) 53 | (def capture-ctx 54 | "pedestal interceptor that captures the request context to the global atom `ctx`." 55 | {:name ::capture-ctx 56 | :enter (fn [context] 57 | (swap! ctx assoc :ctx context) 58 | context)}) 59 | 60 | 61 | (def script-domains [;; graphiql src hosts 62 | "cdn.jsdelivr.net" "unpkg.com"]) 63 | (defn make-script-src-policy 64 | "format a script Content Security Policy that allows sources from the given domains." 65 | [domains] 66 | (str "'self' 'unsafe-inline' 'unsafe-eval' " (string/join " " domains))) 67 | 68 | 69 | (def style-domains [;; client 70 | "fonts.googleapis.com"]) 71 | (defn make-style-src-policy 72 | "format a style Content Security Policy that allows sources from the given domains." 73 | [domains] 74 | (str "'self' 'unsafe-inline' " (string/join " " domains))) 75 | 76 | 77 | (defn make-routes 78 | [schema] 79 | (set/union 80 | ;; the GraphQL endpoint will be: `/graphql` 81 | (lp/graphql-routes schema {}) 82 | ;; and we'll still be able to host other resources. 83 | #{;; the handler can be specified directly, 84 | ["/greet" :get respond-hello :route-name :greet] 85 | ["/lancelot/*file" :get [(strip-prefix "/lancelot") 86 | (middlewares/resource "/public/client") 87 | middlewares/file-info] 88 | :route-name :client] 89 | ["/graphiql/*file" :get [(strip-prefix "/graphiql") 90 | (middlewares/resource "/public/graphiql") 91 | middlewares/file-info] 92 | :route-name :graphiql]})) 93 | 94 | (defn make-service-map 95 | [schema] 96 | {::http/routes (route/expand-routes (make-routes schema)) 97 | ::http/type :jetty 98 | ::http/port 8891 99 | ::http/secure-headers {:content-security-policy-settings {:default-src "*" 100 | :style-src (make-style-src-policy style-domains) 101 | :script-src (make-script-src-policy script-domains)}} 102 | }) 103 | -------------------------------------------------------------------------------- /construct-clj/DESIGN.md: -------------------------------------------------------------------------------- 1 | # Design of construct-clj 2 | 3 | 4 | The inspiration of construct-clj includes: 5 | - Python's construct 3: http://tomerfiliba.com/blog/Survey-of-Construct3/ 6 | - vstruct: http://www.williballenthin.com/blog/2015/09/08/parsing-binary-data-with-vstruct/ 7 | 8 | features: 9 | - lazy unpacking - only unpack what is required 10 | - cache parsed results 11 | - maybe clojure map syntax is possible? 12 | - no: if we want a map, use `unpack` and create a map. 13 | - technical reason: can't update the cache in place. 14 | - avoid copying data from mmap 15 | - be able to query the underlying offsets for some field 16 | - union types would be cool! 17 | - built-in repr? 18 | - resolve enums using a map 19 | - resolve bitfields using some data structure 20 | 21 | wants: 22 | - want: stream unpacking - unpack from a sequence of bytes 23 | - want: packing 24 | 25 | questions: 26 | - what about decompressed buffers? 27 | 28 | 29 | ### unpacker 30 | 31 | a "spec" is a specification for some data that can be deserialized/parsed/unpacked. 32 | it sometimes called a: 33 | - "frame" ([ref](https://github.com/ztellman/gloss/wiki/Introduction)), 34 | - "codec" ([ref](https://github.com/smee/binary)), or 35 | - "spec" ([ref](https://github.com/clojurewerkz/buffy)). 36 | 37 | `parse` returns a parsing context for the given structure and byte buffer. 38 | fields are parsed lazily. 39 | 40 | `unpack` returns a clojure data structure for the given struct and byte buffer. 41 | all parsing is done in one go. 42 | 43 | a key part of lazy structure parsing is knowing where to find fields. 44 | fields are laid out consecutively, so we need to know the length of each field 45 | to find fields. 46 | here's how we minimize the amount of work to do: 47 | 48 | 1. if there is a static size provided, use that. 49 | ```lisp 50 | (make-spec ... :static-size 4) 51 | ``` 52 | 2. if it is a class instance, and already fully parsed, use length. 53 | ```lisp 54 | (when (fully-parsed? s) 55 | (parsed-length s)) 56 | ``` 57 | 3. if there is a class method for computing length, use that. 58 | ```lisp 59 | (make-spec ... :dynamic-size (fn [byte-buffer] 60 | (with-buffer byte-buffer 61 | (unpack-uint8)))) 62 | ``` 63 | 4. else, create instance of class, fully parse it, use length. 64 | ```lisp 65 | (let (parsed (parse some-spec byte-buffer))) 66 | (parsed-length parsed) 67 | ``` 68 | 69 | ```lisp 70 | (def ip-addr (make-spec 71 | (array uint8 4) 72 | :repr #(clojure.string/join "." %))) 73 | 74 | (unpack ip-addr "\xC0\xA8\x02\x01") 75 | >>> [192, 168, 0, 1] 76 | 77 | (repr (parse ip-addr "\xC0\xA8\x02\x01")) 78 | >>> "192.168.0.1" 79 | 80 | (def dos-header (make-spec 81 | (struct 82 | :static-size ... 83 | :fields [ 84 | ;; `always` is a validator 85 | :sig (always (ascii-char 2) "MZ") 86 | :lastsize uint16 87 | :nblocks uint16 88 | :nreloc uint16 89 | :hdrsize uint16 90 | :minalloc uint16 91 | :ss (bytes 2) 92 | :sp (bytes 2) 93 | :checksum uint16 94 | :ip (bytes 2) 95 | :cs (bytes 2) 96 | :relocpos uint16 97 | :noverlay uint16 98 | :reserved1 (array uint16 4) 99 | :oem_id uint16 100 | :oem_info uint16 101 | :e_lfanew uint32]))) 102 | ``` 103 | -------------------------------------------------------------------------------- /lancelot-clj/resources/api-schema.edn: -------------------------------------------------------------------------------- 1 | {:objects 2 | {:Sample 3 | {:description "a binary sample" 4 | :fields 5 | {:name {:type (non-null String) 6 | :description "human readable name for the file (non-unique)"} 7 | :md5 {:type (non-null String) 8 | :description "the MD-5 hash of the sample contents"} 9 | :sha1 {:type (non-null String) 10 | :description "the SHA-1 hash of the sample contents"} 11 | :sha256 {:type (non-null String) 12 | :description "the SHA-256 hash of the sample contents"} 13 | :exports {:type (list :Function) 14 | :description "functions exported by this sample" 15 | :resolve :Sample/exports} 16 | :entrypoint {:type :Function 17 | :description "virtual address of entrypoint function of the sample" 18 | :resolve :Sample/entrypoint}}} 19 | 20 | :Address 21 | {:description "content at a given address" 22 | :fields 23 | {:va {:type Int 24 | :description "the virtual address of the content"} 25 | :insn {:type :Instruction 26 | :description "the disassembled instruction at this address" 27 | :resolve :Address/instruction}}} 28 | 29 | :Instruction 30 | {:description "a disassembled instruction" 31 | :fields 32 | {:va {:type Int 33 | :description "the virtual address of the instruction"} 34 | :mnem {:type String 35 | :description "the human-readable mnenonic"} 36 | :size {:type Int 37 | :description "the length in bytes of this instruction"} 38 | :operands {:type (list :Operand) 39 | :description "operands to the instruction"} 40 | :opstr {:type String 41 | :description "the human-readable reprsentation of the operands"} 42 | :str {:type String 43 | :description "the human-readable representation"}}} 44 | 45 | :Operand 46 | {:description "an operand to an instruction" 47 | :fields 48 | {:str {:type String 49 | :description "the human-readable representation"}}} 50 | ;; TODO: lots of other fields 51 | 52 | :Function 53 | {:description "a function" 54 | :fields 55 | {:sample {:type (non-null String)} ;; TODO: should be of type sample 56 | :va {:type Int 57 | :description "the non-relocated function entry virtual address"} 58 | :address {:type :Address 59 | :description "the content at the start of the function"} 60 | :blocks {:type (list :BasicBlock) 61 | :description "the basic blocks of this function" 62 | :resolve :Function/blocks}}} 63 | 64 | :BasicBlock 65 | {:description "a basic block" 66 | :fields 67 | {:va {:type Int 68 | :description "the non-relocated basic block start virtual address"} 69 | :address {:type :Address 70 | :description "the content at the start of the function"} 71 | :edges_to {:type (list :BasicBlockFlow) 72 | :description "the basic blocks that flow to this basic block" 73 | :resolve :BasicBlock/preds} 74 | :edges_from {:type (list :BasicBlockFlow) 75 | :description "the basic blocks that flow from this basic block" 76 | :resolve :BasicBlock/succs} 77 | :insns {:type (list :Instruction) 78 | :description "the instructions in this basic block" 79 | :resolve :BasicBlock/insns}}} 80 | 81 | :BasicBlockFlow 82 | {:description "a flow from one basic block to another" 83 | :fields 84 | {:src {:type :BasicBlock 85 | :description "the source of the flow"} 86 | :dst {:type :BasicBlock 87 | :description "the destination of the flow"} 88 | :type {:type (non-null String) ;; TODO: enum? define the possible types. 89 | :description "the type of the flow"}}}} 90 | 91 | :queries 92 | {:samples 93 | {:type (list :Sample) 94 | :description "fetch all samples" 95 | :args {} 96 | :resolve :query/samples} 97 | :sample_by_md5 98 | {:type :Sample 99 | :description "fetch sample by its MD5 hash" 100 | :args {:md5 {:type (non-null String)}} 101 | :resolve :query/sample-by-md5} 102 | :function_by_md5_va 103 | {:type :Function 104 | :description "fetch function by sample MD5 hash and virtual address" 105 | :args {:md5 {:type (non-null String)} 106 | :va {:type Int}} 107 | :resolve :query/function-by-md5-va}}} 108 | -------------------------------------------------------------------------------- /lancelot-clj/resources/public/graphiql/index.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Loading... 30 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /pe-clj/test/pe/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns pe.core-test 2 | (:require [clojure.test :refer :all] 3 | [clojure.java.io :as io] 4 | [pe.core :refer :all])) 5 | 6 | 7 | (def fixtures (.getPath (clojure.java.io/resource "fixtures"))) 8 | (def kern32 (io/file fixtures "kernel32.dll")) 9 | 10 | 11 | (deftest pe-header-test 12 | (let [pe (read-pe kern32)] 13 | (testing "dos header" 14 | (is (= 0x5A4D (get-in pe [:dos-header :e_magic]))) 15 | (is (= 0xF0 (get-in pe [:dos-header :e_lfanew])))) 16 | (testing "signature" 17 | (is (= 0x4550 (get-in pe [:nt-header :signature])))) 18 | (testing "signature" 19 | (is (= IMAGE_FILE_MACHINE_I386 (get-in pe [:nt-header :file-header :Machine])))) 20 | (testing "optional header" 21 | (is (= IMAGE_NT_OPTIONAL_HDR32_MAGIC (get-in pe [:nt-header :optional-header :Magic]))) 22 | (is (= 0xDA000 (get-in pe [:nt-header :optional-header :SizeOfCode]))) 23 | (is (= 0x1695 (get-in pe [:nt-header :optional-header :AddressOfEntryPoint]))) 24 | (is (= 0x68900000 (get-in pe [:nt-header :optional-header :ImageBase])))) 25 | (testing "data directories" 26 | (is (= 0xCE220 (get-in pe [:nt-header :optional-header :data-directories 0 :rva]))) 27 | (is (= 0xC985 (get-in pe [:nt-header :optional-header :data-directories 0 :size]))) 28 | (is (= 0x0 (get-in pe [:nt-header :optional-header :data-directories 0xF :rva]))) 29 | (is (= 0x0 (get-in pe [:nt-header :optional-header :data-directories 0xF :size])))) 30 | (testing "section headers" 31 | (is (= ".text" (get-in pe [:section-headers ".text" :Name]))) 32 | (is (= 0xd9c0d (get-in pe [:section-headers ".text" :VirtualSize]))) 33 | (is (= ".reloc" (get-in pe [:section-headers ".reloc" :Name]))) 34 | (is (= 0xfdc0 (get-in pe [:section-headers ".reloc" :VirtualSize])))))) 35 | 36 | 37 | (deftest pe-sections-test 38 | (let [pe (read-pe kern32)] 39 | (testing ".text" 40 | (is (= 0x90 (bit-and 0xFF (.get (get-section pe ".text")))))) 41 | (testing ".data" 42 | (is (= 0x00 (bit-and 0xFF (.get (get-section pe ".data")))))) 43 | (testing ".idata" 44 | (is (= 0x23 (bit-and 0xFF (.get (get-section pe ".idata")))))) 45 | (testing ".rsrc" 46 | (is (= 0x00 (bit-and 0xFF (.get (get-section pe ".rsrc")))))) 47 | (testing ".reloc" 48 | (is (= 0x00 (bit-and 0xFF (.get (get-section pe ".reloc")))))))) 49 | 50 | 51 | (deftest data-access-test 52 | (let [pe (read-pe kern32)] 53 | (testing "get-data" 54 | (is (= 0x4d (bit-and 0xFF (.get (get-data pe 0x0 1))))) ;; in header 55 | (is (= 0x5a (bit-and 0xFF (.get (get-data pe 0x1 1))))) ;; in header 56 | (is (= 0x90 (bit-and 0xFF (.get (get-data pe 0x1000 1))))) ;; start of .text section 57 | (is (= 0xb1 (bit-and 0xFF (.get (get-data pe 0xdb054 1))))) ;; in .data section 58 | (is (= 0x23 (bit-and 0xFF (.get (get-data pe 0xdc000 1))))) ;; start of .idata section 59 | (is (= 0xa0 (bit-and 0xFF (.get (get-data pe 0xe7010 1))))) ;; in .rsrc section 60 | (is (= 0x10 (bit-and 0xFF (.get (get-data pe 0xe8001 1)))))))) ;; in .reloc section 61 | 62 | 63 | (deftest data-directory-test 64 | (let [pe (read-pe kern32)] 65 | (testing "export" 66 | (is (= 0x623 (:NumberOfFunctions (parse-directory pe :export)))) 67 | (is (= 0x623 (:NumberOfNames (parse-directory pe :export)))) 68 | (is (= 0x531185b7 (:TimeDateStamp (parse-directory pe :export)))) 69 | (is (= "KERNEL32.dll" (:Name (parse-directory pe :export))))) 70 | (testing "import" 71 | (is (= 0x531185b7 (:TimeDateStamp (parse-directory pe :import)))) 72 | (is (= 0xFFFFFFFF (:ForwarderChain (parse-directory pe :import)))) 73 | (is (= "api-ms-win-core-rtlsupport-l1-2-0.dll" (:Name (parse-directory pe :import))))))) 74 | 75 | 76 | (deftest exports-test 77 | (let [pe (read-pe kern32) 78 | exports (into [] (get-exports pe))] 79 | (testing "export" 80 | (is (= (get-in exports [0 :ordinal]) 2)) 81 | (is (= (get-in exports [0 :name]) "AcquireSRWLockExclusive")) 82 | (is (= (get-in exports [0 :forwarded?]) true)) 83 | (is (= (get-in exports [0 :forwarded-symbol]) "NTDLL.RtlAcquireSRWLockExclusive")) 84 | (is (= (get-in exports [2 :ordinal]) 4)) 85 | (is (= (get-in exports [2 :name]) "AcquireStateLock")) 86 | (is (= (get-in exports [2 :forwarded?]) false))))) 87 | 88 | 89 | (deftest imports-test 90 | (let [pe (read-pe kern32) 91 | imports (into [] (get-imports pe))] 92 | (testing "import" 93 | (is (= (get-in imports [0 :Name]) "RtlCaptureContext")) 94 | (is (= (get-in imports [0 :Dll]) "api-ms-win-core-rtlsupport-l1-2-0.dll"))))) 95 | ;; TODO: need tests for import by ordinal 96 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_clj/schema.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.schema 2 | "resolvers and function to provide full schema" 3 | (:require 4 | [lancelot-clj.anal :as analysis] 5 | [lancelot-clj.workspace :as workspace] 6 | [clojure.java.io :as io] 7 | [com.walmartlabs.lacinia.util :as util] 8 | [com.walmartlabs.lacinia.schema :as schema] 9 | [clojure.edn :as edn] 10 | [clojure.walk :as walk]) 11 | (:import (clojure.lang IPersistentMap))) 12 | 13 | (defn workspace->sample 14 | "see resources/api-schema.edn/:objects/:Sample" 15 | [ws] 16 | (merge (workspace/get-hashes (:byte-buffer ws)) 17 | {:name "TODO"})) 18 | 19 | (defn va->function 20 | "see resources/api-schema.edn/:objects/:Function" 21 | [ws va] 22 | (merge {:va va 23 | :address {:va va}})) 24 | 25 | (defn resolve-samples 26 | [ws context args value] 27 | ;; while we only have a single workspace in our session, 28 | ;; this routine is trivial. 29 | (list (workspace->sample ws))) 30 | 31 | (defn resolve-sample-by-md5 32 | [ws context args value] 33 | (let [{:keys [md5]} args 34 | current-hashes (workspace/get-hashes (:byte-buffer ws))] 35 | (when (= (:md5 current-hashes) md5) 36 | (workspace->sample ws)))) 37 | 38 | (defn resolve-sample-exports 39 | [ws context args value] 40 | (for [va (analysis/get-exports (:pe ws))] 41 | (va->function ws va))) 42 | 43 | (defn resolve-sample-entrypoint 44 | [ws context args value] 45 | (va->function ws (analysis/get-entrypoint (:pe ws)))) 46 | 47 | (defn resolve-function-by-md5-va 48 | [ws context args value] 49 | (let [{:keys [md5 va]} args 50 | current-hashes (workspace/get-hashes (:byte-buffer ws))] 51 | (when (= (:md5 current-hashes) md5) 52 | (va->function ws va)))) 53 | 54 | (defn va->insn 55 | [ws va] 56 | (let [insn (get-in ws [:analysis :insns-by-addr va]) 57 | csinsn (:insn insn) 58 | mnem (.-mnemonic csinsn) 59 | size (.-size csinsn) 60 | opstr (.-opStr csinsn)] 61 | {:mnem mnem 62 | :opstr opstr 63 | :str (format "%s %s" mnem opstr) 64 | :size size 65 | ;; TODO: resolve the operands here 66 | :va va})) 67 | 68 | (defn resolve-addr-insn 69 | [ws context args value] 70 | (let [{:keys [va]} value] 71 | (va->insn ws va))) 72 | 73 | (defn resolve-function-blocks 74 | [ws context args value] 75 | (let [{:keys [va]} value 76 | func (analysis/analyze-function ws va)] 77 | (for [[block-start block-addrs] (:blocks func)] 78 | {:va block-start 79 | :address {:va va} ;; TODO: va->address 80 | :func func}))) 81 | 82 | (defn resolve-block-preds 83 | [ws context args value] 84 | (let [{:keys [va func]} value] 85 | (for [pred (get-in func [:preds va])] 86 | {:src {:va (:src pred) :address (:src pred) :func func} 87 | :dst {:va (:dst pred) :address (:dst pred) :func func} 88 | :type (:type pred)}))) 89 | 90 | (defn resolve-block-succs 91 | [ws context args value] 92 | (let [{:keys [va func]} value] 93 | (for [pred (get-in func [:succs va])] 94 | {:src {:va (:src pred) :address (:src pred) :func func} 95 | :dst {:va (:dst pred) :address (:dst pred) :func func} 96 | :type (:type pred)}))) 97 | 98 | (defn resolve-block-insns 99 | [ws context args value] 100 | (let [{:keys [va func]} value 101 | insn-addrs (get-in func [:blocks va])] 102 | (map #(va->insn ws %) insn-addrs))) 103 | 104 | (defn resolver-map 105 | [ws] 106 | {:query/samples (partial resolve-samples ws) 107 | :query/sample-by-md5 (partial resolve-sample-by-md5 ws) 108 | :query/function-by-md5-va (partial resolve-function-by-md5-va ws) 109 | 110 | :Sample/exports (partial resolve-sample-exports ws) 111 | :Sample/entrypoint (partial resolve-sample-entrypoint ws) 112 | :Address/instruction (partial resolve-addr-insn ws) 113 | :Function/blocks (partial resolve-function-blocks ws) 114 | :BasicBlock/preds (partial resolve-block-preds ws) 115 | :BasicBlock/succs (partial resolve-block-succs ws) 116 | :BasicBlock/insns (partial resolve-block-insns ws)}) 117 | 118 | (defn load-schema 119 | [ws] 120 | (-> (io/resource "api-schema.edn") 121 | slurp 122 | edn/read-string 123 | (util/attach-resolvers (resolver-map ws)) 124 | schema/compile)) 125 | 126 | 127 | (defn simplify 128 | "Converts all ordered maps nested within the map into standard hash maps, and 129 | sequences into vectors, which makes for easier constants in the tests, and eliminates ordering problems." 130 | [m] 131 | (walk/postwalk 132 | (fn [node] 133 | (cond 134 | (instance? IPersistentMap node) 135 | (into {} node) 136 | 137 | (seq? node) 138 | (vec node) 139 | 140 | :else 141 | node)) 142 | m)) 143 | 144 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_clj/workspace.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.workspace 2 | (:require 3 | [clojure.set :as set] 4 | [clojure.java.io :as io] 5 | [clojure.string :as string] 6 | [clojure.tools.logging :as log] 7 | [pantomime.mime :as panto] 8 | [pe.core :as pe] 9 | [lancelot-clj.dis :refer :all] 10 | [lancelot-clj.anal :refer :all] 11 | ) 12 | (:import (java.io RandomAccessFile)) 13 | (:import (java.nio ByteBuffer ByteOrder)) 14 | (:import (java.nio.channels FileChannel FileChannel$MapMode)) 15 | (:import [java.security MessageDigest]) 16 | (:import [capstone.Capstone]) 17 | (:import [capstone.X86_const]) 18 | ) 19 | 20 | (defn- hex 21 | [i] 22 | (format "%X" i)) 23 | 24 | (defn- conj-if [c e] 25 | (if (not (nil? e)) 26 | (conj c e) 27 | c)) 28 | 29 | (defn- assoc-if [m k e] 30 | (if (not (nil? e)) 31 | (assoc m k e) 32 | m)) 33 | 34 | (defn map-file 35 | [path] 36 | (let [file (RandomAccessFile. path "r") 37 | channel (.getChannel file) 38 | buffer (.map channel FileChannel$MapMode/READ_ONLY 0 (.size channel)) 39 | _ (.load buffer) 40 | _ (.order buffer ByteOrder/LITTLE_ENDIAN)] 41 | buffer)) 42 | 43 | (defn panto-taste 44 | [byte-buffer] 45 | (let [byte-buffer' (at-position byte-buffer 0) 46 | arr (byte-array 0x100) ;; should be able to get by with a 256 byte taste of the header. 47 | _ (.get byte-buffer' arr)] 48 | ;; delegate to pantomime, which asks apache tika. 49 | ;; overkill, but easy. 50 | (panto/mime-type-of arr))) 51 | 52 | (defn pe32? 53 | [byte-buffer] 54 | (let [sig (panto-taste byte-buffer)] 55 | (or 56 | (= "application/x-msdownload; format=pe32" sig) 57 | (= "application/x-msdownload" sig)))) 58 | 59 | (defn detect-file-type 60 | [byte-buffer] 61 | (cond 62 | (pe32? byte-buffer) :pe32 63 | :default :unknown)) 64 | 65 | (defmulti load-bytes detect-file-type) 66 | 67 | (defn map-pe-header 68 | [pe] 69 | (let [base-addr (get-in pe [:nt-header :optional-header :ImageBase]) 70 | header-size (get-in pe [:nt-header :optional-header :SizeOfHeaders])] 71 | {:start base-addr 72 | :end (+ base-addr header-size) 73 | :name "header" 74 | :permissions #{:read} 75 | ;; TODO: remove `dec` once rebuild pe. 76 | :data (pe/get-data pe 0 (dec header-size))})) 77 | 78 | (defn map-pe-section 79 | [pe section] 80 | (let [start (+ (:VirtualAddress section) (get-in pe [:nt-header :optional-header :ImageBase]))] 81 | {:start start 82 | :end (+ start (:VirtualSize section)) 83 | :name (:Name section) 84 | :data (pe/get-section pe (:Name section)) 85 | ;; TODO: correctly compute permissions. 86 | :permissions #{:read :write :execute} 87 | :meta section})) 88 | 89 | (defn map-pe 90 | [pe] 91 | (into [(map-pe-header pe)] 92 | (map #(map-pe-section pe %) 93 | (vals (:section-headers pe))))) 94 | 95 | (defmethod load-bytes :pe32 96 | [byte-buffer] 97 | (let [pe (pe/parse-pe byte-buffer) 98 | cs (capstone.Capstone. capstone.Capstone/CS_ARCH_X86 capstone.Capstone/CS_MODE_32) 99 | _ (.setSyntax cs capstone.Capstone/CS_OPT_SYNTAX_INTEL) 100 | _ (.setDetail cs 1)] 101 | {:loader :pe32 102 | :byte-buffer byte-buffer 103 | :pe pe 104 | :map (map-pe pe) 105 | :dis cs})) 106 | 107 | (defn byte-buffer-size 108 | [byte-buffer] 109 | (let [byte-buffer' (at-position byte-buffer 0)] 110 | (.limit byte-buffer'))) 111 | 112 | (defn byte-buffer->byte-array 113 | [byte-buffer] 114 | (let [byte-buffer' (at-position byte-buffer 0) 115 | size (byte-buffer-size byte-buffer') 116 | buf (byte-array size)] 117 | (.get byte-buffer' buf) 118 | buf)) 119 | 120 | (defn get-hash 121 | [byte-buffer algo] 122 | (let [bytes (byte-buffer->byte-array byte-buffer) ;; TODO: watch memory size. could do this in chunks. 123 | md5 (MessageDigest/getInstance algo) 124 | hash (.digest md5 bytes)] 125 | (string/join "" (map hex hash)))) 126 | 127 | (defn get-hashes 128 | [byte-buffer] 129 | (into {} (for [[kw algo] {:md5 "MD5" 130 | :sha1 "SHA-1" 131 | :sha256 "SHA-256"}] 132 | [kw (get-hash byte-buffer algo)]))) 133 | 134 | (defn get-bytes 135 | [workspace va length] 136 | (let [region (first (filter #(and (<= (:start %) va) 137 | (< va (:end %))) 138 | (:map workspace))) 139 | rva (- va (:start region)) 140 | arr (byte-array length) 141 | data (:data region) 142 | data' (at-position data rva)] 143 | (.get data' arr) 144 | arr)) 145 | 146 | (defn disassemble 147 | [workspace va] 148 | (let [code (get-bytes workspace va 0x10)] ;; 0x10 is an arbitrary max-insn-length constant 149 | (first (.disasm (:dis workspace) code va 1)))) 150 | 151 | (defn load-binary 152 | [path] 153 | (let [buf (map-file path)] 154 | (load-bytes buf))) 155 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/layout/klay.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot_cljs.layout.klay 2 | (:require [lancelot_cljs.common :as cmn])) 3 | 4 | 5 | (def klay (js* "$klay")) 6 | 7 | 8 | (defn make 9 | [] 10 | {"id" "root" 11 | "properties" {"direction" "DOWN" 12 | "intCoordinates" false 13 | 14 | ;; base spacing value 15 | ;; unit: em 16 | "spacing" 2 17 | 18 | ;; horizontal spacing within a layer 19 | ;; unit: multiple of `spacing` 20 | "de.cau.cs.kieler.klay.layered.inLayerSpacingFactor" 3.5 21 | 22 | ;; how far apart to route parallel, horizontal edges 23 | ;; unit: multiple of `spacing` 24 | "de.cau.cs.kieler.klay.layered.edgeSpacingFactor" 0.1 25 | 26 | ;; spacing around the border of the view 27 | ;; unit: em? 28 | "de.cau.cs.kieler.borderSpacing" 1 29 | 30 | ;; no apparent effect 31 | "de.cau.cs.kieler.portSpacing" 0.1 32 | 33 | ;; no apparent effect 34 | "de.cau.cs.kieler.klay.layered.components.compact" true 35 | 36 | ;; unclear what this does 37 | "de.cau.cs.kieler.klay.layered.unnecessaryBendpoints" true 38 | 39 | ;; how many iterations to run the algorithm 40 | ;; default: 7 41 | ;; limit: 1000 42 | ;; 500 was noticable over 19 nodes 43 | "de.cau.cs.kieler.klay.layered.thoroughness" 25} 44 | ;; not supported in klayjs? 45 | ;;"de.cau.cs.kieler.klay.layered.edgeNodeSpacingFactor" 0.1 46 | 47 | "children" [] 48 | "edges" []}) 49 | 50 | 51 | (defn- cfg-bb->klay 52 | [bb] 53 | {"id" (str (:va bb)) 54 | "width" (:width bb) 55 | "height" (:height bb) 56 | "properties" {"de.cau.cs.kieler.portConstraints" "FIXED_SIDE"}}) 57 | 58 | 59 | (defn add-node 60 | [g bb] 61 | (update-in g ["children"] #(cons (cfg-bb->klay bb) %))) 62 | 63 | 64 | (defn- cfg-edge->klay 65 | [edge] 66 | {"source" (str (:src edge)) 67 | "target" (str (:dst edge)) 68 | "type" (name (:type edge)) 69 | "id" (:id edge)}) 70 | 71 | 72 | (defn add-edge 73 | [g edge] 74 | (update-in g ["edges"] #(cons (cfg-edge->klay edge) %))) 75 | 76 | 77 | (defn- klay-bb->cfg 78 | [bb] 79 | (let [x (get bb "x") 80 | y (get bb "y") 81 | w (get bb "width") 82 | h (get bb "height")] 83 | {:x x 84 | :y y 85 | :height h 86 | :width w 87 | :id (js/parseInt (get bb "id"))})) 88 | 89 | 90 | (defn get-nodes 91 | [g] 92 | (mapv klay-bb->cfg (js->clj (aget g "children")))) 93 | 94 | 95 | (defn- klay-point->cfg 96 | [point] 97 | {:x (get point "x") 98 | :y (get point "y")}) 99 | 100 | 101 | (defn- klay-edge->cfg 102 | [edge] 103 | (let [src-point (get edge "sourcePoint") 104 | target-point (get edge "targetPoint") 105 | bend-points (get edge "bendPoints") 106 | points (concat [src-point] bend-points [target-point])] 107 | {:points (mapv klay-point->cfg points) 108 | :type (keyword (get edge "type")) 109 | :src (js/parseInt (get edge "source")) 110 | :dst (js/parseInt (get edge "target"))})) 111 | 112 | 113 | (defn get-edges 114 | [g] 115 | (mapv klay-edge->cfg (js->clj (aget g "edges")))) 116 | 117 | 118 | (defn- make-port-name 119 | [src dst direction] 120 | (str src "-" direction "-" dst)) 121 | 122 | 123 | (defn- make-in-edge-port 124 | [edge] 125 | (make-port-name (get edge "source") (get edge "target") "IN")) 126 | 127 | 128 | (defn- make-out-edge-port 129 | [edge] 130 | (make-port-name (get edge "source") (get edge "target") "OUT")) 131 | 132 | 133 | (defn- update-ports 134 | " 135 | Add ports to nodes and edges. 136 | " 137 | [g] 138 | (let [edges (get g "edges") 139 | edges' (map 140 | (fn [edge] 141 | (merge edge {"sourcePort" (make-out-edge-port edge) 142 | "targetPort" (make-in-edge-port edge)})) 143 | edges) 144 | nodes (get g "children") 145 | nodes-by-id (cmn/index-by #(get % "id") nodes) 146 | nodes-by-id' (reduce 147 | (fn [nodes edge] 148 | (let [nodes' (update-in nodes [(get edge "source") "ports"] conj {"id" (make-out-edge-port edge) 149 | "properties" {"de.cau.cs.kieler.portSide" "SOUTH"} 150 | ;; practical effect: offset from the node at which to start 151 | "height" 0 152 | "width" 0}) 153 | nodes' (update-in nodes' [(get edge "target") "ports"] conj {"id" (make-in-edge-port edge) 154 | "properties" {"de.cau.cs.kieler.portSide" "NORTH"} 155 | "height" 0 156 | "width" 0})] 157 | nodes')) 158 | nodes-by-id 159 | edges)] 160 | (merge g {"children" (into [] (vals nodes-by-id')) 161 | "edges" edges'}))) 162 | 163 | 164 | (defn layout 165 | [g s e] 166 | (let [layout-fn (aget klay "layout") 167 | g' (update-ports g)] 168 | (layout-fn (clj->js {"graph" g' 169 | "options" {} 170 | "success" s 171 | "error" e})))) 172 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/events.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot-cljs.events 2 | (:require 3 | [re-frame.core :refer [reg-event-db 4 | reg-event-fx 5 | dispatch 6 | dispatch-sync 7 | ]] 8 | [ajax.core :as ajax] 9 | [day8.re-frame.http-fx] 10 | [venia.core :as v] 11 | [lancelot-cljs.utils :as utils] 12 | )) 13 | 14 | (reg-event-db 15 | :initialize-db 16 | (fn [_ _] 17 | {})) 18 | 19 | (reg-event-fx 20 | :load-samples 21 | (fn [_ _] 22 | {:http-xhrio {:method :get 23 | :uri "/graphql" 24 | :params {:query (v/graphql-query {:venia/queries [[:samples [:md5 :sha1]]]})} 25 | :format (ajax/json-request-format) 26 | :response-format (ajax/json-response-format {:keywords? true}) 27 | :on-success [:loaded-samples] 28 | :on-failure [:errored-samples]}})) 29 | 30 | (reg-event-db 31 | :loaded-samples 32 | (fn [db [_ response]] 33 | (prn "loaded samples: " response) 34 | (merge db {:samples (get-in response [:data :samples])}))) 35 | 36 | (reg-event-db 37 | :errored-samples 38 | (fn [db error] 39 | (prn "errored-samples: " error) 40 | db)) 41 | 42 | (reg-event-db 43 | :select-sample 44 | (fn [db [_ sample-md5]] 45 | (prn "select-sample: " db sample-md5) 46 | (dispatch [:load-functions]) 47 | (assoc db :sample sample-md5))) 48 | 49 | (reg-event-db 50 | :unselect-sample 51 | (fn [db _] 52 | (prn "unselect-sample") 53 | (-> db 54 | (dissoc :function) 55 | (dissoc :sample)))) 56 | 57 | (reg-event-fx 58 | :load-functions 59 | (fn [{db :db} _] 60 | (prn "load-functions") 61 | {:http-xhrio {:method :get 62 | :uri "/graphql" 63 | :params {:query (v/graphql-query {:venia/queries [[:sample_by_md5 {:md5 (:sample db)} 64 | [[:entrypoint [:va]] 65 | [:exports [:va]] 66 | ]]]})} 67 | :format (ajax/json-request-format) 68 | :response-format (ajax/json-response-format {:keywords? true}) 69 | :on-success [:loaded-functions] 70 | :on-failure [:errored-functions]}})) 71 | 72 | (reg-event-db 73 | :loaded-functions 74 | (fn [db [_ response]] 75 | (let [exports (get-in response [:data :sample_by_md5 :exports]) 76 | entrypoint (get-in response [:data :sample_by_md5 :entrypoint]) 77 | functions (conj exports entrypoint)] 78 | (prn "loaded functions: " functions) 79 | (assoc db :functions functions)))) 80 | 81 | (reg-event-db 82 | :errored-functions 83 | (fn [db error] 84 | (prn "errored-functions: " error) 85 | db)) 86 | 87 | (reg-event-db 88 | :select-function 89 | (fn [db [_ function-va]] 90 | (prn "select-function: " function-va) 91 | (dispatch [:load-function function-va]) 92 | (-> db 93 | (assoc :function function-va) 94 | (dissoc :blocks) 95 | (dissoc :edges) 96 | (dissoc :insns)))) 97 | 98 | (reg-event-db 99 | :unselect-function 100 | (fn [db _] 101 | (prn "unselect-function") 102 | (dissoc db :function))) 103 | 104 | (reg-event-fx 105 | :load-function 106 | (fn [{db :db} [_ function-va]] 107 | (prn "load-function" function-va) 108 | {:http-xhrio {:method :get 109 | :uri "/graphql" 110 | :params {:query (v/graphql-query 111 | {:venia/queries [[:function_by_md5_va {:md5 (:sample db) 112 | :va (:function db)} 113 | [[:blocks 114 | [:va 115 | [:edges_to 116 | [[:src [:va]] 117 | [:dst [:va]] 118 | :type]] 119 | [:edges_from 120 | [[:src [:va]] 121 | [:dst [:va]] 122 | :type]] 123 | [:insns 124 | [:va 125 | :mnem 126 | :opstr 127 | :size]]] 128 | ]]]]})} 129 | :format (ajax/json-request-format) 130 | :response-format (ajax/json-response-format {:keywords? true}) 131 | :on-success [:loaded-function] 132 | :on-failure [:errored-function]}})) 133 | 134 | 135 | (defn compute-edge-id 136 | [edge] 137 | (str (:src edge) "->" (:dst edge) "|" (:type edge))) 138 | 139 | (defn add-edge-id 140 | [edge] 141 | (assoc edge :id (compute-edge-id edge))) 142 | 143 | (defn api->edge 144 | [e] 145 | (-> e 146 | (update :type #(keyword (subs % 1))) ; :type looks like ":cjmp", so trim the leading colon, and make it a keyword. 147 | (assoc :src (get-in e [:src :va])) ; de-nest the src/dst addresses. 148 | (assoc :dst (get-in e [:dst :va])) 149 | (assoc :id (compute-edge-id e)))) 150 | 151 | (reg-event-db 152 | :loaded-function 153 | (fn [db [_ response]] 154 | (let [blocks (get-in response [:data :function_by_md5_va :blocks]) 155 | edges (concat (flatten (map :edges_to blocks)) 156 | (flatten (map :edges_from blocks))) 157 | edges' (into #{} (map api->edge edges)) 158 | insns (flatten (map :insns blocks))] 159 | (prn "loaded function" insns) 160 | (merge db {:blocks (utils/index-by :va blocks) 161 | :edges edges' 162 | :insns insns})))) 163 | 164 | (reg-event-db 165 | :errored-function 166 | (fn [db error] 167 | (prn "errored-function: " error) 168 | db)) 169 | -------------------------------------------------------------------------------- /lancelot-clj/resources/public/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | cfg-ui 6 | 7 | 8 | 9 | 10 | 256 | 257 | 258 |
259 | 260 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /construct-clj/test/construct_clj/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns construct-clj.core-test 2 | (:require [clojure.test :refer :all] 3 | [construct-clj.core :refer :all]) 4 | (:import (java.nio ByteBuffer ByteOrder))) 5 | 6 | 7 | (defn uint32->byte-buffer 8 | [integer] 9 | (let [byte-buffer (ByteBuffer/allocate 4)] 10 | (.order byte-buffer ByteOrder/BIG_ENDIAN) 11 | (.putInt byte-buffer 0 integer) 12 | byte-buffer)) 13 | 14 | (defn uint64->byte-buffer 15 | [integer] 16 | (let [byte-buffer (ByteBuffer/allocate 8)] 17 | (.order byte-buffer ByteOrder/BIG_ENDIAN) 18 | (.putLong byte-buffer 0 integer) 19 | byte-buffer)) 20 | 21 | (deftest size-test 22 | (let [byte-buffer (uint64->byte-buffer 0x1122334455667788)] 23 | (testing "numbers" 24 | (is (= (size (parse uint8 byte-buffer)) 1)) 25 | (is (= (size (parse int8 byte-buffer)) 1)) 26 | (is (= (size (parse uint16 byte-buffer)) 2)) 27 | (is (= (size (parse int16 byte-buffer)) 2)) 28 | (is (= (size (parse uint32 byte-buffer)) 4)) 29 | (is (= (size (parse int32 byte-buffer)) 4)) 30 | (is (= (size (parse uint64 byte-buffer)) 8)) 31 | (is (= (size (parse int64 byte-buffer)) 8))) 32 | (testing "array" 33 | (is (= (size (parse (array uint8 2) byte-buffer)) 2)) 34 | (is (= (size (parse (array uint16 2) byte-buffer)) 4)) 35 | (is (= (size (parse (array uint32 2) byte-buffer)) 8)) 36 | (is (= (size (parse (array (array uint8 2) 2) byte-buffer)) 4))) 37 | (testing "struct" 38 | (is (= (size (parse (struct [:a uint8 :b uint16 :c uint32]) byte-buffer)) 7)) 39 | (is (= (size (parse (struct [:a (struct [:x uint8 :y uint16]) 40 | :b (struct [:m uint8 :n uint16])]) 41 | byte-buffer)) 42 | 6))))) 43 | 44 | (deftest primitive-parse-test 45 | (let [byte-buffer (uint64->byte-buffer 0x1122334455667788)] 46 | (testing "numbers" 47 | (is (= (unpack (parse uint8 byte-buffer)) 0x11)) 48 | (is (= (unpack (parse int8 byte-buffer)) 0x11)) 49 | (is (= (unpack (parse uint16 byte-buffer)) 0x1122)) 50 | (is (= (unpack (parse int16 byte-buffer)) 0x1122)) 51 | (is (= (unpack (parse uint32 byte-buffer)) 0x11223344)) 52 | (is (= (unpack (parse int32 byte-buffer)) 0x11223344)) 53 | (is (= (unpack (parse uint64 byte-buffer)) 0x1122334455667788)) 54 | (is (= (unpack (parse int64 byte-buffer)) 0x1122334455667788)))) 55 | (let [byte-buffer (uint64->byte-buffer -1)] 56 | (testing "signed numbers" 57 | (is (= (unpack (parse uint8 byte-buffer)) 0xFF)) 58 | (is (= (unpack (parse int8 byte-buffer)) -1)) 59 | (is (= (unpack (parse uint16 byte-buffer)) 0xFFFF)) 60 | (is (= (unpack (parse int16 byte-buffer)) -1)) 61 | (is (= (unpack (parse uint32 byte-buffer)) 0xFFFFFFFF)) 62 | (is (= (unpack (parse int32 byte-buffer)) -1)) 63 | (is (= (unpack (parse uint64 byte-buffer)) 0xFFFFFFFFFFFFFFFF)) 64 | (is (= (unpack (parse int64 byte-buffer)) -1)))) 65 | (let [byte-buffer (uint64->byte-buffer 0x1122334455667788)] 66 | (testing "bytes" 67 | (is (= (repr (parse (byte-sequence 0) byte-buffer)) "")) 68 | (is (= (repr (parse (byte-sequence 1) byte-buffer)) "11")) 69 | (is (= (repr (parse (byte-sequence 2) byte-buffer)) "1122"))) 70 | (testing "array" 71 | (is (= (unpack (parse (array uint32 2) byte-buffer)) [0x11223344 0x55667788])) 72 | (is (= (unpack (parse (array uint16 4) byte-buffer)) [0x1122 0x3344 0x5566 0x7788])) 73 | (is (= (unpack (parse (array uint8 8) byte-buffer)) [0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88])) 74 | (is (= (unpack (second (parse-array-index (parse (array uint8 8) byte-buffer) 2))) 0x33))) 75 | (testing "nested array" 76 | (is (= (unpack (parse (array (array uint8 4) 2) byte-buffer)) [[0x11 0x22 0x33 0x44] [0x55 0x66 0x77 0x88]]))) 77 | (testing "ascii" 78 | (let [byte-buffer (uint64->byte-buffer 0x4142434445464748)] 79 | (is (= (unpack (parse (ascii 8) byte-buffer)) "ABCDEFGH")) 80 | (is (= (unpack (parse (utf-8 8) byte-buffer)) "ABCDEFGH")))))) 81 | 82 | (deftest hexify-test 83 | (let [bytes (byte-array 0x10)] 84 | (doseq [i (range 0x10)] 85 | (aset-byte bytes i i)) 86 | (testing "hexify" 87 | (is (= (hexify bytes) "000102030405060708090a0b0c0d0e0f"))) 88 | (testing "unhexify" 89 | ;; round-trippin' 90 | (is (= (hexify (unhexify (hexify bytes))) "000102030405060708090a0b0c0d0e0f"))))) 91 | 92 | (deftest repr-test 93 | (testing "numbers" 94 | (is (= (repr-hex 0) "0x0")) 95 | (is (= (repr-hex 1) "0x1")) 96 | (is (= (repr-hex 16) "0x10")) 97 | (is (= (repr-hex 256) "0x100"))) 98 | (testing "bytes" 99 | (let [byte-buffer (uint64->byte-buffer 0x1122334455667788)] 100 | (is (= (repr-bytes byte-buffer) "112233445566..."))) 101 | (let [byte-buffer (uint32->byte-buffer 0x11223344)] 102 | (is (= (repr-bytes byte-buffer) "11223344"))))) 103 | 104 | (deftest struct-parse-test 105 | (let [byte-buffer (uint64->byte-buffer 0x1122334455667788) 106 | spec (struct [:a uint8 107 | :b uint16 108 | :c uint32])] 109 | (testing "struct field indexes" 110 | (let [parse-result (parse spec byte-buffer)] 111 | (is (= (get-struct-field-index parse-result :a) 0)) 112 | (is (= (get-struct-field-index parse-result :b) 1)) 113 | (is (= (get-struct-field-index parse-result :c) 2)))) 114 | (testing "struct field sizes" 115 | (let [parse-result (parse spec byte-buffer)] 116 | (is (= (second (get-struct-index-size parse-result 0)) 1)) 117 | (is (= (second (get-struct-index-size parse-result 1)) 2)) 118 | (is (= (second (get-struct-index-size parse-result 2)) 4)))) 119 | (testing "struct offsets" 120 | (let [parse-result (parse spec byte-buffer)] 121 | (is (= (second (get-struct-field-offset parse-result :a)) 0)) 122 | (is (= (second (get-struct-field-offset parse-result :b)) 1)) 123 | (is (= (second (get-struct-field-offset parse-result :c)) 3)))) 124 | (testing "unpack fields" 125 | (let [parse-result (parse spec byte-buffer)] 126 | (is (= (second (unpack-struct-field parse-result :a)) 0x11)) 127 | (is (= (second (unpack-struct-field parse-result :b)) 0x2233)) 128 | (is (= (second (unpack-struct-field parse-result :c)) 0x44556677)))) 129 | (testing "unpack struct" 130 | (let [parse-result (parse spec byte-buffer)] 131 | (is (= (unpack parse-result) {:a 0x11 :b 0x2233 :c 0x44556677})) 132 | (is (= (unpack (parse (struct [:a (struct [:x uint8 :y uint16]) 133 | :b (struct [:m uint8 :n uint16])]) 134 | byte-buffer)) 135 | {:a {:x 0x11 :y 0x2233} :b {:m 0x44 :n 0x5566}})))))) 136 | 137 | (deftest parse-in-test 138 | (let [byte-buffer (uint64->byte-buffer 0x1122334455667788) 139 | nested (struct [:a (struct [:x uint8 :y uint16]) 140 | :b (struct [:m uint8 :n uint16])]) 141 | arrays (array (array uint8 4) 2) 142 | mixed (struct [:a (array uint8 4) :b (array uint16 2)])] 143 | (testing "nested structs" 144 | (let [r (parse nested byte-buffer)] 145 | (is (= (unpack (second (parse-in r [:a :x]))) 0x11)) 146 | (is (= (unpack (second (parse-in r [:a :y]))) 0x2233)) 147 | (is (= (unpack (second (parse-in r [:b :m]))) 0x44)) 148 | (is (= (unpack (second (parse-in r [:b :n]))) 0x5566)) 149 | (is (= (unpack (second (parse-in r [:a]))) {:x 0x11 :y 0x2233})) 150 | (is (= (unpack (second (parse-in r [:b]))) {:m 0x44 :n 0x5566})) 151 | (is (= (unpack (second (parse-in r []))) {:a {:x 0x11 :y 0x2233} :b {:m 0x44 :n 0x5566}})))) 152 | (testing "arrays" 153 | (let [r (parse arrays byte-buffer)] 154 | (is (= (unpack (second (parse-in r [0 0]))) 0x11)) 155 | (is (= (unpack (second (parse-in r [0 1]))) 0x22)) 156 | (is (= (unpack (second (parse-in r [0 3]))) 0x44)) 157 | (is (= (unpack (second (parse-in r [1 0]))) 0x55)) 158 | (is (= (unpack (second (parse-in r [1 1]))) 0x66)) 159 | (is (= (unpack (second (parse-in r [1 3]))) 0x88)))) 160 | (testing "mixed struct and arrays" 161 | (let [r (parse mixed byte-buffer)] 162 | (is (= (unpack (second (parse-in r [:a 0]))) 0x11)) 163 | (is (= (unpack (second (parse-in r [:a 1]))) 0x22)) 164 | (is (= (unpack (second (parse-in r [:a 3]))) 0x44)) 165 | (is (= (unpack (second (parse-in r [:b 0]))) 0x5566)) 166 | (is (= (unpack (second (parse-in r [:b 1]))) 0x7788)))))) 167 | 168 | (deftest dynamic-count-test 169 | (let [byte-buffer (uint64->byte-buffer 0x03656667FFFFFFFF)] 170 | (testing "pstring" 171 | (let [pstring (struct [:length uint8 172 | :value (ascii :length)]) 173 | r (parse pstring byte-buffer) 174 | u (unpack r)] 175 | (is (= (:length u) 0x3)) 176 | (is (= (:value u)) "abc") 177 | (is (= (size r) 0x4)))) 178 | (testing "astring" 179 | ;; let's define astring as like pstring, except the length field has only 7 useful bits. 180 | (let [astring (struct [:length uint8 181 | :value (ascii (fn [ctx spec] 182 | (let [[ctx length-result] (parse-in ctx [:length]) 183 | length (bit-and 0x7F (unpack length-result))] 184 | [ctx (assoc spec :static-size length)])))] 185 | :dynamic-size #(inc (unpack (parse uint8 %))) 186 | :repr #(str (:value (unpack %)))) 187 | r (parse astring byte-buffer) 188 | u (unpack r)] 189 | (is (= (:length u) 0x3)) 190 | (is (= (:value u) "abc")) 191 | (is (= (size r) 0x4)) 192 | (is (= (repr r) "abc")))))) 193 | -------------------------------------------------------------------------------- /lancelot-clj/test/lancelot_clj/anal_test.clj: -------------------------------------------------------------------------------- 1 | (ns lancelot-clj.anal-test 2 | (:require [clojure.test :refer :all] 3 | [pe.core :as pe] 4 | [lancelot-clj.dis :as dis] 5 | [lancelot-clj.anal :as analysis] 6 | [lancelot-clj.core :as core] 7 | [lancelot-clj.workspace :as workspace] 8 | [lancelot-clj.testutils :as testutils] 9 | [clojure.java.io :as io]) 10 | (:import (java.nio ByteBuffer ByteOrder)) 11 | (:import [capstone.Capstone]) 12 | (:import [capstone.X86_const])) 13 | 14 | 15 | (defn analyze-bytes 16 | [bytes] 17 | (let [cs (testutils/make-capstone capstone.Capstone/CS_ARCH_X86 capstone.Capstone/CS_MODE_32) 18 | base-addr 0x0 19 | buf (testutils/make-byte-buffer bytes) 20 | raw-insns (dis/disassemble-all cs buf base-addr)] 21 | (analysis/analyze-instructions raw-insns))) 22 | 23 | (deftest analysis-test 24 | 25 | (testing "instruction fall though test" 26 | (let [ianal (analyze-bytes [0x6A 0x10 ; 0: 6a 10 push 0x10 27 | 0x58 ; 2: 58 pop eax 28 | 0xE8 0xF8 0xFF 0xFF 0xFF ; 3: e8 f8 ff ff ff call 0 29 | 0xC3 ; 8: c3 ret 30 | 0xCD 0x80 ; 9: cd 80 int 0x80 31 | 0xCC ; b: cc int3 32 | ]) 33 | insns (:insns-by-addr ianal)] 34 | (is (= 1 (count (:flow (get insns 0x0))))) 35 | (is (= 1 (count (:flow (get insns 0x2))))) 36 | (is (= 1 (count (:flow (get insns 0x3))))) 37 | (is (= 0 (count (:flow (get insns 0x8))))) 38 | (is (= 0 (count (:flow (get insns 0x9))))) 39 | (is (= 0 (count (:flow (get insns 0xb))))))) 40 | 41 | (let [insn-analysis (analyze-bytes [0x55 ;; 0 push ebp 42 | 0x89 0xE5 ;; 1 mov ebp, esp 43 | 0x50 ;; 3 push eax 44 | 0x53 ;; 4 push ebx 45 | 0x51 ;; 5 push ecx 46 | 0x56 ;; 6 push esi 47 | 0x8B 0x75 0x08 ;; 7 mov esi, [ebp+arg_0] 48 | 0x8B 0x4D 0x0C ;; A mov ecx, [ebp+arg_4] 49 | 0xC1 0xE9 0x02 ;; D shr ecx, 2 50 | 0x8B 0x45 0x10 ;; 10 mov eax, [ebp+arg_8] 51 | 0x8B 0x5D 0x14 ;; 13 mov ebx, [ebp+arg_C] 52 | ;; 16: ; CODE XREF: +22 53 | 0x85 0xC9 ;; 16 test ecx, ecx 54 | 0x74 0x0A ;; 18 jz short +24 <<--- cjmp 55 | 0x31 0x06 ;; 1A xor [esi], eax 56 | 0x01 0x1E ;; 1C add [esi], ebx 57 | 0x83 0xC6 0x04 ;; 1E add esi, 4 58 | 0x49 ;; 21 dec ecx 59 | 0xEB 0xF2 ;; 22 jmp short +16 <<--- jmp, no fallthrough 60 | ;; 24: ; CODE XREF: +18 61 | 0x5E ;; 24 pop esi 62 | 0x59 ;; 25 pop ecx 63 | 0x5B ;; 26 pop ebx 64 | 0x58 ;; 27 pop eax 65 | 0xC9 ;; 28 leave 66 | 0xC2 0x10 0x00])] ;; 29 retn 10h <<--- ret, no fallthrough 67 | 68 | (testing "flow-analysis" 69 | (let [{:keys [insns-by-addr 70 | flows-by-src 71 | flows-by-dst]} insn-analysis] 72 | ;; this is the initial `push ebp` instruction. 73 | ;; just a single flow: fallthrough to next insn. 74 | (is (= (:flow (get insns-by-addr 0x0)) 75 | #{{:type :fall-through 76 | :address 0x1}})) 77 | ;; this is the `jz +24` instruction. 78 | ;; two flows: 79 | ;; - fallthrough to next insn. 80 | ;; - cjmp to +24 81 | (is (= (:flow (get insns-by-addr 0x18)) 82 | #{{:type :fall-through 83 | :address 0x1A} 84 | {:type :cjmp 85 | :address 0x24}})) 86 | ;; only flow from the `push ebp` is the fallthrough. 87 | (is (= 1 (count (get flows-by-src 0x0)))) 88 | ;; the `jz ...` has two possible next instructions. 89 | (is (= 2 (count (get flows-by-src 0x18)))) 90 | ;; entrypoint has no flows to it. 91 | (is (= 0 (count (get flows-by-dst 0x0)))) 92 | ;; the `mov ebp, esp` instruction can only be reached from `push ebp`. 93 | (is (= 1 (count (get flows-by-dst 0x1)))) 94 | ;; the `test ecx, ecx` instruction has two ways to get to it: 95 | ;; - fallthrough from previous instruction. 96 | ;; - jmp from address +22 97 | (is (= 2 (count (get flows-by-dst 0x16)))))) 98 | 99 | (testing "fallthrough-sequence-analysis" 100 | ;; this is the "basic block" from the entry (+0x0) until the jz (+0x18). 101 | ;; ends with a conditional jump. 102 | (let [bb0 (into #{} (analysis/read-fallthrough-sequence insn-analysis 0x0))] 103 | ;; first two instructions are in the basic block. 104 | (is (= true (contains? bb0 0x0))) 105 | (is (= true (contains? bb0 0x1))) 106 | ;; the overlapping instruction at 0x2 is not. 107 | (is (= false (contains? bb0 0x2))) 108 | ;; the `test ecx, ecx` insn in part of these fallthrough instructions. 109 | ;; however, it is not actually part of the basic block, because its split by the jmp. 110 | (is (= true (contains? bb0 0x16))) 111 | ;; the `jz` is part of the sequence, but nothing after it. 112 | (is (= true (contains? bb0 0x18))) 113 | (is (= false (contains? bb0 0x19))) 114 | (is (= false (contains? bb0 0x1A)))) 115 | ;; this is the "basic block" from the `xor` (+0x1A) until the `jmp` (+0x22). 116 | ;; ends with an unconditional jump (non-fallthrough instruction). 117 | (let [bb1 (into #{} (analysis/read-fallthrough-sequence insn-analysis 0x1A))] 118 | ;; the xor at +0x1A 119 | (is (= true (contains? bb1 0x1A))) 120 | (is (= false (contains? bb1 0x19))) 121 | (is (= false (contains? bb1 0x1B))) 122 | ;; the jmp at +0x22 123 | (is (= true (contains? bb1 0x22))) 124 | (is (= false (contains? bb1 0x23))) 125 | (is (= false (contains? bb1 0x24)))) 126 | ;; this is the "basic block" from the `pop esi` (+0x24) until the `ret` (+0x29). 127 | ;; ends with an instruction with no successors. 128 | (let [bb2 (into #{} (analysis/read-fallthrough-sequence insn-analysis 0x24))] 129 | ;; the `pop esi` at +0x24 130 | (is (= true (contains? bb2 0x24))) 131 | (is (= false (contains? bb2 0x23))) 132 | ;; the `ret` at +0x29 133 | (is (= true (contains? bb2 0x29))) 134 | (is (= false (contains? bb2 0x2A))))) 135 | 136 | (testing "reachable-instruction-analysis" 137 | (let [reachable-insns (analysis/find-reachable-addresses insn-analysis 0x0)] 138 | (is (= reachable-insns #{0x0 0x1 0x3 0x4 0x5 139 | 0x6 0x7 0xA 0xD 0x10 140 | 0x13 0x16 0x18 0x1a 141 | 0x1c 0x1e 0x21 0x22 142 | 0x24 0x25 0x26 0x27 143 | 0x28 0x29})))) 144 | 145 | (testing "bb-analysis" 146 | (is (= (analysis/read-basic-block insn-analysis 0x0) 147 | ;; all instructions before `test ecx, ecx` at 0x16. 148 | [0x0 0x1 0x3 0x4 0x5 0x6 0x7 0xA 0xD 0x10 0x13])) 149 | (is (= (analysis/read-basic-block insn-analysis 0x16) 150 | [0x16 0x18])) 151 | (is (= (analysis/read-basic-block insn-analysis 0x1A) 152 | [0x1a 0x1c 0x1e 0x21 0x22])) 153 | (is (= (analysis/read-basic-block insn-analysis 0x24) 154 | [0x24 0x25 0x26 0x27 0x28 0x29]))) 155 | 156 | (testing "function analysis" 157 | (let [bbs (analysis/get-function-blocks insn-analysis 0x0) 158 | flows (into #{} (analysis/get-block-flows insn-analysis bbs))] 159 | (is (= (sort (keys bbs)) (list 0x0 0x16 0x1A 0x24))) 160 | (is (= true (contains? flows {:src 0x0 :dst 0x16 :type :fall-through}))) 161 | (is (= true (contains? flows {:src 0x16 :dst 0x1A :type :fall-through}))) 162 | (is (= true (contains? flows {:src 0x16 :dst 0x24 :type :cjmp}))) 163 | (is (= true (contains? flows {:src 0x1A :dst 0x16 :type :jmp})))))) 164 | 165 | (let [insn-analysis (analyze-bytes [;;00000000 : 166 | ;;0: b8 01 00 00 00 mov eax,0x1 167 | ;;5: e8 01 00 00 00 call b 168 | ;;a: c3 ret 169 | ;;0000000b : 170 | ;;b: b8 02 00 00 00 mov eax,0x2 171 | ;;10: e8 01 00 00 00 call 16 172 | ;;15: c3 ret 173 | ;;00000016 : 174 | ;;16: b8 03 00 00 00 mov eax,0x3 175 | ;;1b: e8 e0 ff ff ff call 0 176 | ;;20: c3 ret 177 | 0xB8, 0x01, 0x00, 0x00, 0x00, 178 | 0xE8, 0x01, 0x00, 0x00, 0x00, 179 | 0xC3, 180 | 0xB8, 0x02, 0x00, 0x00, 0x00, 181 | 0xE8, 0x01, 0x00, 0x00, 0x00, 182 | 0xC3, 183 | 0xB8, 0x03, 0x00, 0x00, 0x00, 184 | 0xE8, 0xE0, 0xFF, 0xFF, 0xFF, 185 | 0xC3])] 186 | 187 | (testing "find-function-targets" 188 | (is (= '(0xB) (analysis/find-function-targets insn-analysis 0x0))) 189 | (is (= '(0x16) (analysis/find-function-targets insn-analysis 0xB))) 190 | (is (= '(0x0) (analysis/find-function-targets insn-analysis 0x16)))) 191 | 192 | (testing "find-functions" 193 | (is (= #{0x0 0xB 0x16} (analysis/find-functions insn-analysis (list 0x0))))))) 194 | 195 | -------------------------------------------------------------------------------- /pe-clj/LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor to control, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /capstone-clj/LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor to control, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /construct-clj/LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor to control, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /lancelot-clj/LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor to control, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /unicorn-clj/LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor to control, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /lancelot-clj/src/lancelot_cljs/views.cljs: -------------------------------------------------------------------------------- 1 | (ns lancelot-cljs.views 2 | (:require [reagent.core :as reagent] 3 | [re-frame.core :refer [subscribe dispatch]] 4 | [clojure.string :as str] 5 | [lancelot_cljs.utils :as utils] 6 | [lancelot_cljs.layout.klay :as klay] 7 | [lancelot_cljs.layout.dagre :as dagre] 8 | )) 9 | 10 | (def evt re-frame.core/dispatch) 12 | 13 | (defn hex-format 14 | "format the given number into a hex string. 15 | 16 | example:: 17 | => (hex-format 10) 18 | '0xA' 19 | " 20 | [n] 21 | (str "0x" (str/upper-case (.toString n 16)))) 22 | 23 | (defn parse-hex [#^String s] 24 | (js/parseInt s)) 25 | 26 | ;;; 27 | ;;; geometric/canvas drawing components 28 | ;;; 29 | 30 | 31 | (defn canvas 32 | " 33 | component that renders the given children on a pan-able canvas. 34 | mouse click-drag pans the canvas, while mouse wheel in/out zooms it. 35 | 36 | example:: 37 | => [canvas 38 | [:h1#title 'hello world!']] 39 | " 40 | ([meta children] 41 | ;; this works by constructing a viewport over a "canvas" div containing the children. 42 | ;; as the client moves the mouse to pan, we translate the canvas. 43 | ;; 44 | ;; we capture events at the viewport layer, and apply the translations to the canvas layer. 45 | ;; 46 | ;; the size of the canvas may exceed that of the viewport; its no problem, as we can use CSS to clip it. 47 | ;; 48 | (let [state (reagent/atom {:shift-left 0 ; the x translation of the canvas 49 | :shift-top 0 ; the y translation of the canvas 50 | :dragging false ; is the user currently dragging? 51 | :drag-x 0 ; the x delta since the user started dragging, 0 if not dragging 52 | :drag-y 0 ; the y delta since the user started dragging, 0 if not dragging 53 | :zoom 1.0})] ; the zoom scale of the canvas 54 | (fn [] 55 | [:div.canvas-viewport 56 | (merge 57 | meta 58 | {:on-wheel 59 | ;; handle zooming in/out. 60 | ;; just a simple update to the zoom translation. 61 | (fn [e] 62 | (.preventDefault e) 63 | (let [zoom-factor 1.1 64 | delta (.-deltaY e)] 65 | (if (> 0 delta) 66 | (swap! state update :zoom #(* zoom-factor %)) 67 | (swap! state update :zoom #(/ % zoom-factor))))) 68 | :on-mouse-down 69 | ;; handle the mouse starting a drag. 70 | ;; on drag, we capture a few things: 71 | ;; - that dragging is in progress, 72 | ;; - where the dragging began, and 73 | ;; - the x-y delta from when when dragging began (always (0, 0) for :on-mouse-down) 74 | ;; 75 | ;; when we apply the translation to the canvas layer, the x-y coordinate gets calculated from: 76 | ;; 77 | ;; (+ initial-location drag-delta) 78 | ;; 79 | ;; where drag-delta is: 80 | ;; 81 | ;; (- current-drag-location drag-start) 82 | (fn [e] 83 | (.preventDefault e) 84 | (let [evt (or e (js/event)) 85 | client-x (.-clientX evt) 86 | client-y (.-clientY evt)] 87 | (swap! state merge {:dragging true 88 | :down-x client-x 89 | :down-y client-y 90 | :drag-x 0 91 | :drag-y 0}))) 92 | :on-mouse-move 93 | ;; handle mouse continuing a drag. 94 | ;; we've already recorded where the drag started, so just need to update the drag-delta. 95 | (fn [e] 96 | (.preventDefault e) 97 | (when (:dragging @state) 98 | (let [evt (or e (js/event)) 99 | client-x (.-clientX evt) 100 | client-y (.-clientY evt)] 101 | (swap! state merge {:drag-x (- client-x (:down-x @state)) 102 | :drag-y (- client-y (:down-y @state))})))) 103 | :on-mouse-up 104 | ;; handle the mouse ending a drag. 105 | ;; now that the drag is complete, we commit the delta to the canvas layer position. 106 | (fn [e] 107 | (.preventDefault e) 108 | (when (:dragging @state) 109 | (let [evt (or e (js/event)) 110 | client-x (.-clientX evt) 111 | client-y (.-clientY evt)] 112 | (swap! state #(-> % 113 | (dissoc :down-x) 114 | (dissoc :down-y) 115 | (merge {:dragging false 116 | :drag-x 0 117 | :drag-y 0 118 | :shift-left (+ (:shift-left @state) 119 | (- client-x (:down-x @state))) 120 | :shift-top (+ (:shift-top @state) 121 | (- client-y (:down-y @state)))})))))) 122 | :on-mouse-leave 123 | ;; handle when the mouse exceeds the bounds of the viewport. 124 | ;; commit the current drag, and end it. 125 | ;; note this is a duplication of :on-mouse-up. TODO: refactor code. 126 | ;; 127 | ;; note: don't try to change this to use :on-mouse-out. 128 | ;; that event fires when the mouse enters another element, which happens often during a lagging drag. 129 | (fn [e] 130 | (when (:dragging @state) 131 | (.preventDefault e) 132 | (let [evt (or e (js/event)) 133 | client-x (.-clientX evt) 134 | client-y (.-clientY evt)] 135 | (swap! state #(-> % 136 | (dissoc :down-x) 137 | (dissoc :down-y) 138 | (merge {:dragging false 139 | :drag-x 0 140 | :drag-y 0 141 | :shift-left (+ (:shift-left @state) 142 | (- client-x (:down-x @state))) 143 | :shift-top (+ (:shift-top @state) 144 | (- client-y (:down-y @state)))})))))) 145 | 146 | }) 147 | [:div.canvas 148 | {:style {:position "relative" ; position relative so that children can be absolute relative to this element. 149 | :transform-origin "center center" 150 | :transform 151 | (let [{:keys [zoom drag-x drag-y shift-left shift-top]} @state] 152 | (str 153 | "translate(" (+ drag-x shift-left) "px, " 154 | (+ drag-y shift-top) "px) " 155 | "scale(" zoom ") "))}} 156 | children]]))) 157 | ([children] (canvas {} children)) 158 | ([] (canvas {} [:div.empty]))) 159 | 160 | (defn positioned 161 | "wrap the given children with a div at the given x-y coordinates. 162 | this is useful when you want to place an element on a canvas at a specific place. 163 | 164 | example:: 165 | 166 | => [canvas 167 | [positioned {:x 1 :y 10} 168 | [:div#title 'hello world!']] 169 | [positioned {:x 1 :y 12} 170 | [:div#trailer 'goodbye world!']]] 171 | " 172 | [{:keys [x y]} children] 173 | [:div.laid-out 174 | {:style {:position "absolute" ; absolute position is relative to origin of the canvas. 175 | :float "left" 176 | :display "inline" 177 | :top (str y "em") 178 | :left (str x "em")}} 179 | children]) 180 | 181 | (def sqrt (.-sqrt js/Math)) 182 | (def PI (.-PI js/Math)) 183 | (def atan2 (.-atan2 js/Math)) 184 | 185 | ;; these line drawing algorithms ripped directly from: 186 | ;; http://stackoverflow.com/questions/4270485/drawing-lines-on-html-page 187 | 188 | (defn geoline 189 | "draw a 'line' from the given x-y coordinates with the given length and angle. 190 | the coordinates are given in ems. 191 | the angle is given in radians. 192 | 193 | you should probably CSS-style the line with: 194 | 195 | border-top: px solid #; 196 | " 197 | [x y length angle] 198 | [:div.line 199 | {:style {:width (str length "em") 200 | :transform (str "rotate(" angle "rad)") 201 | :top (str y "em") 202 | :left (str x "em")}}]) 203 | 204 | (defn line 205 | "draw a 'line' between the two given x-y coordinates." 206 | [x2 y2 x1 y1] 207 | (let [a (- x1 x2) 208 | b (- y1 y2) 209 | c (sqrt 210 | (+ 211 | (* a a) 212 | (* b b))) 213 | sx (/ (+ x1 x2) 2) 214 | sy (/ (+ y1 y2) 2) 215 | x (- sx (/ c 2)) 216 | y sy 217 | alpha (- PI (atan2 (- b) a))] 218 | [geoline x y c alpha])) 219 | 220 | ;;; 221 | ;;; application components 222 | ;;; 223 | 224 | 225 | (defn sample-list 226 | [samples] 227 | [:ul.sample-list 228 | (for [{md5 :md5} samples] 229 | ^{:key md5} 230 | [:li.sample-entry 231 | [:a.sample-link 232 | {:href "#" 233 | :on-click #(dispatch [:select-sample md5])} 234 | md5]])]) 235 | 236 | (defn function-list 237 | [functions] 238 | [:ul.function-list 239 | (for [{va :va} functions] 240 | ^{:key va} 241 | [:li.function-entry 242 | [:a.function-link 243 | {:href "#" 244 | :on-click #(dispatch [:select-function va])} 245 | (hex-format va)]])]) 246 | 247 | (defn function-nav-bar 248 | [] 249 | (let [value (reagent/atom "") 250 | submit (fn [] 251 | (let [va (parse-hex @value)] 252 | (when (and (number? va) (not (js/isNaN va))) 253 | (dispatch [:select-function va]))))] 254 | (fn [] 255 | [:div.function-nav-bar 256 | [:input {:type "text" 257 | :value @value 258 | :on-change (fn [evt] 259 | (let [v (-> evt .-target .-value)] 260 | (reset! value v))) 261 | :on-key-press (fn [e] 262 | (when (= 13 (.-charCode e)) 263 | (submit)))}] 264 | [:input {:type "button" 265 | :value "go" 266 | :on-click submit}]]))) 267 | 268 | (defn format-insn 269 | [insn] 270 | (str (hex-format (:va insn)) " " (:mnem insn) " " (:opstr insn))) 271 | 272 | (defn insn-list 273 | [insns] 274 | [:ul 275 | (for [insn (sort :va insns)] 276 | ^{:key (:va insn)} 277 | [:div (format-insn insn)])]) 278 | 279 | (defn basic-block 280 | [va] 281 | (let [block @(subscribe [:basic-block va])] 282 | [:div.basic-block 283 | [:div.bb-header "basic block " (hex-format (:va block))] 284 | [:div.bb-content 285 | [:table 286 | [:thead] 287 | [:tbody 288 | (for [insn (:insns block)] 289 | ^{:key (:va insn)} 290 | [:tr.insn 291 | [:td.va (hex-format (:va insn))] 292 | [:td.padding-1 {:style {:min-width "1em"}}] 293 | ;; TODO: re-enable bytes 294 | [:td.bytes #_(str/upper-case (:bytes insn))] 295 | [:td.padding-2 {:style {:min-width "1em"}}] 296 | [:td.mnem (:mnem insn)] 297 | [:td.padding-3 {:style {:min-width "1em"}}] 298 | [:td.operands (:opstr insn)] 299 | [:td.padding-4 {:style {:min-width "1em"}}] 300 | [:td.comments (when (and (:comments insn) 301 | (not= "" (:comments insn))) 302 | (str "; " (:comments insn)))]])]]]])) 303 | 304 | (defn compute-bb-height 305 | "compute the height, in lines, of the given basic block. 306 | when dealing when with em-based coordinate system, this is the height of the basic block component. 307 | " 308 | [bb] 309 | (let [insn-count (count (:insns bb)) 310 | ;; assume header size is 1em, 311 | ;; which is defined in the css style. 312 | header-size 1] 313 | (+ header-size insn-count))) 314 | 315 | (defn compute-bb-width 316 | "compute the width, in characters, of the given basic block 317 | when dealing when with em-based coordinate system, this is the width of the basic block component. 318 | " 319 | [bb] 320 | ;; the following constants are defined in the basic-block component. 321 | (let [padding-1-size 1 322 | padding-2-size 1 323 | padding-3-size 1 324 | padding-4-size 1 325 | bytes-size 12 326 | mnem-size 6 327 | operands-size (apply max (map #(count (:opstr %)) (:insns bb))) 328 | comments-size (apply max (map #(count (:comments %)) (:insns bb)))] 329 | (+ padding-1-size 330 | padding-2-size 331 | padding-3-size 332 | padding-4-size 333 | bytes-size 334 | mnem-size 335 | operands-size))) 336 | 337 | (defn layout-cfg-klay 338 | "invoke the klay library to layout the given basic blocks and edges. 339 | the library will call the given success or error handlers, as appropriate. 340 | " 341 | [basic-blocks edges s e] 342 | (when (< 0 (count (remove nil? basic-blocks))) 343 | (let [bbs (map #(-> % 344 | (assoc :width (compute-bb-width %)) 345 | (assoc :height (compute-bb-height %)) 346 | (dissoc :edges_to) 347 | (dissoc :edges_from)) 348 | basic-blocks) 349 | g (klay/make) 350 | g (reduce klay/add-node g bbs) 351 | g (reduce klay/add-edge g edges)] 352 | (klay/layout g 353 | (fn [r] 354 | (s {:nodes (klay/get-nodes r) 355 | :edges (klay/get-edges r)})) 356 | (fn [err] 357 | (e {:msg "klay: error" 358 | :error err})))))) 359 | 360 | (defn layout-cfg 361 | "invoke the layout library to layout the given blocks and edges. 362 | the library will call the given success or error handlers, as appropriate. 363 | 364 | Args: 365 | basic-blocks: sequence of maps with keys: 366 | - :va 367 | - :insns 368 | edges: sequence of maps with keys: 369 | - :id 370 | - :src 371 | - :dst 372 | - :type 373 | s: function accepting arguments: 374 | - nodes: sequence of maps with keys: 375 | - :id: the va of the basic block 376 | - :x 377 | - :y 378 | - edges: sequence of maps with keys: 379 | - :id 380 | - :type 381 | - :points: sequence of maps with keys: 382 | - :x 383 | - :y 384 | e: function accepting arguments: 385 | - error: map of error details 386 | " 387 | [basic-blocks edges s e] 388 | (layout-cfg-klay basic-blocks edges s e)) 389 | ;;(layout-cfg-dagre basic-blocks s e)) 390 | 391 | (defn edge-line 392 | "draw a control-flow graph multi-segment line" 393 | [edge] 394 | [:div 395 | {:class (condp = (:type edge) 396 | :fall-through "edge-false" 397 | :cjmp "edge-true" 398 | :jmp "edge-jmp" 399 | "edge-unk")} 400 | (doall 401 | (for [pair (partition 2 1 (:points edge))] 402 | (let [{x1 :x y1 :y} (first pair) 403 | {x2 :x y2 :y} (second pair)] 404 | ^{:key (str x1 "-" y1 "-" x2 "-" y2)} 405 | [line x1 y1 x2 y2])))]) 406 | 407 | ;; TODO: dup with events.cljs 408 | (defn compute-edge-id 409 | [edge] 410 | (str (:src edge) "->" (:dst edge) "|" (:type edge))) 411 | 412 | (defn add-edge-id 413 | [edge] 414 | (assoc edge :id (compute-edge-id edge))) 415 | 416 | (defn function-graph 417 | "display a control-flow graph of the given basic blocks and edges. 418 | " 419 | [basic-blocks edges] 420 | ;; the implementation here is a little tricky because the layout engine is async. 421 | ;; so, the `layout` atom contains the positions for nodes/edges. 422 | ;; we'll populate this as soon as its available. 423 | ;; until then, the blocks have a random placement. 424 | (let [;; the edges are passed directly to `edge-line`. 425 | ;; the nodes are x-y coordinates that must be correlated with existing basic blocks. 426 | ;; the :id of the node matches the :va of the basic block. 427 | layout (reagent/atom {:nodes {} 428 | :edges []})] 429 | (layout-cfg 430 | basic-blocks edges 431 | (fn [{layout-nodes :nodes layout-edges :edges}] 432 | (swap! layout merge {:nodes (utils/index-by :id layout-nodes) 433 | :edges (map add-edge-id layout-edges)})) 434 | (fn [err] (prn "layout error: " err))) 435 | (fn [_ _] 436 | ;; note that we ignore the arguments to this re-render. 437 | ;; instead we use the results of the layout from local state. 438 | [canvas 439 | (concat (doall 440 | (for [va (map :va basic-blocks)] 441 | ^{:key va} 442 | [positioned 443 | (get-in @layout [:nodes va]) 444 | [basic-block va]])) 445 | (doall 446 | (for [edge (:edges @layout)] 447 | ^{:key (:id edge)} 448 | [edge-line edge])))]))) 449 | 450 | (defn nav-bar 451 | [] 452 | [:ul.nav 453 | [:li.home 454 | {:on-click #(dispatch [:unselect-sample])} 455 | "root"] 456 | (when ( {1 {:a 1 :b 2} 19 | 3 {:a 3 :b 4}} 20 | " 21 | [col k] 22 | (into {} (map #(vector (get % k) %) col))) 23 | 24 | 25 | (defn- conj-if [c e] 26 | (if (not (nil? e)) 27 | (conj c e) 28 | c)) 29 | 30 | 31 | (defn- assoc-if [m k e] 32 | (if (not (nil? e)) 33 | (assoc m k e) 34 | m)) 35 | 36 | 37 | (defn call? 38 | [insn] 39 | (condp = (. insn id) 40 | capstone.X86_const/X86_INS_CALL true 41 | capstone.X86_const/X86_INS_LCALL true 42 | false)) 43 | 44 | 45 | (defn ret? 46 | [insn] 47 | (condp = (. insn id) 48 | capstone.X86_const/X86_INS_RET true 49 | capstone.X86_const/X86_INS_IRET true 50 | capstone.X86_const/X86_INS_IRETD true 51 | capstone.X86_const/X86_INS_IRETQ true 52 | false)) 53 | 54 | 55 | (defn jmp? [insn] (= (. insn id) capstone.X86_const/X86_INS_JMP)) 56 | 57 | 58 | (def ^:const x86-cjmp-instructions 59 | #{capstone.X86_const/X86_INS_JAE 60 | capstone.X86_const/X86_INS_JA 61 | capstone.X86_const/X86_INS_JBE 62 | capstone.X86_const/X86_INS_JB 63 | capstone.X86_const/X86_INS_JCXZ 64 | capstone.X86_const/X86_INS_JECXZ 65 | capstone.X86_const/X86_INS_JE 66 | capstone.X86_const/X86_INS_JGE 67 | capstone.X86_const/X86_INS_JG 68 | capstone.X86_const/X86_INS_JLE 69 | capstone.X86_const/X86_INS_JL 70 | capstone.X86_const/X86_INS_JNE 71 | capstone.X86_const/X86_INS_JNO 72 | capstone.X86_const/X86_INS_JNP 73 | capstone.X86_const/X86_INS_JNS 74 | capstone.X86_const/X86_INS_JO 75 | capstone.X86_const/X86_INS_JP 76 | capstone.X86_const/X86_INS_JRCXZ 77 | capstone.X86_const/X86_INS_JS}) 78 | 79 | 80 | (defn cjmp? [insn] (contains? x86-cjmp-instructions (. insn id))) 81 | 82 | 83 | (defn get-op0 84 | "fetch the first operand to the instruction" 85 | [insn] 86 | (let [[op &rest] (.. insn operands op)] 87 | op)) 88 | 89 | 90 | ;; capstone indexing: 91 | ;; given: [eax+10h] 92 | ;; - segment: 0x0 93 | ;; - base: 0x13 (eax) 94 | ;; - index: 0x0 95 | ;; - disp: 0x10 96 | 97 | 98 | (defn indirect-target? 99 | [insn] 100 | (let [op (get-op0 insn)] 101 | (cond 102 | ;; jmp eax 103 | (= (.-type op) capstone.X86_const/X86_OP_REG) true 104 | ;; jmp [eax+0x10] 105 | ;; jmp [eax*0x8+0x10] 106 | (and (= (.-type op) capstone.X86_const/X86_OP_MEM) 107 | (or (not= (.. op value mem base) capstone.X86_const/X86_REG_INVALID) 108 | (not= (.. op value mem index) capstone.X86_const/X86_REG_INVALID))) true 109 | :default false))) 110 | 111 | 112 | (defn get-target 113 | "assuming the given instruction has a first operand that is not indirect." 114 | [insn] 115 | (let [op (get-op0 insn)] 116 | (cond 117 | (= (.-type op) capstone.X86_const/X86_OP_IMM) (.. op value imm) 118 | ;; should we annotate this value with the `deref`? 119 | ;; upside: more information. 120 | ;; downside: inconsistent return value type. 121 | (= (.-type op) capstone.X86_const/X86_OP_MEM) {:deref (.. op value mem disp)} 122 | :default nil))) 123 | 124 | 125 | (defn nop? 126 | [insn] 127 | (if (= (.-id insn) capstone.X86_const/X86_INS_NOP) 128 | true 129 | (if (not (= (count (.-op (.-operands insn))) 2)) 130 | false 131 | (let [[op0 op1] (.-op (.-operands insn))] 132 | (cond 133 | ;; via: https://github.com/uxmal/nucleus/blob/master/disasm.cc 134 | (and (= (. insn id) capstone.X86_const/X86_INS_MOV) 135 | (= (. op0 type) capstone.X86_const/X86_OP_REG) 136 | (= (. op1 type) capstone.X86_const/X86_OP_REG) 137 | (= (.. op0 value reg) (.. op1 value reg))) true 138 | (and (= (. insn id) capstone.X86_const/X86_INS_XCHG) 139 | (= (. op0 type) capstone.X86_const/X86_OP_REG) 140 | (= (. op1 type) capstone.X86_const/X86_OP_REG) 141 | (= (.. op0 value reg) (.. op1 value reg))) true 142 | (and (= (. insn id) capstone.X86_const/X86_INS_LEA) 143 | (= (. op0 type) capstone.X86_const/X86_OP_REG) 144 | (= (. op1 type) capstone.X86_const/X86_OP_MEM) 145 | (= (.. op1 value mem segment) capstone.X86_const/X86_REG_INVALID) 146 | (= (.. op1 value mem base) (.. op0 value reg)) 147 | (= (.. op1 value mem index) capstone.X86_const/X86_REG_INVALID) 148 | (= (.. op1 value mem disp) 0)) true 149 | :default false))))) 150 | 151 | (defn fall-through? 152 | [insn] 153 | ;; we'd like to use `case` here, but capstone fields are not contants. 154 | (condp = (.-id insn) 155 | capstone.X86_const/X86_INS_RET false 156 | capstone.X86_const/X86_INS_JMP false 157 | capstone.X86_const/X86_INS_RETF false 158 | capstone.X86_const/X86_INS_IRET false 159 | capstone.X86_const/X86_INS_IRETD false 160 | capstone.X86_const/X86_INS_IRETQ false 161 | capstone.X86_const/X86_INS_INT false 162 | capstone.X86_const/X86_INS_INT1 false 163 | capstone.X86_const/X86_INS_INT3 false 164 | capstone.X86_const/X86_INS_INTO false 165 | true)) 166 | 167 | (defn analyze-instruction-flow 168 | [insn] 169 | (-> #{} 170 | (conj-if (when (fall-through? insn) 171 | {:type :fall-through 172 | :address (+ (. insn address) (. insn size))})) 173 | (conj-if (when (and (jmp? insn) 174 | (not (indirect-target? insn))) 175 | {:type :jmp 176 | :address (get-target insn)})) 177 | (conj-if (when (and (cjmp? insn) 178 | (not (indirect-target? insn))) 179 | {:type :cjmp 180 | :address (get-target insn)})))) 181 | 182 | 183 | (defn analyze-instruction 184 | " 185 | extract features from the given capstone instruction instance. 186 | 187 | Returns: 188 | map: keys: 189 | - :flow - set of flow references (fallthrough, jmp, cjmp). 190 | - :cref - set of code references (calls). 191 | - :insn - capstone instruction instance. 192 | - :address - va of instruction. 193 | " 194 | [insn] 195 | (-> {:flow (analyze-instruction-flow insn) 196 | :insn insn 197 | :address (.address insn)} 198 | (assoc-if :cref (when (and (call? insn) 199 | (not (indirect-target? insn))) 200 | #{{:address (get-target insn)}})))) 201 | 202 | 203 | (defn compute-instruction-flows 204 | " 205 | flows are the paths from a source instruction to successor instructions. 206 | 207 | Returns: 208 | lazy sequence of maps with keys: 209 | - :src - the source address. 210 | - :dst - the destination address. 211 | - :type - the flow type (:fall-through, :jmp, :cjmp) 212 | " 213 | [insns] 214 | (flatten (for [insn insns] 215 | (for [flow (:flow insn)] 216 | {:src (:address insn) 217 | :dst (:address flow) 218 | :type (:type flow)})))) 219 | 220 | 221 | (defn analyze-instructions 222 | [raw-insns] 223 | (let [insns (map analyze-instruction (filter some? raw-insns)) 224 | insns-by-addr (index-by insns :address) 225 | flows (into [] (compute-instruction-flows (vals insns-by-addr)))] 226 | {:insns-by-addr insns-by-addr 227 | :flows-by-src (group-by :src flows) 228 | :flows-by-dst (group-by :dst flows)})) 229 | 230 | 231 | (defn read-fallthrough-sequence 232 | " 233 | collect a sequence of instruction addresses from the given address that look sorta like a basic block. 234 | that is, they simply fall through from one to another. 235 | note, this routine cannot determine when an otherwise contiguous basic block is split by the target of a jump. 236 | 237 | example:: 238 | 239 | (read-fallthrough-sequence (analyze-instructions (disassemble-all ...)) 0x401000) 240 | => [0x401000 0x401001 0x4010003 ...] 241 | " 242 | [{:keys [insns-by-addr]} start-addr] 243 | (loop [bb-addrs [] 244 | addr start-addr] 245 | (let [insn (get insns-by-addr addr)] 246 | (cond 247 | ;; no successors, this must be last insn. 248 | (= 0 (count (:flow insn))) (conj bb-addrs addr) 249 | ;; multiple successors, this must be a cjmp, so this is end of bb. 250 | (< 1 (count (:flow insn))) (conj bb-addrs addr) 251 | ;; single successor, but not fallthrough, so its a jmp, and this is end of bb. 252 | (not (= :fall-through (:type (first (:flow insn))))) (conj bb-addrs addr) 253 | :else (recur (conj bb-addrs addr) 254 | (:address (first (:flow insn)))))))) 255 | 256 | 257 | (defn find-reachable-addresses 258 | " 259 | collect the set of instruction addresses that are reachable by following forward flows from the given address. 260 | 261 | example:: 262 | 263 | (find-reachable-addresses (analyze-instructions (disassemble-all ...)) 0x401000) 264 | => #{0x401000 0x401001 0x4010003 ...} 265 | " 266 | [{:keys [insns-by-addr]} start-addr] 267 | ;; make queue of addresses to explore. 268 | ;; pop address. 269 | ;; read fallthrough sequence. 270 | ;; update seen addrs. 271 | ;; find next addrs to explore. 272 | ;; if seen, break. 273 | ;; else, push to queue. 274 | ;; repeat until queue empty. 275 | (loop [q (conj clojure.lang.PersistentQueue/EMPTY start-addr) 276 | seen #{}] 277 | (if-let [addr (peek q)] 278 | (if (contains? seen addr) 279 | ;; if already processed, keep going 280 | (recur (pop q) seen) 281 | 282 | ;; else, read the sequence of fallthrough instructions and update seen set. 283 | (let [q (pop q) 284 | run (read-fallthrough-sequence insns-by-addr addr) 285 | seen' (set/union seen (into #{} run)) 286 | last-insn-addr (last run) 287 | last-insn (get insns-by-addr last-insn-addr) 288 | flow-addrs (map :address (:flow last-insn))] 289 | (recur (apply conj q flow-addrs) seen'))) 290 | ;; when work is done, return set of seen addresses. 291 | seen))) 292 | 293 | 294 | (defn read-basic-block 295 | " 296 | collect the instruction addresses of the basic block from the given address. 297 | if the given address is not the start of a basic block, the behavior is undefined. 298 | 299 | example:: 300 | 301 | ;; implicitly compute reachability, more concise in one-off situations. 302 | (read-basic-block (analyze-instructions (disassemble-all ...)) 0x401000) 303 | => [0x401000 0x401001 0x4010003 ...] 304 | 305 | example:: 306 | 307 | ;; explicitly compute reachability, more performant when invoking many times. 308 | (let [insn-analysis (analyze-instructions (disassemble-all ...)) 309 | reachable (find-reachable-addresses insn-analysis 0x401000)] 310 | (read-basic-block insn-analysis 0x401000 reachable) 311 | => [0x401000 0x401001 0x4010003 ...] 312 | " 313 | ([{:keys [insns-by-addr flows-by-dst]} start-addr reachable-addrs] 314 | {:pre [(map? insns-by-addr) 315 | (set? reachable-addrs) 316 | (number? start-addr)]} 317 | (loop [bb-addrs [] 318 | addr start-addr] 319 | (let [insn (get insns-by-addr addr)] 320 | (cond 321 | ;; no successors, this must be last insn. 322 | (= 0 (count (:flow insn))) 323 | (conj bb-addrs addr) 324 | ;; multiple successors, this must be a cjmp, so this is end of bb. 325 | (< 1 (count (:flow insn))) 326 | (conj bb-addrs addr) 327 | ;; single successor, but not fallthrough, so its a jmp, and this is end of bb. 328 | (not (= :fall-through (:type (first (:flow insn))))) 329 | (conj bb-addrs addr) 330 | ;; there is more than one relevant xref to this insn. 331 | ;; TODO: if addr == start-addr, then there should be none? 332 | ;; note: the current addr is *not* part of the basic block. its one past the end. 333 | (and 334 | (not= addr start-addr) 335 | (< 1 (count (filter reachable-addrs (map :src (get flows-by-dst addr)))))) 336 | bb-addrs 337 | ;; otherwise, keep scanning forward 338 | :else 339 | (recur (conj bb-addrs addr) 340 | (:address (first (:flow insn)))))))) 341 | ([insn-analysis start-addr] 342 | (let [reachable-addrs (find-reachable-addresses insn-analysis start-addr)] 343 | (read-basic-block insn-analysis start-addr (into #{} reachable-addrs))))) 344 | 345 | 346 | (defn thunk? 347 | [address] 348 | (and (map? address) 349 | (contains? address :deref))) 350 | 351 | 352 | (defn get-exports 353 | [pe] 354 | (map #(+ (:function-address %) 355 | (get-in pe [:nt-header :optional-header :ImageBase])) 356 | (remove :forwarded? (pe/get-exports pe)))) 357 | 358 | 359 | (defn get-entrypoint 360 | [pe] 361 | (+ 362 | (get-in pe [:nt-header :optional-header :ImageBase]) 363 | (get-in pe [:nt-header :optional-header :AddressOfEntryPoint]))) 364 | 365 | 366 | (defn get-insns 367 | "map a list of instruction addresses to the instruction instances" 368 | [{:keys [:insns-by-addr]} addrs] 369 | (for [addr addrs] 370 | (get insns-by-addr addr))) 371 | 372 | 373 | (defn find-function-targets 374 | " 375 | search for target addresses of calls from instructions reachable from the given address. 376 | 377 | example:: 378 | 379 | => (find-function-targets analysis 0x401000) 380 | #{0x40101B 0x401030 ...} 381 | " 382 | [insn-analysis fva] 383 | (let [insn-addrs (find-reachable-addresses insn-analysis fva) 384 | insns (get-insns insn-analysis insn-addrs) 385 | calls (filter :cref insns)] 386 | (filter some? 387 | (flatten 388 | (for [call calls] 389 | (for [cref (:cref call)] 390 | (let [address (:address cref)] 391 | (when (number? address) 392 | address)))))))) 393 | 394 | 395 | (defn find-functions 396 | " 397 | recursively search for called addresses from the given set of seed instruction addresses. 398 | 399 | example:: 400 | 401 | => (find-functions analysis (conj (get-exports ws) 402 | (get-entrypoint ws))) 403 | #{0x40101B 0x401030 ...} 404 | " 405 | [insn-analysis init-addrs] 406 | (loop [q (apply conj clojure.lang.PersistentQueue/EMPTY init-addrs) 407 | seen #{}] 408 | (if-let [addr (peek q)] 409 | (if (contains? seen addr) 410 | ;; if already processed, keep going 411 | (recur (pop q) seen) 412 | ;; otherwise, search for new functions 413 | (recur (apply conj (pop q) (find-function-targets insn-analysis addr)) 414 | (conj seen addr))) 415 | ;; when work is done, return set of seen addresses. 416 | seen))) 417 | 418 | (defn analyze-workspace 419 | [workspace] 420 | (if (some? (:analysis workspace)) 421 | workspace ;; don't recompute analysis 422 | (let [text-section (pe/get-section (:pe workspace) ".text") ;; TODO: map all executable sections... 423 | 424 | text-rva (get-in workspace [:pe :section-headers ".text" :VirtualAddress]) 425 | _ (log/info "text section at rva: " text-rva) 426 | 427 | text-addr (pe/rva->va (:pe workspace) text-rva) 428 | _ (log/info "text section at va: " text-addr) 429 | 430 | entry-addr (get-entrypoint (:pe workspace)) 431 | _ (log/info "entry va: " entry-addr) 432 | 433 | _ (log/info "disassembling...") 434 | raw-insns (disassemble-all (:dis workspace) text-section text-addr) 435 | 436 | _ (log/info "analyzing...") 437 | insn-analysis (analyze-instructions raw-insns)] 438 | (merge workspace {:analysis insn-analysis})))) 439 | 440 | 441 | (defn get-function-blocks 442 | " 443 | compute the basic blocks in the function that starts at the given address. 444 | 445 | example:: 446 | 447 | => (get-function-blocks ws 0x401000) 448 | {0x401000: [0x401000 0x401003 0x401005] 449 | 0x401008: [0x401008 0x401009] ...} 450 | 451 | Returns: 452 | map: from basic block start addr to vector of addrs of insns in basic block. 453 | " 454 | ([analysis start-addr reachable-addrs] 455 | (let [insns-by-addr (:insns-by-addr analysis) 456 | reachable-addrs (find-reachable-addresses analysis start-addr)] 457 | (loop [q (conj clojure.lang.PersistentQueue/EMPTY start-addr) 458 | basic-blocks {}] 459 | (if-let [addr (peek q)] 460 | (if (contains? basic-blocks addr) 461 | ;; if already processed, keep going 462 | (recur (pop q) basic-blocks) 463 | 464 | ;; else, read the basic block and update seen set. 465 | (let [q (pop q) 466 | basic-block (read-basic-block analysis addr reachable-addrs) 467 | last-insn-addr (last basic-block) 468 | last-insn (get insns-by-addr last-insn-addr) 469 | flow-addrs (filter reachable-addrs (map :address (:flow last-insn)))] 470 | (recur (apply conj q flow-addrs) 471 | (assoc basic-blocks addr basic-block)))) 472 | ;; when work is done, return set of seen addresses. 473 | basic-blocks)))) 474 | ([analysis start-addr] 475 | (let [reachable-addrs (find-reachable-addresses analysis start-addr)] 476 | (get-function-blocks analysis start-addr reachable-addrs)))) 477 | 478 | 479 | (defn get-block-flows 480 | " 481 | compute the flow references among the given basic blocks. 482 | 483 | Args: 484 | analysis: instruction analysis results 485 | blocks: map from block start address to sequence of instruction addresses 486 | 487 | Returns: 488 | sequence of maps with keys: 489 | - src: block starting address 490 | - dst: block starting address 491 | - type: flow type keyword 492 | " 493 | [analysis blocks] 494 | (filter some? 495 | (flatten (let [block-starts (into #{} (keys blocks))] 496 | (for [block (vals blocks)] 497 | (let [last-addr (last block) 498 | last-insn (get (:insns-by-addr analysis) last-addr) 499 | succs (filter block-starts (map :add))] 500 | (for [flow (:flow last-insn)] 501 | (when (contains? block-starts (:address flow)) 502 | {:src (first block) 503 | :type (:type flow) 504 | :dst (:address flow)})))))))) 505 | 506 | (defn analyze-function 507 | [ws va] 508 | (let [analysis (:analysis ws) 509 | blocks (get-function-blocks analysis va) 510 | flows (get-block-flows analysis blocks)] 511 | {:blocks blocks 512 | :flows flows 513 | :succs (group-by :src flows) 514 | :preds (group-by :dst flows)})) 515 | 516 | --------------------------------------------------------------------------------