├── .gitignore ├── .gitmodules ├── Dockerfile ├── LICENSE.md ├── Makefile ├── README.md ├── build_image.sh ├── build_src.sh ├── clear_image.sh ├── external └── Makefile.external ├── issue_template.md ├── lifter └── Makefile.lifter └── src ├── Makefile.src ├── MeanDiff ├── Alias.fs ├── Alias.fsi ├── App.config ├── CFG.fs ├── CFG.fsi ├── CmdOpt.fs ├── CmdOpt.fsi ├── DataFlow.fs ├── DataFlow.fsi ├── Exception.fs ├── Graph.fs ├── Graph.fsi ├── JSONParse.fs ├── JSONParse.fsi ├── Lift.fs ├── Lift.fsi ├── MeanDiff.fs ├── MeanDiff.fsproj ├── MultProc.fs ├── Report.fs ├── Report.fsi ├── SMTSolver.fs ├── StreamGen.fs ├── StreamGen.fsi ├── Symbolic.fs ├── Symbolic.fsi ├── Tree.fs ├── Tree.fsi ├── Type.fs ├── Type.fsi ├── UIR.fs ├── Utils.fs └── packages.config ├── ReleaseNotes.md └── build.fsx /.gitignore: -------------------------------------------------------------------------------- 1 | TAGS 2 | src/.fake 3 | build 4 | src/MeanDiff/AssemblyInfo.fs 5 | src/MeanDiff/obj 6 | src/packages 7 | /insn_x86 8 | /insn_x64 9 | /reports32 10 | /reports64 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lifter/LifterBAP"] 2 | path = lifter/LifterBAP 3 | url = git@github.com:SoftSec-KAIST/MeanDiff-LifterBAP.git 4 | [submodule "lifter/LifterBINSEC"] 5 | path = lifter/LifterBINSEC 6 | url = git@github.com:SoftSec-KAIST/MeanDiff-LifterBINSEC.git 7 | [submodule "lifter/LifterPyVEX"] 8 | path = lifter/LifterPyVEX 9 | url = git@github.com:SoftSec-KAIST/MeanDiff-LifterPyVEX.git 10 | [submodule "external/ExternalXED"] 11 | path = external/ExternalXED 12 | url = git@github.com:SoftSec-KAIST/MeanDiff-ExternalXED.git -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM build_base 2 | MAINTAINER Soomin Kim 3 | 4 | RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF 5 | RUN echo "deb http://download.mono-project.com/repo/ubuntu xenial main" | tee /etc/apt/sources.list.d/mono-official.list 6 | RUN apt-get update -y 7 | 8 | RUN apt install ca-certificates-mono -y 9 | RUN apt install mono-complete -y 10 | RUN apt install fsharp -y 11 | RUN apt install wget -y 12 | 13 | # RUN mkdir /compile 14 | # ADD ./src/ /compile/ 15 | 16 | # WORKDIR /compile 17 | # RUN mkdir /compile/nuget 18 | # RUN wget -O ./nuget/nuget.exe \ 19 | # https://dist.nuget.org/win-x86-commandline/v2.8.6/nuget.exe 20 | # RUN mono ./nuget/nuget.exe install FAKE -OutputDirectory packages \ 21 | # -ExcludeVersion 22 | 23 | # RUN make 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SoftSec Lab https://softsec.kaist.ac.kr/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILDDIR = build 2 | SRCDIR = src 3 | LIFTERDIR = lifter 4 | EXTERNALDIR = external 5 | 6 | all: meandiff 7 | 8 | $(BUILDDIR): 9 | mkdir -p $(BUILDDIR) 10 | 11 | init: 12 | git submodule init 13 | git submodule update 14 | 15 | lifters: $(BUILDDIR) 16 | cd $(LIFTERDIR) && $(MAKE) -f Makefile.lifter 17 | 18 | external: $(BUILDDIR) 19 | cd $(EXTERNALDIR) && $(MAKE) -f Makefile.external 20 | 21 | meandiff: 22 | cd $(SRCDIR) && $(MAKE) -f Makefile.src 23 | 24 | clean: 25 | rm -rf $(BUILDDIR) 26 | 27 | .PHONY: all init lifters external build 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MeanDiff 2 | 3 | If you want to see the details about the system, go to 4 | [here](https://softsec-kaist.github.io/MeanDiff/). 5 | 6 | ## Table of Contents 7 | 8 | * [Installation](#installation) 9 | * [Usage](#usage) 10 | * [Testing additional lifters](#testing-additional-lifters) 11 | * [UIR](#uir) 12 | * [Abstract Syntax](#abstract-syntax) 13 | * [Semantics](#semantics) 14 | * [Writing translator for UIR](#writing-translator-to-uir) 15 | * [Adding translator to MeanDiff](#adding-translator-to-meandiff) 16 | * [Citing MeanDiff](#citing-meandiff) 17 | * [License](#license) 18 | * [Acknowledgement](#acknowledgement) 19 | 20 | ## Installation 21 | 22 | As MeanDiff has several external dependencies due to lifters and external 23 | libraries, the whole build system is containerized with docker. 24 | 25 | All docker images (for each lifter, etc.) are based to the `BaseImage` (T.B.D 26 | Link), which used `ubuntu:16.10`. 27 | 28 | ### Building 29 | 30 | Start by building submodules. This could take some time as the docker images 31 | needs to be downloaded and built. 32 | 33 | make init 34 | make lifters 35 | make external 36 | 37 | Now, MeanDiff can be built either 38 | * A. Inside the docker container 39 | * B. In your native environment 40 | 41 | For option B., you can find dependencies in the respective `Dockerfile`s. 42 | 43 | The resulting binaries are found in the `build` directory. 44 | 45 | #### A. 46 | To build and setup docker environment: 47 | 48 | ./build_image.sh 49 | ./build_src.sh 50 | 51 | #### B. 52 | If you want to run MeanDiff outside docker, just type `make`. 53 | 54 | ## Usage 55 | 56 | T.B.D. 57 | 58 | To log into the docker container for MeanDiff, taged `build_meandiff`: 59 | 60 | docker run -v $(pwd):/src -ti build_meandiff:latest 61 | 62 | ## Testing additional lifters 63 | 64 | ### UIR 65 | 66 | UIR stands for `Unified Intermediate Representation`. UIR is used for unifying 67 | every BBIR into a single form. UIR is a simple, but Turing-complete language. It 68 | is also designed to be explicit and self-contained. 69 | 70 | #### Abstract Syntax 71 | 72 | ``` 73 | ::= BE | LE 74 | 75 | ::= NEG | NOT 76 | 77 | ::= ADD | SUB | UMUL | SMUL | UDIV | SDIV | UMOD | SMOD | SHL | USHR 78 | | SSHR | AND | OR | XOR | CONCAT 79 | 80 | ::= EQ | NEQ | ULT | SLT | ULE | SLE 81 | 82 | ::= LOW | HIGH | ZERO | SIGN 83 | 84 | ::= | | []: | 85 | | | 86 | | -> : | If | Undefined 87 | 88 | ::= Start | := 89 | | [] := | | If 90 | | End | Unrecognized 91 | 92 | ::= :: | [] 93 | 94 | ::= | | 95 | ``` 96 | 97 | #### Semantics 98 | 99 | Here, only non-trivial semantics of UIR are shown. 100 | 101 | Primitive types: ``, ``, ``, `` 102 | 103 | ``: 104 | - `[]:`: Load a value of size `` from ``. 105 | - ` -> :`: Enlarge or shorten `` of size `` by 106 | referencing ``. 107 | - `If `: If-Then-Else expression. `` and 108 | `` should have same type. 109 | 110 | ``: 111 | - `Start `: Indicate information aboutn an instruction 112 | and system. The target instruction is placed at `` with length 113 | ``, and has the endianness of ``. 114 | - `[] := `: Store `` into the memory pointed by ``. 115 | - `End `: Indicates the end of control-flow of IR statements. `` 116 | represents the address of next instruction. 117 | 118 | ### Writing translator for UIR 119 | 120 | There are some rules for a translator from your IR to our UIR. 121 | - Register names must be in lower cases 122 | - For each expression and statement, we have a simple type system. See 123 | `src/MeanDiff/Type.fs` 124 | - The first item in `` should be `Start` 125 | - `End` must be placed at the end of the instruction semantics. 126 | 127 | ### Adding translator to MeanDiff 128 | 129 | In order to add your translator to MeanDiff, you need to manually modify 130 | `src/MeanDiff/Report.fs` appropriately. 131 | 132 | ## Citing MeanDiff 133 | 134 | To cite our paper: 135 | 136 | ``` 137 | @INPROCEEDINGS{kim:ase2017, 138 | author = {Soomin Kim, Markus Faerevaag, Minkyu Jung, SeungIl Jung, DongYeop Oh, JongHyup Lee, and Sang Kil Cha}, 139 | title = {Testing Intermediate Representations for Binary Analysis}, 140 | booktitle = {Proceedings of the 32nd IEEE/ACM International Conference on Automated Software Engineering}, 141 | year = {2017}, 142 | pages = {353--364} 143 | } 144 | ``` 145 | 146 | ## License 147 | 148 | This project is licensed under the [MIT License](LICENSE.md). 149 | 150 | ## Acknowledgement 151 | 152 | The work was supported by Institute for Information & communications Technology Promotion (IITP) grant funded by the Korea government (MSIT). 153 | -------------------------------------------------------------------------------- /build_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo docker build -t build_meandiff . 4 | -------------------------------------------------------------------------------- /build_src.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo docker run -v $(pwd):/src build_meandiff:latest /bin/bash -c 'cd /src && make' 4 | 5 | # fix permissions 6 | sudo chown -R $(whoami):users build 7 | -------------------------------------------------------------------------------- /clear_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo docker rmi $(sudo docker images -qa -f "dangling=true") 4 | -------------------------------------------------------------------------------- /external/Makefile.external: -------------------------------------------------------------------------------- 1 | EXTERNALS := $(wildcard External*) 2 | 3 | all: $(EXTERNALS) 4 | 5 | $(EXTERNALS): 6 | cd $@ && ./build_image.sh 7 | cd $@ && ./build_src.sh 8 | cd $@ && cp build/$@ ../../build/$@ 9 | 10 | .PHONY: all $(EXTERNALS) 11 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | TODO 3 | 4 | **Reference:** 5 | Ref. Intel 64 and IA-32 Architecture Software Developer's Manual Vol. **TODO** 6 | 7 | **Affected instructions:** 8 | ``` 9 | 0xTODO 10 | ``` 11 | _NOTE:_ All combinations of prefixes are omitted. 12 | 13 | ## Reproduction guide 14 | **Instruction:** 15 | ``` 16 | TODO 17 | ``` 18 | 19 | **Input:** 20 | ``` 21 | TODO 22 | ``` 23 | 24 | **Observed output:** 25 | ``` 26 | TODO 27 | ``` 28 | 29 | **Expected output:** 30 | ``` 31 | TODO 32 | ``` 33 | 34 | ## System Info 35 | **OS:** 36 | ``` 37 | # uname -a 38 | TODO 39 | # cat /etc/lsb-release 40 | TODO 41 | ``` 42 | 43 | **TODO:** 44 | ``` 45 | TODO 46 | ``` 47 | -------------------------------------------------------------------------------- /lifter/Makefile.lifter: -------------------------------------------------------------------------------- 1 | LIFTERS := LifterPyVEX LifterBINSEC LifterBAP 2 | #LIFTERS := $(wildcard */.) 3 | 4 | all: $(LIFTERS) 5 | 6 | $(LIFTERS): 7 | cd $@ && ./build_image.sh 8 | cd $@ && ./build_src.sh 9 | cd $@ && cp -r build/$@* ../../build/ 10 | 11 | .PHONY: all $(LIFTERS) 12 | -------------------------------------------------------------------------------- /src/Makefile.src: -------------------------------------------------------------------------------- 1 | MONO = /usr/bin/mono 2 | 3 | SRC = MeanDiff/*.fs* 4 | BUILDDIR = build 5 | PKGDIR = packages 6 | 7 | TARGET = $(BUILDDIR)/Debug/MeanDiff.exe 8 | 9 | NUGET = $(PKGDIR)/nuget.exe 10 | FAKE = $(PKGDIR)/FAKE/tools/FAKE.exe 11 | 12 | all: $(PKGDIR) $(NUGET) $(FAKE) $(TARGET) 13 | 14 | $(TARGET): build.fsx $(SRC) 15 | $(MONO) $(FAKE) $< 16 | cp $(BUILDDIR)/Debug/* ../$(BUILDDIR)/ 17 | 18 | $(PKGDIR): 19 | mkdir -p $@ 20 | 21 | $(NUGET): 22 | wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -O $(NUGET) 23 | 24 | $(FAKE): 25 | $(MONO) $(NUGET) install FAKE -OutputDirectory packages \ 26 | -ExcludeVersion 27 | 28 | package: $(FAKE) build.fsx 29 | $(MONO) $(FAKE) build.fsx $@ 30 | 31 | clean: $(FAKE) build.fsx 32 | $(MONO) $(FAKE) build.fsx $@ 33 | 34 | .PHONY: all package clean 35 | -------------------------------------------------------------------------------- /src/MeanDiff/Alias.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.Alias 2 | 3 | open CmdOpt 4 | open UIR 5 | 6 | let mapReg32 = function 7 | | "al", 8us -> ("eax", 32us) 8 | | "ax", 16us -> ("eax", 32us) 9 | | "cl", 8us -> ("ecx", 32us) 10 | | "cx", 16us -> ("ecx", 32us) 11 | | "dl", 8us -> ("edx", 32us) 12 | | "dx", 16us -> ("edx", 32us) 13 | | "bl", 8us -> ("ebx", 32us) 14 | | "bx", 16us -> ("ebx", 32us) 15 | | "sp", 16us -> ("esp", 32us) 16 | | "bp", 16us -> ("ebp", 32us) 17 | | "sil", 8us -> ("esi", 32us) 18 | | "si", 16us -> ("esi", 32us) 19 | | "dil", 8us -> ("edi", 32us) 20 | | "di", 16us -> ("edi", 32us) 21 | | "mm0", 64us -> ("ymm0", 256us) 22 | | "mm1", 64us -> ("ymm1", 256us) 23 | | "mm2", 64us -> ("ymm2", 256us) 24 | | "mm3", 64us -> ("ymm3", 256us) 25 | | "mm4", 64us -> ("ymm4", 256us) 26 | | "mm5", 64us -> ("ymm5", 256us) 27 | | "mm6", 64us -> ("ymm6", 256us) 28 | | "mm7", 64us -> ("ymm7", 256us) 29 | | "xmm0", 128us -> ("ymm0", 256us) 30 | | "xmm1", 128us -> ("ymm1", 256us) 31 | | "xmm2", 128us -> ("ymm2", 256us) 32 | | "xmm3", 128us -> ("ymm3", 256us) 33 | | "xmm4", 128us -> ("ymm4", 256us) 34 | | "xmm5", 128us -> ("ymm5", 256us) 35 | | "xmm6", 128us -> ("ymm6", 256us) 36 | | "xmm7", 128us -> ("ymm7", 256us) 37 | | reg -> reg 38 | 39 | let mapReg64 = function 40 | | "al", 8us -> ("rax", 64us) 41 | | "ax", 16us -> ("rax", 64us) 42 | | "eax", 32us -> ("rax", 64us) 43 | | "cl", 8us -> ("rcx", 64us) 44 | | "cx", 16us -> ("rcx", 64us) 45 | | "ecx", 32us -> ("rcx", 64us) 46 | | "dl", 8us -> ("rdx", 64us) 47 | | "dx", 16us -> ("rdx", 64us) 48 | | "edx", 32us -> ("rdx", 64us) 49 | | "bl", 8us -> ("rbx", 64us) 50 | | "bx", 16us -> ("rbx", 64us) 51 | | "ebx", 32us -> ("rbx", 64us) 52 | | "sp", 16us -> ("rsp", 64us) 53 | | "esp", 32us -> ("rsp", 64us) 54 | | "bp", 16us -> ("rbp", 64us) 55 | | "ebp", 32us -> ("rbp", 64us) 56 | | "sil", 8us -> ("rsi", 64us) 57 | | "si", 16us -> ("rsi", 64us) 58 | | "esi", 32us -> ("rsi", 64us) 59 | | "dil", 8us -> ("rdi", 64us) 60 | | "di", 16us -> ("rdi", 64us) 61 | | "edi", 32us -> ("rdi", 64us) 62 | | "mm0", 64us -> ("ymm0", 256us) 63 | | "mm1", 64us -> ("ymm1", 256us) 64 | | "mm2", 64us -> ("ymm2", 256us) 65 | | "mm3", 64us -> ("ymm3", 256us) 66 | | "mm4", 64us -> ("ymm4", 256us) 67 | | "mm5", 64us -> ("ymm5", 256us) 68 | | "mm6", 64us -> ("ymm6", 256us) 69 | | "mm7", 64us -> ("ymm7", 256us) 70 | | "xmm0", 128us -> ("ymm0", 256us) 71 | | "xmm1", 128us -> ("ymm1", 256us) 72 | | "xmm2", 128us -> ("ymm2", 256us) 73 | | "xmm3", 128us -> ("ymm3", 256us) 74 | | "xmm4", 128us -> ("ymm4", 256us) 75 | | "xmm5", 128us -> ("ymm5", 256us) 76 | | "xmm6", 128us -> ("ymm6", 256us) 77 | | "xmm7", 128us -> ("ymm7", 256us) 78 | | reg -> reg 79 | 80 | let mkLow size var = 81 | Cast (LOW, size, var) 82 | 83 | let changeReg arch reg = 84 | let _, size = reg 85 | let mapReg = 86 | match arch with 87 | | X86 -> mapReg32 88 | | X64 -> mapReg64 89 | if reg = (reg |> mapReg) 90 | then 91 | Var reg 92 | else 93 | Var (reg |> mapReg) |> mkLow size 94 | 95 | let rec aliasExpr arch = function 96 | | Var (reg) -> 97 | reg |> changeReg arch 98 | | Load (addr, size) -> 99 | let addr = addr |> aliasExpr arch 100 | Load (addr |> aliasExpr arch, size) 101 | | UnOp (op, expr) -> 102 | let expr = expr |> aliasExpr arch 103 | UnOp (op, expr) 104 | | BinOp (op, expr1, expr2) -> 105 | let expr1 = expr1 |> aliasExpr arch 106 | let expr2 = expr2 |> aliasExpr arch 107 | BinOp (op, expr1, expr2) 108 | | RelOp (op, expr1, expr2) -> 109 | let expr1 = expr1 |> aliasExpr arch 110 | let expr2 = expr2 |> aliasExpr arch 111 | RelOp (op, expr1, expr2) 112 | | Cast (op, size, expr) -> 113 | let expr = expr |> aliasExpr arch 114 | Cast (op, size, expr) 115 | | Ite (cond, thenExpr, elseExpr) -> 116 | let cond = cond |> aliasExpr arch 117 | let thenExpr = thenExpr |> aliasExpr arch 118 | let elseExpr = elseExpr |> aliasExpr arch 119 | Ite (cond, thenExpr, elseExpr) 120 | | expr -> expr 121 | 122 | let embedExpr reg oldSize newSize expr = 123 | let newExpr = Cast (ZERO, newSize, expr) 124 | let embedding = BinOp (USHR, Var (reg), Num (oldSize |> uint64, newSize)) 125 | let embedding = BinOp (SHL, embedding, Num (oldSize |> uint64, newSize)) 126 | BinOp (OR, embedding, newExpr) 127 | 128 | let aliasMove arch reg expr = 129 | let mapReg = 130 | match arch with 131 | | X86 -> mapReg32 132 | | X64 -> mapReg64 133 | let newReg = reg |> mapReg 134 | if reg = newReg 135 | then 136 | Move (reg, expr) 137 | else 138 | let _, oldSize = reg 139 | let _, newSize = newReg 140 | let expr = expr |> embedExpr newReg oldSize newSize 141 | Move (newReg, expr) 142 | 143 | let aliasStmt arch = function 144 | | Move (reg, expr) -> 145 | let expr = expr |> aliasExpr arch 146 | aliasMove arch reg expr 147 | | Store (addr, expr) -> 148 | let addr = addr |> aliasExpr arch 149 | let expr = expr |> aliasExpr arch 150 | Store (addr, expr) 151 | | CJump (cond, thenLbl, elseLbl) -> 152 | let cond = cond |> aliasExpr arch 153 | CJump (cond, thenLbl, elseLbl) 154 | | End (addr) -> 155 | let addr = addr |> aliasExpr arch 156 | End (addr) 157 | | stmt -> stmt 158 | 159 | let alias arch = function 160 | | Stmts (stmtList) -> 161 | Stmts (stmtList |> List.map (aliasStmt arch)) 162 | | ast -> ast 163 | -------------------------------------------------------------------------------- /src/MeanDiff/Alias.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.Alias 2 | 3 | open CmdOpt 4 | open UIR 5 | 6 | val alias : ArchOption -> AST -> AST 7 | -------------------------------------------------------------------------------- /src/MeanDiff/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/MeanDiff/CFG.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.CFG 2 | 3 | open Graph 4 | open UIR 5 | 6 | let identifyLeader (prevJump, acc) = function 7 | | Start (_, _, _) 8 | | Label (_) as stmt -> false, ((stmt, true) :: acc) 9 | | CJump (_, _, _) 10 | | End (_) as stmt -> true, ((stmt, false) :: acc) 11 | | stmt -> 12 | if prevJump = true 13 | then 14 | false, ((stmt, true) :: acc) 15 | else 16 | false, ((stmt, false) :: acc) 17 | 18 | let cutting acc (stmt, isLeader) = 19 | match acc with 20 | | [] -> raise InvalidIRStructure 21 | | hd :: tl -> 22 | if isLeader = true 23 | then 24 | [] :: (stmt :: hd) :: tl 25 | else 26 | (stmt :: hd) :: tl 27 | 28 | let toBlocks stmts = 29 | let _, aux = stmts |> List.fold identifyLeader (false, []) 30 | aux |> List.fold cutting [[]] |> List.filter (fun x -> x <> []) 31 | 32 | let numbering list = 33 | list |> List.zip [0 .. (List.length list - 1)] 34 | 35 | let addStmt blockId graph (stmtId, stmt) = 36 | let symb = 37 | match stmt with 38 | | Start (_, _, _) -> Some "Label_Start" 39 | | Label (symb) -> Some symb 40 | | _ -> None 41 | graph |> addNode (blockId, stmtId) (symb, stmt) 42 | 43 | let addBlock graph (blockId, block) = 44 | block 45 | |> numbering 46 | |> List.fold (addStmt blockId) graph 47 | 48 | let findNodeIdByLabel label graph nodeId (symb, _) = 49 | match symb with 50 | | Some (symb) -> label = symb 51 | | None -> false 52 | 53 | let connectEdge graph nodeId (label, stmt) = 54 | match stmt with 55 | | CJump (_, thenLbl, elseLbl) -> 56 | let thenId = graph |> findNodeId (findNodeIdByLabel thenLbl) 57 | let elseId = graph |> findNodeId (findNodeIdByLabel elseLbl) 58 | graph 59 | |> connectNodes nodeId thenId 60 | |> connectNodes nodeId elseId 61 | | End (_) -> graph 62 | | _ -> 63 | let blockId, stmtId = nodeId 64 | graph |> connectNodes nodeId (blockId, stmtId + 1) 65 | 66 | let toGraph stmts = 67 | stmts 68 | |> toBlocks 69 | |> numbering 70 | |> List.fold addBlock empty 71 | |> graphMap connectEdge 72 | 73 | let toCfg ast = 74 | ast |> getStmts |> toGraph 75 | -------------------------------------------------------------------------------- /src/MeanDiff/CFG.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.CFG 2 | 3 | open Graph 4 | open UIR 5 | 6 | val toCfg : AST -> Graph 7 | -------------------------------------------------------------------------------- /src/MeanDiff/CmdOpt.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.CmdOpt 2 | 3 | type ArchOption = 4 | | X86 5 | | X64 6 | with 7 | member this.toString = 8 | match this with 9 | | X86 -> "x86" 10 | | X64 -> "x64" 11 | 12 | type StreamOption = 13 | | ALL 14 | | BLACK 15 | | WHITE 16 | | USE 17 | 18 | type CmdOpts = 19 | { 20 | archFlag : bool 21 | archOption : ArchOption 22 | helpFlag : bool 23 | streamFlag : bool 24 | streamOption : StreamOption 25 | streamFile : string 26 | } 27 | 28 | type Mode = 29 | | TopLevel 30 | | ArchParse 31 | | StreamParse 32 | | StreamFile 33 | 34 | type FoldState = 35 | { 36 | opts : CmdOpts 37 | mode : Mode 38 | } 39 | 40 | let parseTopLevel options = function 41 | | "--arch" -> 42 | if not options.archFlag 43 | then 44 | let options = { options with archFlag = true } 45 | { opts = options ; mode = ArchParse } 46 | else 47 | raise DuplicatedOption 48 | | "--help" -> 49 | if not options.helpFlag 50 | then 51 | let options = { options with helpFlag = true } 52 | { opts = options ; mode = TopLevel } 53 | else 54 | raise DuplicatedOption 55 | | "--stream" -> 56 | if not options.streamFlag 57 | then 58 | let options = { options with streamFlag = true } 59 | { opts = options ; mode = StreamParse } 60 | else 61 | raise DuplicatedOption 62 | | arg -> 63 | raise InvalidOption 64 | 65 | let parseArch options arg = 66 | let options = 67 | match arg with 68 | | "x86" -> { options with archOption = X86 } 69 | | "x64" -> { options with archOption = X64 } 70 | | _ -> raise InvalidOption 71 | { opts = options ; mode = TopLevel } 72 | 73 | let parseStream options = function 74 | | "All" -> 75 | { opts = { options with streamOption = ALL } ; mode = TopLevel } 76 | | "BlackList" -> 77 | { opts = { options with streamOption = BLACK } ; mode = StreamFile } 78 | | "WhiteList" -> 79 | { opts = { options with streamOption = WHITE } ; mode = StreamFile } 80 | | "Use" -> 81 | { opts = { options with streamOption = USE } ; mode = TopLevel } 82 | | arg -> raise InvalidOption 83 | 84 | let parseStreamFile options arg = 85 | { opts = { options with streamFile = arg } ; mode = TopLevel } 86 | 87 | let parse arg = function 88 | | { opts = options ; mode = TopLevel } -> 89 | parseTopLevel options arg 90 | | { opts = options ; mode = ArchParse } -> 91 | parseArch options arg 92 | | { opts = options ; mode = StreamParse } -> 93 | parseStream options arg 94 | | { opts = options ; mode = StreamFile } -> 95 | parseStreamFile options arg 96 | 97 | let help () = 98 | printfn "[Usage] MeanDiff.exe [Options...]" 99 | 100 | let parseCmdOpts args = 101 | if Array.length args < 1 102 | then 103 | help () 104 | exit 1 105 | 106 | let defaultOpts = { 107 | archFlag = false 108 | archOption = X86 109 | helpFlag = false 110 | streamFlag = false 111 | streamOption = ALL 112 | streamFile = "" 113 | } 114 | let initialState = { opts = defaultOpts ; mode = TopLevel } 115 | 116 | try 117 | let { opts = options ; mode = mode } = 118 | Array.fold (fun state arg -> parse arg state) initialState args 119 | if mode <> TopLevel then raise InsufficientOption 120 | if options.helpFlag 121 | then 122 | help () 123 | exit 1 124 | else 125 | options 126 | with 127 | | InsufficientOption -> 128 | eprintfn "Insufficient Option: %s" (String.concat " " args) |> help 129 | exit 1 130 | | InvalidOption -> 131 | eprintfn "Invalid Option: %s" (String.concat " " args) |> help 132 | exit 1 133 | | DuplicatedOption -> 134 | eprintfn "Duplicated Option: %s" (String.concat " " args) |> help 135 | exit 1 136 | -------------------------------------------------------------------------------- /src/MeanDiff/CmdOpt.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.CmdOpt 2 | 3 | type ArchOption = 4 | | X86 5 | | X64 6 | with 7 | member toString : string 8 | 9 | type StreamOption = 10 | | ALL 11 | | BLACK 12 | | WHITE 13 | | USE 14 | 15 | type CmdOpts = 16 | { 17 | // If this flag is true, arch option is already parsed 18 | archFlag : bool 19 | // Indicates target architecture 20 | archOption : ArchOption 21 | // If this flag is true, help msg should be printed 22 | helpFlag : bool 23 | // If this flag is true, stream-mode option is already parsed 24 | streamFlag : bool 25 | // Indicates stream generating mode 26 | streamOption : StreamOption 27 | // Indicates a list for stream generating 28 | streamFile : string 29 | } 30 | 31 | type Mode = 32 | | TopLevel 33 | | ArchParse 34 | | StreamParse 35 | | StreamFile 36 | 37 | val parseCmdOpts : string [] -> CmdOpts 38 | -------------------------------------------------------------------------------- /src/MeanDiff/DataFlow.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.DataFlow 2 | 3 | open Graph 4 | open Type 5 | open UIR 6 | 7 | let rec useAnalysisExpr expr useNodeSet = 8 | match expr with 9 | | Var (reg) -> 10 | useNodeSet 11 | |> Set.add reg 12 | | Load (addr, size) -> 13 | useNodeSet 14 | |> useAnalysisExpr addr 15 | | UnOp (_, expr) -> 16 | useNodeSet |> useAnalysisExpr expr 17 | | BinOp (_, expr1, expr2) -> 18 | useNodeSet 19 | |> useAnalysisExpr expr1 20 | |> useAnalysisExpr expr2 21 | | RelOp (_, expr1, expr2) -> 22 | useNodeSet 23 | |> useAnalysisExpr expr1 24 | |> useAnalysisExpr expr2 25 | | Cast (_, _, expr) -> 26 | useNodeSet |> useAnalysisExpr expr 27 | | Ite (cond, thenExpr, elseExpr) -> 28 | useNodeSet 29 | |> useAnalysisExpr cond 30 | |> useAnalysisExpr thenExpr 31 | |> useAnalysisExpr elseExpr 32 | | _ -> useNodeSet 33 | 34 | let getItem (map : Map<'a, Set<'b>>) key = 35 | try 36 | map.Item key 37 | with 38 | | :? System.Collections.Generic.KeyNotFoundException -> Set.empty 39 | 40 | let useAnalysisStmt _ useMap nodeId (_, stmt) = 41 | let keySet = 42 | match stmt with 43 | | Move (_, expr) -> 44 | Set.empty |> useAnalysisExpr expr 45 | | Store (addr, expr) -> 46 | Set.empty |> useAnalysisExpr addr |> useAnalysisExpr expr 47 | | CJump (cond, _, _) -> 48 | Set.empty |> useAnalysisExpr cond 49 | | End (addr) -> 50 | Set.empty |> useAnalysisExpr addr 51 | | _ -> Set.empty 52 | keySet 53 | |> Set.fold 54 | (fun map key -> map |> Map.add key (getItem map key |> Set.add nodeId)) 55 | useMap 56 | 57 | let defAnalysisStmt _ defMap nodeId (_, stmt) = 58 | match stmt with 59 | | Move (reg, _) -> 60 | defMap |> Map.add reg ((getItem defMap reg) |> Set.add nodeId) 61 | | _ -> defMap 62 | 63 | let usedefAnalysis analysisFunc graph = 64 | graph |> graphFold analysisFunc Map.empty 65 | 66 | let useAnalysis graph = usedefAnalysis useAnalysisStmt graph 67 | 68 | let defAnalysis graph = usedefAnalysis defAnalysisStmt graph 69 | 70 | let addDefData defData def locSet = 71 | if defData |> Map.exists (fun key _ -> key = def) 72 | then 73 | defData |> Map.add def (locSet |> Set.union (defData.Item def)) 74 | else 75 | defData |> Map.add def locSet 76 | 77 | let unionDefData defData1 defData2 = 78 | defData2 |> Map.fold addDefData defData1 79 | 80 | let collectPredDefs graph predIdSet = 81 | predIdSet 82 | |> Set.map (getNode graph) 83 | |> Set.fold unionDefData Map.empty 84 | 85 | let calcGenKill (defMap : Map>) nodeId = function 86 | | Move (reg, _) -> 87 | Some (reg, nodeId), Some (reg, (defMap.Item reg |> Set.remove nodeId)) 88 | | _ -> None, None 89 | 90 | let removeKill kill defData = 91 | match kill with 92 | | Some (def, locSet) -> 93 | if defData |> Map.exists (fun key _ -> key = def) 94 | then 95 | defData |> Map.add def (locSet |> Set.difference (defData.Item def)) 96 | else 97 | defData 98 | | None -> defData 99 | 100 | let addGen gen defData = 101 | match gen with 102 | | Some (def, loc) -> 103 | if defData |> Map.exists (fun key _ -> key = def) 104 | then 105 | defData |> Map.add def ((defData.Item def) |> Set.add loc) 106 | else 107 | defData |> Map.add def (Set.empty |> Set.add loc) 108 | | None -> defData 109 | 110 | let reachDefComputation defMap oldPair _ newPair nodeId (_, stmt) = 111 | let oldInGraph, oldOutGraph = oldPair 112 | let newInGraph, newOutGraph = newPair 113 | let newInData = 114 | nodeId |> getPredNodes oldOutGraph |> collectPredDefs oldOutGraph 115 | let newInGraph = newInGraph |> addNode nodeId newInData 116 | let gen, kill = calcGenKill defMap nodeId stmt 117 | let newOutData = 118 | nodeId |> getNode oldInGraph |> removeKill kill |> addGen gen 119 | let newOutGraph = newOutGraph |> addNode nodeId newOutData 120 | newInGraph, newOutGraph 121 | 122 | let rec dataFlowRec analysisFunc graph map initGraph oldInGraph oldOutGraph = 123 | let func = analysisFunc map (oldInGraph, oldOutGraph) 124 | let newInGraph, newOutGraph = 125 | graph |> graphFold func (initGraph, initGraph) 126 | if oldInGraph = newInGraph && oldOutGraph = newOutGraph 127 | then 128 | newInGraph, newOutGraph 129 | else 130 | dataFlowRec analysisFunc graph map initGraph newInGraph newOutGraph 131 | 132 | let dataFlowAnalysis analysisFunc initData graph map = 133 | let initGraph = graph |> copyGraph initData 134 | dataFlowRec analysisFunc graph map initGraph initGraph initGraph 135 | 136 | let reachingDefinition defMap graph = 137 | dataFlowAnalysis reachDefComputation Map.empty graph defMap 138 | 139 | let isDefined rdInGraph var inSet loc = 140 | if loc |> getNode rdInGraph |> Map.containsKey var 141 | then 142 | inSet 143 | else 144 | inSet |> Set.add var 145 | 146 | let testDefined rdInGraph inSet var locSet = 147 | locSet |> Set.fold (isDefined rdInGraph var) inSet 148 | 149 | let getInVariables useMap rdInGraph = 150 | useMap |> Map.fold (testDefined rdInGraph) Set.empty 151 | 152 | let findVariables nameSet varSet var _ = 153 | let name, _ = var 154 | if nameSet |> Set.contains name 155 | then 156 | varSet |> Set.add var 157 | else 158 | varSet 159 | 160 | let filterContext nameSet rdOutGraph cfg outSet nodeId (_, stmt) = 161 | match stmt with 162 | | End (_) -> 163 | let contextVariables = 164 | nodeId 165 | |> getNode rdOutGraph 166 | |> Map.fold (findVariables nameSet) Set.empty 167 | outSet |> Set.union contextVariables 168 | | _ -> outSet 169 | 170 | let getOutVariables nameSet cfg rdOutGraph = 171 | cfg |> graphFold (filterContext nameSet rdOutGraph) Set.empty 172 | 173 | let getInOutVariables nameSet cfg = 174 | let useMap = cfg |> useAnalysis 175 | let defMap = cfg |> defAnalysis 176 | let rdInGraph, rdOutGraph = cfg |> reachingDefinition defMap 177 | let inVars = getInVariables useMap rdInGraph 178 | let outVars = getOutVariables nameSet cfg rdOutGraph 179 | inVars, outVars 180 | -------------------------------------------------------------------------------- /src/MeanDiff/DataFlow.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.DataFlow 2 | 3 | open Graph 4 | open UIR 5 | 6 | val getInOutVariables : 7 | Set 8 | -> Graph<'a, 'b * Stmt> 9 | -> Set * Set 10 | -------------------------------------------------------------------------------- /src/MeanDiff/Exception.fs: -------------------------------------------------------------------------------- 1 | namespace MeanDiff 2 | 3 | exception NotImplemented 4 | 5 | exception FileNotFound // MeanDiff.fs 6 | 7 | exception InsufficientOption // CmdOpt.fs 8 | exception InvalidOption // CmdOpt.fs 9 | exception DuplicatedOption // CmdOpt.fs 10 | 11 | exception EmptyList // Graph.fs 12 | exception InvalidIRStructure // Graph.fs 13 | 14 | exception FieldNotFound // JSONParse.fs 15 | exception InvalidTypeField // JSONParse.fs 16 | exception InvalidSubTypeField // JSONParse.fs 17 | exception InvalidArgsLength // JSONParse.fs 18 | 19 | exception InvalidMessage // MultProc.fs 20 | 21 | exception IncomparableMemoryWarning // SMTSolver.fs 22 | exception MemoryNumberMismatch // SMTSolver.fs 23 | exception VariableNumberMismatch // SMTSolver.fs 24 | exception SolverUnknown // SMTSolver.fs 25 | 26 | exception AddressNotSet // Symbolic.fs 27 | exception ConditionNotSet // Symbolic.fs 28 | exception InvalidDestination // Symbolic.fs 29 | exception LoopDetected // Symbolic.fs 30 | exception TimeOut // Symbolic.fs 31 | 32 | exception InvalidCastSize // Type.fs 33 | exception OperandSizeMismatch // Type.fs 34 | exception VariableSizeMismatch // Type.fs 35 | 36 | exception OperandLengthUnmatched // Utils.fs 37 | -------------------------------------------------------------------------------- /src/MeanDiff/Graph.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.Graph 2 | 3 | open UIR 4 | 5 | type Graph<'a, 'b when 'a : comparison> = 6 | { 7 | nodes : Map<'a, 'b> 8 | preds : Map<'a, Set<'a>> 9 | succs : Map<'a, Set<'a>> 10 | } 11 | 12 | let empty = { nodes = Map.empty ; preds = Map.empty ; succs = Map.empty } 13 | 14 | let addNode nodeId nodeData graph = 15 | { graph with nodes = graph.nodes |> Map.add nodeId nodeData } 16 | 17 | let findNodeId findFunc graph = 18 | graph.nodes |> Map.findKey (findFunc graph) 19 | 20 | let getNode graph nodeId = graph.nodes.Item nodeId 21 | 22 | let getPredNodes graph nodeId = 23 | if graph.preds |> Map.containsKey nodeId 24 | then 25 | graph.preds.Item nodeId 26 | else 27 | Set.empty 28 | 29 | let getSuccNodes graph nodeId = 30 | if graph.succs |> Map.containsKey nodeId 31 | then 32 | graph.succs.Item nodeId 33 | else 34 | Set.empty 35 | 36 | let connectNodes srcId dstId graph = 37 | { graph with 38 | preds = graph.preds 39 | |> Map.add dstId (dstId |> getPredNodes graph |> Set.add srcId) 40 | succs = graph.succs 41 | |> Map.add srcId (srcId |> getSuccNodes graph |> Set.add dstId) 42 | } 43 | 44 | let graphMap mapFunc graph = graph.nodes |> Map.fold mapFunc graph 45 | 46 | let graphFold foldFunc acc graph = graph.nodes |> Map.fold (foldFunc graph) acc 47 | 48 | let copyGraphNode initData graph copied nodeId nodeData = 49 | copied |> addNode nodeId initData 50 | 51 | let copyGraphEdge graph copied nodeId nodeData = 52 | nodeId 53 | |> getSuccNodes graph 54 | |> Set.fold (fun graph dstId -> graph |> connectNodes nodeId dstId) copied 55 | 56 | let copyGraph initData graph = 57 | let copied = graph |> graphFold (copyGraphNode initData) empty 58 | graph |> graphFold copyGraphEdge copied 59 | -------------------------------------------------------------------------------- /src/MeanDiff/Graph.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.Graph 2 | 3 | open UIR 4 | 5 | type Graph<'a, 'b when 'a : comparison> = 6 | { 7 | nodes : Map<'a, 'b> 8 | preds : Map<'a, Set<'a>> 9 | succs : Map<'a, Set<'a>> 10 | } 11 | 12 | val empty : Graph<'a, 'b> 13 | 14 | val addNode : 'a -> 'b -> Graph<'a, 'b> -> Graph<'a, 'b> 15 | 16 | val findNodeId : (Graph<'a, 'b> -> 'a -> 'b -> bool) -> Graph<'a, 'b> -> 'a 17 | 18 | val getNode : Graph<'a, 'b> -> 'a -> 'b 19 | 20 | val getPredNodes : Graph<'a, 'b> -> 'a -> Set<'a> 21 | 22 | val getSuccNodes : Graph<'a, 'b> -> 'a -> Set<'a> 23 | 24 | val connectNodes : 'a -> 'a -> Graph<'a, 'b> -> Graph<'a, 'b> 25 | 26 | val graphMap : 27 | (Graph<'a, 'b> -> 'a -> 'b -> Graph<'a, 'b>) -> Graph<'a, 'b> -> Graph<'a, 'b> 28 | 29 | val graphFold : 30 | (Graph<'a, 'b> -> 'c -> 'a -> 'b -> 'c) -> 'c -> Graph<'a, 'b> -> 'c 31 | 32 | val copyGraph : 'c -> Graph<'a, 'b> -> Graph<'a, 'c> 33 | -------------------------------------------------------------------------------- /src/MeanDiff/JSONParse.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.JSONParse 2 | 3 | open FSharp.Data 4 | open System 5 | 6 | open UIR 7 | 8 | let getTypeField (json : JsonValue) = 9 | match (json.TryGetProperty "Type") with 10 | | Some x -> x.AsString() 11 | | None -> raise FieldNotFound 12 | 13 | let getSubTypeField (json : JsonValue) = 14 | match (json.TryGetProperty "SubType") with 15 | | Some x -> x.AsString() 16 | | None -> raise FieldNotFound 17 | 18 | let getArgsField (json : JsonValue) = 19 | match (json.TryGetProperty "Args") with 20 | | Some x -> x.AsArray() 21 | | None -> raise FieldNotFound 22 | 23 | let chkType s = function 24 | | x when x = s -> () 25 | | _ -> raise InvalidTypeField 26 | 27 | let chkLength s = function 28 | | x when s = Array.length x -> () 29 | | _ -> raise InvalidArgsLength 30 | 31 | let toValue (json : JsonValue) = json.AsString() |> Convert.ToUInt64 32 | 33 | let toSize (json : JsonValue) = json.AsString() |> Convert.ToUInt16 34 | 35 | let toSymbol (json : JsonValue) = json.AsString() 36 | 37 | let toEndianT json = 38 | let ty = getTypeField json 39 | let sty = getSubTypeField json 40 | chkType "EndianT" ty 41 | match sty with 42 | | "BE" -> BE 43 | | "LE" -> LE 44 | | _ -> raise InvalidSubTypeField 45 | 46 | let toUnOpT json = 47 | let ty = getTypeField json 48 | let sty = getSubTypeField json 49 | chkType "UnOpT" ty 50 | match sty with 51 | | "NEG" -> NEG 52 | | "NOT" -> NOT 53 | | _ -> raise InvalidSubTypeField 54 | 55 | let toBinOpT json = 56 | let ty = getTypeField json 57 | let sty = getSubTypeField json 58 | chkType "BinOpT" ty 59 | match sty with 60 | | "ADD" -> ADD 61 | | "SUB" -> SUB 62 | | "UMUL" -> UMUL 63 | | "SMUL" -> SMUL 64 | | "UDIV" -> UDIV 65 | | "SDIV" -> SDIV 66 | | "UMOD" -> UMOD 67 | | "SMOD" -> SMOD 68 | | "SHL" -> SHL 69 | | "USHR" -> USHR 70 | | "SSHR" -> SSHR 71 | | "AND" -> AND 72 | | "OR" -> OR 73 | | "XOR" -> XOR 74 | | "CONCAT" -> CONCAT 75 | | _ -> raise InvalidSubTypeField 76 | 77 | let toRelOpT json = 78 | let ty = getTypeField json 79 | let sty = getSubTypeField json 80 | chkType "RelOpT" ty 81 | match sty with 82 | | "EQ" -> EQ 83 | | "NEQ" -> NEQ 84 | | "ULT" -> ULT 85 | | "SLT" -> SLT 86 | | "ULE" -> ULE 87 | | "SLE" -> SLE 88 | | _ -> raise InvalidSubTypeField 89 | 90 | let toCastOpT json = 91 | let ty = getTypeField json 92 | let sty = getSubTypeField json 93 | chkType "CastOpT" ty 94 | match sty with 95 | | "LOW" -> LOW 96 | | "HIGH" -> HIGH 97 | | "ZERO" -> ZERO 98 | | "SIGN" -> SIGN 99 | | _ -> raise InvalidSubTypeField 100 | 101 | let rec toExpr json = 102 | let ty = getTypeField json 103 | let sty = getSubTypeField json 104 | chkType "Expr" ty 105 | match sty with 106 | | "Num" -> 107 | let args = getArgsField json 108 | chkLength 2 args 109 | (toValue args.[0], toSize args.[1]) |> Num 110 | | "Var" -> 111 | let args = getArgsField json 112 | chkLength 2 args 113 | (toSymbol args.[0], toSize args.[1]) |> Var 114 | | "Load" -> 115 | let args = getArgsField json 116 | chkLength 2 args 117 | (toExpr args.[0], toSize args.[1]) |> Load 118 | | "UnOp" -> 119 | let args = getArgsField json 120 | chkLength 2 args 121 | (toUnOpT args.[0], toExpr args.[1]) |> UnOp 122 | | "BinOp" -> 123 | let args = getArgsField json 124 | chkLength 3 args 125 | (toBinOpT args.[0], toExpr args.[1], toExpr args.[2]) |> BinOp 126 | | "RelOp" -> 127 | let args = getArgsField json 128 | chkLength 3 args 129 | (toRelOpT args.[0], toExpr args.[1], toExpr args.[2]) |> RelOp 130 | | "Cast" -> 131 | let args = getArgsField json 132 | chkLength 3 args 133 | (toCastOpT args.[0], toSize args.[1], toExpr args.[2]) |> Cast 134 | | "Ite" -> 135 | let args = getArgsField json 136 | chkLength 3 args 137 | (toExpr args.[0], toExpr args.[1], toExpr args.[2]) |> Ite 138 | | "Undefined" -> Undefined 139 | | _ -> raise InvalidSubTypeField 140 | 141 | let toStmt json = 142 | let ty = getTypeField json 143 | let sty = getSubTypeField json 144 | chkType "Stmt" ty 145 | match sty with 146 | | "Start" -> 147 | let args = getArgsField json 148 | chkLength 3 args 149 | (toValue args.[0], toSize args.[1], toEndianT args.[2]) |> Start 150 | | "Move" -> 151 | let args = getArgsField json 152 | chkLength 3 args 153 | ((toSymbol args.[0], toSize args.[1]), toExpr args.[2]) |> Move 154 | | "Store" -> 155 | let args = getArgsField json 156 | chkLength 2 args 157 | (toExpr args.[0], toExpr args.[1]) |> Store 158 | | "Label" -> 159 | let args = getArgsField json 160 | chkLength 1 args 161 | toSymbol args.[0] |> Label 162 | | "CJump" -> 163 | let args = getArgsField json 164 | chkLength 3 args 165 | (toExpr args.[0], toSymbol args.[1], toSymbol args.[2]) |> CJump 166 | | "End" -> 167 | let args = getArgsField json 168 | chkLength 1 args 169 | toExpr args.[0] |> End 170 | | "Unrecognized" -> Unrecognized 171 | | _ -> raise InvalidSubTypeField 172 | 173 | let toAST s = 174 | let json = JsonValue.Parse s 175 | let ty = getTypeField json 176 | let sty = getSubTypeField json 177 | chkType "AST" ty 178 | match sty with 179 | | "Stmts" -> 180 | let args = getArgsField json 181 | args |> List.ofArray |> List.map toStmt |> Stmts 182 | | "Uninterpretable" -> Uninterpretable 183 | | "Incapable" -> Incapable 184 | | _ -> raise InvalidSubTypeField 185 | -------------------------------------------------------------------------------- /src/MeanDiff/JSONParse.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.JSONParse 2 | 3 | val translate : string -> AST 4 | -------------------------------------------------------------------------------- /src/MeanDiff/Lift.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.Lift 2 | 3 | open CmdOpt 4 | open Utils 5 | 6 | let lift (arch : ArchOption) insn lifter = 7 | let prog = sprintf "build/Lifter%s" lifter 8 | let arg = sprintf "%s %s" arch.toString insn 9 | procStdOutStr [ prog ; arg ] 10 | 11 | let loadVar lifter = 12 | let file = sprintf "build/Lifter%s" lifter 13 | readLinesToSet file 14 | -------------------------------------------------------------------------------- /src/MeanDiff/Lift.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.Lift 2 | 3 | open CmdOpt 4 | 5 | val lift : ArchOption -> string -> string -> string 6 | 7 | val loadVar : string -> Set 8 | -------------------------------------------------------------------------------- /src/MeanDiff/MeanDiff.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.MeanDiff 2 | 3 | open System.IO 4 | 5 | open CmdOpt 6 | open MultProc 7 | open StreamGen 8 | open Report 9 | 10 | [] 11 | let main argv = 12 | let option = parseCmdOpts argv 13 | try 14 | match option.streamOption with 15 | | BLACK 16 | | WHITE -> 17 | if not (File.Exists option.streamFile) then raise FileNotFound 18 | | _ -> () 19 | with 20 | | FileNotFound -> 21 | eprintfn "File does not exist: %s" option.streamFile 22 | exit 1 23 | let agent = streamGen option |> createAgent 24 | [0 .. 99] 25 | |> List.map (fun _ -> worker option agent) 26 | |> Async.Parallel 27 | |> Async.RunSynchronously 28 | |> ignore 29 | 0 30 | -------------------------------------------------------------------------------- /src/MeanDiff/MeanDiff.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 346faf23-b624-4861-ae72-0efb43ad4b68 9 | Exe 10 | MeanDiff 11 | MeanDiff 12 | v4.5 13 | 4.4.0.0 14 | true 15 | MeanDiff 16 | 17 | 18 | true 19 | full 20 | false 21 | true 22 | ..\build\Debug\ 23 | DEBUG;TRACE 24 | 3 25 | 26 | 27 | 28 | pdbonly 29 | true 30 | true 31 | ..\build\Release\ 32 | TRACE 33 | 3 34 | 35 | 36 | 37 | 11 38 | 39 | 40 | x64 41 | 42 | 43 | x86 44 | 45 | 46 | 47 | 48 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 49 | 50 | 51 | 52 | 53 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | ..\packages\FSharp.Core.4.0.0.1\lib\net40\FSharp.Core.dll 94 | True 95 | 96 | 97 | 98 | ..\packages\FSharp.Data.2.3.2\lib\net40\FSharp.Data.dll 99 | True 100 | 101 | 102 | ..\packages\z3x64win.4.5.0.1\lib\Microsoft.Z3.dll 103 | True 104 | 105 | 106 | 107 | 108 | 109 | 110 | 117 | 118 | -------------------------------------------------------------------------------- /src/MeanDiff/MultProc.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.MultProc 2 | 3 | open Report 4 | 5 | type Msg = 6 | | BasicResponse 7 | | InsnResponse of string 8 | | EndResponse 9 | 10 | type ProcessMessage = 11 | | PM of Msg * AsyncReplyChannel 12 | 13 | type Agent = MailboxProcessor 14 | 15 | let createAgent insnList = 16 | MailboxProcessor.Start(fun inbox -> 17 | let rec loop cnt insnList = 18 | async { 19 | let! PM(_, replyChannel) = inbox.Receive() 20 | match insnList with 21 | | [] -> 22 | replyChannel.Reply(PM(EndResponse, replyChannel)) 23 | return! (loop cnt insnList) 24 | | hd :: tl -> 25 | replyChannel.Reply(PM(InsnResponse hd, replyChannel)) 26 | if (cnt + 1) % 1000 = 0 27 | then 28 | printfn "%d instructions have been tested" (cnt + 1) 29 | return! (loop (cnt + 1) tl) 30 | } 31 | loop 0 insnList) 32 | 33 | let rec worker option (agent : Agent) = 34 | async { 35 | let msg = 36 | match (agent.PostAndReply(fun replyChannel -> PM(BasicResponse, replyChannel))) with 37 | | PM (x, _) -> x 38 | match msg with 39 | | InsnResponse (insn) -> 40 | do! reporting option insn 41 | return! (worker option agent) 42 | | EndResponse -> () 43 | | _ -> raise InvalidMessage 44 | } 45 | -------------------------------------------------------------------------------- /src/MeanDiff/Report.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.Report 2 | 3 | open Microsoft.Z3 4 | 5 | open Alias 6 | open CFG 7 | open CmdOpt 8 | open DataFlow 9 | open JSONParse 10 | open Lift 11 | open SMTSolver 12 | open Symbolic 13 | open Tree 14 | open Type 15 | open UIR 16 | open Utils 17 | 18 | type Info = Set * SummaryInfo 19 | 20 | type Report = 21 | { 22 | insn : string 23 | arch : ArchOption 24 | astBAP : AST 25 | astPyVEX : AST 26 | astBINSEC : AST 27 | varBAP : Set 28 | varPyVEX : Set 29 | varBINSEC : Set 30 | infoBAP : Info 31 | infoPyVEX : Info 32 | infoBINSEC : Info 33 | undefSet : Set 34 | resultBAPPYVEX : TestingResult 35 | resultBAPBINSEC : TestingResult 36 | resultPYVEXBINSEC : TestingResult 37 | } 38 | 39 | let emptyReport = { 40 | insn = "" 41 | arch = X86 42 | astBAP = Incapable 43 | astPyVEX = Incapable 44 | astBINSEC = Incapable 45 | varBAP = Set.empty 46 | varPyVEX = Set.empty 47 | varBINSEC = Set.empty 48 | infoBAP = Set.empty, (Map.empty, Map.empty, Map.empty) 49 | infoPyVEX = Set.empty, (Map.empty, Map.empty, Map.empty) 50 | infoBINSEC = Set.empty, (Map.empty, Map.empty, Map.empty) 51 | undefSet = Set.empty 52 | resultBAPPYVEX = UNCOMPARABLE 53 | resultBAPBINSEC = UNCOMPARABLE 54 | resultPYVEXBINSEC = UNCOMPARABLE 55 | } 56 | 57 | let setInsnToReport insn report = 58 | { report with insn = insn } 59 | 60 | let setArchToReport arch report = 61 | { report with arch = arch } 62 | 63 | let translate arch json = 64 | let ast = json |> toAST 65 | ast |> typeCheck |> ignore 66 | ast |> alias arch 67 | 68 | let setAstsToReport report = 69 | match report.arch with 70 | | X86 -> 71 | { report with 72 | astBAP = 73 | "BAP" |> lift report.arch report.insn |> translate report.arch 74 | astPyVEX = 75 | "PyVEX" |> lift report.arch report.insn |> translate report.arch 76 | astBINSEC = 77 | "BINSEC" |> lift report.arch report.insn |> translate report.arch } 78 | | X64 -> 79 | { report with 80 | astBAP = 81 | "BAP" |> lift report.arch report.insn |> translate report.arch 82 | astPyVEX = 83 | "PyVEX" |> lift report.arch report.insn |> translate report.arch } 84 | 85 | let setVarsToReport report = 86 | match report.arch with 87 | | X86 -> 88 | { report with 89 | varBAP = "BAP" |> loadVar 90 | varPyVEX = "PyVEX" |> loadVar 91 | varBINSEC = "BINSEC" |> loadVar } 92 | | X64 -> 93 | { report with 94 | varBAP = "BAP" |> loadVar 95 | varPyVEX = "PyVEX" |> loadVar } 96 | 97 | let summarize vars ast = 98 | match ast with 99 | | Stmts (_) -> 100 | let cfg = ast |> toCfg 101 | let inVars, outVars = cfg |> getInOutVariables vars 102 | let summaryInfo, undefSet = cfg |> symbolicExecution inVars outVars 103 | Some (inVars, summaryInfo, undefSet) 104 | | _ -> 105 | None 106 | 107 | let setSummaryInfoToReport report = 108 | match report.arch with 109 | | X86 -> 110 | let inVarsBAP, summaryInfoBAP, undefBAP = 111 | match report.astBAP |> summarize report.varBAP with 112 | | Some (inVars, summaryInfo, undefSet) -> inVars, summaryInfo, undefSet 113 | | None -> Set.empty, (Map.empty, Map.empty, Map.empty), Set.empty 114 | let inVarsPyVEX, summaryInfoPyVEX, undefPyVEX = 115 | match report.astPyVEX |> summarize report.varPyVEX with 116 | | Some (inVars, summaryInfo, undefSet) -> inVars, summaryInfo, undefSet 117 | | None -> Set.empty, (Map.empty, Map.empty, Map.empty), Set.empty 118 | let inVarsBINSEC, summaryInfoBINSEC, undefBINSEC = 119 | match report.astBINSEC |> summarize report.varBINSEC with 120 | | Some (inVars, summaryInfo, undefSet) -> inVars, summaryInfo, undefSet 121 | | None -> Set.empty, (Map.empty, Map.empty, Map.empty), Set.empty 122 | let undefSet = 123 | seq [ undefBAP ; undefPyVEX ; undefBINSEC ] |> Set.unionMany 124 | { report with 125 | infoBAP = inVarsBAP, summaryInfoBAP 126 | infoPyVEX = inVarsPyVEX, summaryInfoPyVEX 127 | infoBINSEC = inVarsBINSEC, summaryInfoBINSEC 128 | undefSet = undefSet } 129 | | X64 -> 130 | let inVarsBAP, summaryInfoBAP, undefBAP = 131 | match report.astBAP |> summarize report.varBAP with 132 | | Some (inVars, summaryInfo, undefSet) -> inVars, summaryInfo, undefSet 133 | | None -> Set.empty, (Map.empty, Map.empty, Map.empty), Set.empty 134 | let inVarsPyVEX, summaryInfoPyVEX, undefPyVEX = 135 | match report.astPyVEX |> summarize report.varPyVEX with 136 | | Some (inVars, summaryInfo, undefSet) -> inVars, summaryInfo, undefSet 137 | | None -> Set.empty, (Map.empty, Map.empty, Map.empty), Set.empty 138 | let undefSet = 139 | seq [ undefBAP ; undefPyVEX ] |> Set.unionMany 140 | { report with 141 | infoBAP = inVarsBAP, summaryInfoBAP 142 | infoPyVEX = inVarsPyVEX, summaryInfoPyVEX 143 | undefSet = undefSet } 144 | 145 | let setSolverToReport report = 146 | match report.arch with 147 | | X86 -> 148 | let resultBAPPYVEX = 149 | match report.astBAP, report.astPyVEX with 150 | | Stmts (_), Stmts (_) -> 151 | differentialTesting report.undefSet report.infoBAP report.infoPyVEX 152 | | _ -> 153 | UNCOMPARABLE 154 | let resultBAPBINSEC = 155 | match report.astBAP, report.astBINSEC with 156 | | Stmts (_), Stmts (_) -> 157 | differentialTesting report.undefSet report.infoBAP report.infoBINSEC 158 | | _ -> 159 | UNCOMPARABLE 160 | let resultPYVEXBINSEC = 161 | match report.astPyVEX, report.astBINSEC with 162 | | Stmts (_), Stmts (_) -> 163 | differentialTesting report.undefSet report.infoPyVEX report.infoBINSEC 164 | | _ -> 165 | UNCOMPARABLE 166 | { report with 167 | resultBAPPYVEX = resultBAPPYVEX 168 | resultBAPBINSEC = resultBAPBINSEC 169 | resultPYVEXBINSEC = resultPYVEXBINSEC } 170 | | X64 -> 171 | let resultBAPPYVEX = 172 | match report.astBAP, report.astPyVEX with 173 | | Stmts (_), Stmts (_) -> 174 | differentialTesting report.undefSet report.infoBAP report.infoPyVEX 175 | | _ -> 176 | UNCOMPARABLE 177 | { report with 178 | resultBAPPYVEX = resultBAPPYVEX } 179 | 180 | let saveReport report = 181 | match report.arch with 182 | | X86 -> 183 | let reportStr = "" 184 | let reportStr = reportStr + "======== Report ========\n" 185 | let reportStr = 186 | reportStr + (sprintf "Architecture : %s\n" (report.arch.toString)) 187 | let reportStr = 188 | reportStr + (sprintf "Instruction : %s\n" report.insn) 189 | let reportStr = 190 | reportStr + (sprintf "Result between BAP and PYVEX:\n%A\n" report.resultBAPPYVEX) 191 | let reportStr = 192 | reportStr + (sprintf "Result between BAP and BINSEC:\n%A\n" report.resultBAPBINSEC) 193 | let reportStr = 194 | reportStr + (sprintf "Result between PYVEX and BINSEC:\n%A\n" report.resultPYVEXBINSEC) 195 | let results = [ report.resultBAPPYVEX ; report.resultBAPBINSEC ; report.resultPYVEXBINSEC ] 196 | let path = 197 | if results |> List.exists (function INEQUIV (_) -> true | _ -> false) 198 | then 199 | sprintf "reports32/inequiv/%s" report.insn 200 | else 201 | if results |> List.forall (fun x -> x = EQUIV) 202 | then 203 | sprintf "reports32/allEquiv/%s" report.insn 204 | else 205 | if results |> List.forall (fun x -> x = UNCOMPARABLE) 206 | then 207 | sprintf "reports32/allUncomp/%s" report.insn 208 | else 209 | sprintf "reports32/otherCase/%s" report.insn 210 | writeToFile path reportStr 211 | | X64 -> 212 | let reportStr = "" 213 | let reportStr = reportStr + "======== Report ========\n" 214 | let reportStr = 215 | reportStr + (sprintf "Architecture : %s\n" (report.arch.toString)) 216 | let reportStr = 217 | reportStr + (sprintf "Instruction : %s\n" report.insn) 218 | let reportStr = 219 | reportStr + (sprintf "Result between BAP and PYVEX:\n%A\n" report.resultBAPPYVEX) 220 | let path = 221 | match report.resultBAPPYVEX with 222 | | EQUIV -> 223 | sprintf "reports64/equiv/%s" report.insn 224 | | INEQUIV (_) -> 225 | sprintf "reports64/inequiv/%s" report.insn 226 | | UNCOMPARABLE -> 227 | sprintf "reports64/uncomparable/%s" report.insn 228 | writeToFile path reportStr 229 | 230 | let reporting option insn = 231 | async { 232 | try 233 | emptyReport 234 | |> setInsnToReport insn 235 | |> setArchToReport option.archOption 236 | |> setVarsToReport 237 | |> setAstsToReport 238 | |> setSummaryInfoToReport 239 | |> setSolverToReport 240 | |> saveReport 241 | with 242 | | IncomparableMemoryWarning -> 243 | let str = "Error Occured" 244 | let path = 245 | match option.archOption with 246 | | X86 -> sprintf "reports32/memWarn/%s" insn 247 | | X64 -> sprintf "reports64/memWarn/%s" insn 248 | writeToFile path str 249 | | MemoryNumberMismatch -> 250 | let str = "Error Occured" 251 | let path = 252 | match option.archOption with 253 | | X86 -> sprintf "reports32/memNumErr/%s" insn 254 | | X64 -> sprintf "reports64/memNumErr/%s" insn 255 | writeToFile path str 256 | | VariableNumberMismatch -> 257 | let str = "Error Occured" 258 | let path = 259 | match option.archOption with 260 | | X86 -> sprintf "reports32/varNumErr/%s" insn 261 | | X64 -> sprintf "reports64/varNumErr/%s" insn 262 | writeToFile path str 263 | | TimeOut -> 264 | let str = "Error Occured" 265 | let path = 266 | match option.archOption with 267 | | X86 -> sprintf "reports32/timeOutErr/%s" insn 268 | | X64 -> sprintf "reports64/timeOutErr/%s" insn 269 | writeToFile path str 270 | | _ -> 271 | let str = "Error Occured" 272 | let path = 273 | match option.archOption with 274 | | X86 -> sprintf "reports32/otherErr/%s" insn 275 | | X64 -> sprintf "reports64/otherErr/%s" insn 276 | writeToFile path str 277 | } 278 | -------------------------------------------------------------------------------- /src/MeanDiff/Report.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.Report 2 | 3 | open CmdOpt 4 | 5 | val reporting : CmdOpts -> string -> Async 6 | -------------------------------------------------------------------------------- /src/MeanDiff/SMTSolver.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.SMTSolver 2 | 3 | open Microsoft.Z3 4 | 5 | open Tree 6 | open UIR 7 | 8 | type TestingResult = 9 | | EQUIV 10 | | INEQUIV of Set 11 | | UNCOMPARABLE 12 | 13 | type Env = Map 14 | 15 | let filterMemVars ((name : Symbol), _) _ = 16 | name.StartsWith "mem" 17 | 18 | let getNumMemVars summary = 19 | let filtered = summary |> Map.filter filterMemVars 20 | filtered.Count 21 | 22 | let filterVar keySet (key : Reg) _ = 23 | let name, _ = key 24 | (name.StartsWith "mem") || (keySet |> Set.contains key) 25 | 26 | let regToBV (ctx : Context) ((name, size) : Reg) = 27 | ctx.MkBVConst(name, (size |> uint32)) 28 | 29 | let calcUnOpBV (ctx : Context) bv = function 30 | | NEG -> ctx.MkBVNeg(bv) 31 | | NOT -> ctx.MkBVNot(bv) 32 | 33 | let calcBinOpBV (ctx : Context) bv1 bv2 = function 34 | | ADD -> ctx.MkBVAdd(bv1, bv2) 35 | | SUB -> ctx.MkBVSub(bv1, bv2) 36 | | UMUL -> 37 | let bv1 = ctx.MkZeroExt(1u, bv1) 38 | let bv2 = ctx.MkZeroExt(1u, bv2) 39 | let bv = ctx.MkBVMul(bv1, bv2) 40 | ctx.MkExtract(bv.SortSize - 2u, 0u, bv) 41 | | SMUL -> ctx.MkBVMul(bv1, bv2) 42 | | UDIV -> ctx.MkBVUDiv(bv1, bv2) 43 | | SDIV -> ctx.MkBVSDiv(bv1, bv2) 44 | | UMOD -> ctx.MkBVURem(bv1, bv2) 45 | | SMOD -> ctx.MkBVSRem(bv1, bv2) 46 | | SHL -> 47 | let bv2 = ctx.MkZeroExt(bv1.SortSize - bv2.SortSize, bv2) 48 | ctx.MkBVSHL(bv1, bv2) 49 | | USHR -> 50 | let bv2 = ctx.MkZeroExt(bv1.SortSize - bv2.SortSize, bv2) 51 | ctx.MkBVLSHR(bv1, bv2) 52 | | SSHR -> 53 | let bv2 = ctx.MkZeroExt(bv1.SortSize - bv2.SortSize, bv2) 54 | ctx.MkBVASHR(bv1, bv2) 55 | | AND -> ctx.MkBVAND(bv1, bv2) 56 | | OR -> ctx.MkBVOR(bv1, bv2) 57 | | XOR -> ctx.MkBVXOR(bv1, bv2) 58 | | CONCAT -> ctx.MkConcat(bv1, bv2) 59 | 60 | let calcRelOpBV (ctx : Context) bv1 bv2 op = 61 | let tBv = ctx.MkBV(1, 1u) 62 | let fBv = ctx.MkBV(0, 1u) 63 | match op with 64 | | EQ -> ctx.MkITE(ctx.MkEq(bv1, bv2), tBv, fBv) :?> BitVecExpr 65 | | NEQ -> ctx.MkITE(ctx.MkNot(ctx.MkEq(bv1, bv2)), tBv, fBv) :?> BitVecExpr 66 | | ULT -> ctx.MkITE(ctx.MkBVULT(bv1, bv2), tBv, fBv) :?> BitVecExpr 67 | | SLT -> ctx.MkITE(ctx.MkBVSLT(bv1, bv2), tBv, fBv) :?> BitVecExpr 68 | | ULE -> ctx.MkITE(ctx.MkBVULE(bv1, bv2), tBv, fBv) :?> BitVecExpr 69 | | SLE -> ctx.MkITE(ctx.MkBVSLE(bv1, bv2), tBv, fBv) :?> BitVecExpr 70 | 71 | let calcCastOpBV (ctx : Context) bv size = function 72 | | LOW -> ctx.MkExtract(size - 1u, 0u, bv) 73 | | HIGH -> ctx.MkExtract(bv.SortSize - 1u, bv.SortSize - size, bv) 74 | | SIGN -> ctx.MkSignExt(size - bv.SortSize, bv) 75 | | ZERO -> ctx.MkZeroExt(size - bv.SortSize, bv) 76 | 77 | let rec exprToBV (oldEnv : Env) (ctx : Context) (env : Env) = function 78 | | Num (value, size) -> 79 | ctx.MkBV(value, (size |> uint32)) :> BitVecExpr 80 | | Var (reg) -> 81 | oldEnv.Item reg 82 | | UnOp (op, expr) -> 83 | let bv = expr |> exprToBV oldEnv ctx env 84 | op |> calcUnOpBV ctx bv 85 | | BinOp (op, expr1, expr2) -> 86 | let bv1 = expr1 |> exprToBV oldEnv ctx env 87 | let bv2 = expr2 |> exprToBV oldEnv ctx env 88 | op |> calcBinOpBV ctx bv1 bv2 89 | | RelOp (op, expr1, expr2) -> 90 | let bv1 = expr1 |> exprToBV oldEnv ctx env 91 | let bv2 = expr2 |> exprToBV oldEnv ctx env 92 | op |> calcRelOpBV ctx bv1 bv2 93 | | Ite (cond, thenExpr, elseExpr) -> 94 | let condBv = cond |> exprToBV oldEnv ctx env 95 | let condBv = ctx.MkEq(condBv, ctx.MkBV(1, 1u)) 96 | let thenBv = thenExpr |> exprToBV oldEnv ctx env 97 | let elseBv = elseExpr |> exprToBV oldEnv ctx env 98 | ctx.MkITE(condBv, thenBv, elseBv) :?> BitVecExpr 99 | | Cast (op, size, expr) -> 100 | let bv = expr |> exprToBV oldEnv ctx env 101 | op |> calcCastOpBV ctx bv (size |> uint32) 102 | | expr -> raise NotImplemented 103 | 104 | let addVarToEnv ctx env reg = 105 | env |> Map.add reg (reg |> regToBV ctx) 106 | 107 | let initEnv (ctx : Context) inVars = 108 | inVars |> Set.fold (addVarToEnv ctx) Map.empty 109 | 110 | let treeToExprLeaf oldEnv ctx env expr = 111 | expr |> exprToBV oldEnv ctx env 112 | 113 | let treeToExprInternal oldEnv (ctx : Context) env leftExpr rightExpr cond = 114 | let condBV = ctx.MkEq(cond |> exprToBV oldEnv ctx env, ctx.MkBV(1, 1u)) 115 | ctx.MkITE(condBV, leftExpr, rightExpr) :?> BitVecExpr 116 | 117 | let treeToExpr oldEnv ctx env tree = 118 | let leafFunc = treeToExprLeaf oldEnv ctx env 119 | let internalFunc = treeToExprInternal oldEnv ctx env 120 | tree |> treeFoldPostorder leafFunc internalFunc 121 | 122 | let convertToBV oldEnv (ctx : Context) env (reg : Reg) tree = 123 | let name, size = reg 124 | let value = tree |> treeToExpr oldEnv ctx env 125 | env |> Map.add reg value 126 | 127 | let memToVar summary varSet _ idx = 128 | let name = sprintf "mem%d" idx 129 | let reg = summary |> Map.findKey (fun (name_, _) _ -> name_ = name) 130 | varSet |> Set.add reg 131 | 132 | let convertToEnv (ctx : Context) keys info = 133 | let inVars, memSummary, regSummary = info 134 | let vars = 135 | memSummary |> Map.toSeq |> Seq.map fst |> Set.ofSeq |> Set.union inVars 136 | let env = vars |> initEnv ctx 137 | let summary = 138 | Map(Seq.concat [ (Map.toSeq memSummary) ; (Map.toSeq regSummary) ]) 139 | summary 140 | |> Map.fold (convertToBV env ctx) env 141 | |> Map.filter (filterVar keys) 142 | 143 | let combineEnv (ctx:Context) (env2:Map) acc (key1:Reg) value1 = 144 | let name1, size1 = key1 145 | if name1.StartsWith("mem") 146 | then 147 | let name2, size2 = env2 |> Map.findKey (fun (name, _) _ -> name = name1) 148 | if size1 = size2 149 | then 150 | acc |> Map.add key1 (value1, env2.Item key1) 151 | else 152 | let value2 = env2.Item (name2, size2) 153 | let bigSize, smallSize = 154 | if size1 > size2 then size1, size2 else size2, size1 155 | let bigValue, smallValue = 156 | if size1 > size2 then value1, value2 else value2, value1 157 | let size = 158 | ctx.MkBV((smallSize |> uint32), (bigSize |> uint32)) :> BitVecExpr 159 | let orig = ctx.MkBVConst(name1, bigSize |> uint32) 160 | let orig = ctx.MkBVLSHR(orig, size) 161 | let orig = ctx.MkBVSHL(orig, size) 162 | let smallValue = 163 | ctx.MkZeroExt((bigSize - smallSize) |> uint32, smallValue) 164 | let smallValue = ctx.MkBVOR(orig, smallValue) 165 | acc |> Map.add key1 (bigValue, smallValue) 166 | else 167 | acc |> Map.add key1 (value1, env2.Item key1) 168 | 169 | let equating (ctx : Context) acc _ (e1, e2) = 170 | ctx.MkOr(acc, ctx.MkNot(ctx.MkEq(e1, e2))) 171 | 172 | let mkEquation (ctx : Context) env1 env2 = 173 | let combined = env1 |> Map.fold (combineEnv ctx env2) Map.empty 174 | let acc = ctx.MkFalse() 175 | let equation = 176 | combined 177 | |> Map.fold (equating ctx) acc 178 | combined, equation 179 | 180 | let renameMemFold (memMap1 : Map) memSummary2 map addr idx = 181 | let name = sprintf "mem%d" (memMap1.Item addr) 182 | let oldname = sprintf "mem%d" idx 183 | let _, size = 184 | memSummary2 |> Map.findKey (fun (name, size) _ -> name = oldname) 185 | let expr = memSummary2.Item (oldname, size) 186 | map |> Map.add (oldname, size) expr 187 | 188 | let renameMem memMap1 memMap2 memSummary2 = 189 | memMap2 |> Map.fold (renameMemFold memMap1 memSummary2) Map.empty 190 | 191 | let differentialTesting undefSet info1 info2 = 192 | let inVars1, (memSummary1, memMap1, regSummary1) = info1 193 | let inVars2, (memSummary2, memMap2, regSummary2) = info2 194 | 195 | let memKey1 = memMap1 |> Map.toSeq |> Seq.map fst |> Set.ofSeq 196 | let memKey2 = memMap2 |> Map.toSeq |> Seq.map fst |> Set.ofSeq 197 | 198 | if (memKey1 |> Set.count) <> (memKey2 |> Set.count) 199 | then raise MemoryNumberMismatch 200 | 201 | if memKey1 <> memKey2 202 | then raise IncomparableMemoryWarning 203 | 204 | let memSummary2 = memSummary2 |> renameMem memMap1 memMap2 205 | 206 | let regKey1 = 207 | regSummary1 208 | |> Map.toSeq 209 | |> Seq.map fst 210 | |> Set.ofSeq 211 | |> Set.filter (fun key -> undefSet |> Set.contains key |> not) 212 | let regKey2 = 213 | regSummary2 214 | |> Map.toSeq 215 | |> Seq.map fst 216 | |> Set.ofSeq 217 | |> Set.filter (fun key -> undefSet |> Set.contains key |> not) 218 | 219 | (* 220 | if regKey1 <> regKey2 221 | then raise VariableNumberMismatch 222 | *) 223 | let regKey = Set.union regKey1 regKey2 224 | 225 | let regSummary1 = 226 | regSummary1 227 | |> Map.filter (fun key _ -> regKey |> Set.contains key) 228 | let regSummary2 = 229 | regSummary2 230 | |> Map.filter (fun key _ -> regKey |> Set.contains key) 231 | 232 | let ctx = new Context() 233 | 234 | let env1 = (inVars1, memSummary1, regSummary1) |> convertToEnv ctx regKey1 235 | let env2 = (inVars2, memSummary2, regSummary2) |> convertToEnv ctx regKey2 236 | 237 | let combined, equation = mkEquation ctx env1 env2 238 | let solver = ctx.MkSolver() 239 | solver.Assert(equation) 240 | match solver.Check() with 241 | | Status.UNSATISFIABLE -> EQUIV 242 | | Status.SATISFIABLE -> 243 | let model = solver.Model 244 | //printfn "%A" model 245 | let regs = 246 | combined 247 | |> Map.map (fun k (e1, e2) -> (*printfn "%A - %A - %A" k (model.Eval(e1)) (model.Eval(e2)) ;*) model.Eval(e1) = model.Eval(e2)) 248 | |> Map.filter (fun _ v -> v = false) 249 | |> Map.toSeq 250 | |> Seq.map fst 251 | |> Seq.map fst 252 | |> Set.ofSeq 253 | INEQUIV (regs) 254 | | _ -> raise SolverUnknown 255 | -------------------------------------------------------------------------------- /src/MeanDiff/StreamGen.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.StreamGen 2 | 3 | open CmdOpt 4 | open Utils 5 | 6 | let xedPath = "./build/ExternalXED" 7 | 8 | let addBefore pf lst = List.map (fun elt -> pf + elt) lst 9 | 10 | let mixTwoLists lst1 lst2 = 11 | List.fold 12 | (fun lst elt -> lst @ (addBefore elt lst2)) 13 | [] 14 | lst1 15 | 16 | let mixThreeLists lst1 lst2 lst3 = 17 | mixTwoLists lst2 lst3 |> mixTwoLists lst1 18 | 19 | let mixFourLists lst1 lst2 lst3 lst4 = 20 | lst4 21 | |> mixTwoLists lst3 22 | |> mixTwoLists lst2 23 | |> mixTwoLists lst1 24 | 25 | // Prefix Group 1 26 | let prefixCandidateType1 = ["" ; "f0" ; "f2" ; "f3"] 27 | 28 | // Prefix Group 2 29 | let prefixCandidateType2 = ["" ; "64"] 30 | 31 | // Prefix Group 3 32 | let prefixCandidateType3 = ["" ; "66"] 33 | 34 | // Prefix Group 4 35 | let prefixCandidateType4 = ["" ; "67"] 36 | 37 | let prefixFilterList32 = 38 | ["f0" ; "f2" ; "f3" ; "2e" ; "36" ; "3e" ; "26" ; "64" ; "65" ; "66" ; "67" ; 39 | "0f" ; "c4" ; "c5"] 40 | 41 | let prefixFilterList64 = 42 | seq [prefixFilterList32 ; List.map toHexStr [0x40 .. 0x4f]] |> List.concat 43 | 44 | let twoBytesFilterList = ["38" ; "3a"] 45 | 46 | // Only ModRM 47 | let modrmCandidateType1 = ["00" ; "08" ; "c0" ; "c8"] 48 | 49 | // ModRM + SIB 50 | let modrmCandidateType2 = ["04"] 51 | 52 | // ModRM + disp8 53 | let modrmCandidateType3 = ["40" ; "48"] 54 | 55 | // ModRM + disp32 56 | let modrmCandidateType4 = ["05" ; "0d" ; "80" ; "88"] 57 | 58 | // ModRM + SIB + disp8 59 | let modrmCandidateType5 = ["44" ; "4c"] 60 | 61 | // ModRM + SIB + disp32 62 | let modrmCandidateType6 = ["84" ; "8c"] 63 | 64 | // Only SIB 65 | let sibCandidateType1 = ["00" ; "01" ; "20" ; "21" ; "40" ; "41"] 66 | 67 | // SIB + disp32 68 | let sibCandidateType2 = ["05" ; "25"] 69 | 70 | // constant8 71 | let conCandidateType1 = ["00" ; "42" ; "ff"] 72 | 73 | // constant32 74 | let conCandidateType2 = ["00000000" ; "42424242" ; "ffffffff"] 75 | 76 | // constant64 77 | let conCandidateType3 = 78 | ["0000000000000000" ; "4242424242424242" ; "ffffffffffffffff"] 79 | 80 | let genPrefixCandidates arch = 81 | let basePrefix = 82 | mixFourLists 83 | prefixCandidateType1 84 | prefixCandidateType2 85 | prefixCandidateType3 86 | prefixCandidateType4 87 | match arch with 88 | | X86 -> basePrefix 89 | | X64 -> List.fold (fun l x -> x :: x + "48" :: l) [] basePrefix 90 | 91 | let rexPrefixCandidate = ["48"] 92 | 93 | let vexPrefixCandidate = 94 | List.fold (fun l x -> x :: (0b10000000 ||| x) :: l) [] [0 .. 31] 95 | |> List.map toHexStr 96 | |> mixTwoLists (List.map (fun x -> toHexStr (0b11100000 ||| x)) [0 .. 31]) 97 | |> addBefore "c4" 98 | 99 | let oneByteOpcodes32 = 100 | List.map toHexStr [0 .. 255] 101 | |> List.filter (fun x -> List.contains x prefixFilterList32 |> not) 102 | 103 | let oneByteOpcodes64 = 104 | List.map toHexStr [0 .. 255] 105 | |> List.filter (fun x -> List.contains x prefixFilterList64 |> not) 106 | 107 | let twoBytesOpcodes = 108 | List.map toHexStr [0 .. 255] 109 | |> List.filter (fun x -> List.contains x twoBytesFilterList |> not) 110 | |> addBefore "0f" 111 | 112 | let threeBytesOpcodes = 113 | List.map toHexStr [0 .. 255] 114 | |> List.fold (fun l x -> "38" + x :: "3a" + x :: l) [] 115 | |> addBefore "0f" 116 | 117 | let opcodeCandidates32 = 118 | seq [oneByteOpcodes32 ; twoBytesOpcodes ; threeBytesOpcodes] |> List.concat 119 | 120 | let opcodeCandidates64 = 121 | seq [oneByteOpcodes64 ; twoBytesOpcodes ; threeBytesOpcodes] |> List.concat 122 | 123 | let modrmCandidates = 124 | seq [ 125 | modrmCandidateType1 ; 126 | mixTwoLists modrmCandidateType2 sibCandidateType1 ; 127 | mixThreeLists modrmCandidateType2 sibCandidateType2 conCandidateType2 ; 128 | mixTwoLists modrmCandidateType3 conCandidateType1 ; 129 | mixTwoLists modrmCandidateType4 conCandidateType2 ; 130 | mixThreeLists modrmCandidateType5 sibCandidateType1 conCandidateType1 ; 131 | mixThreeLists modrmCandidateType6 sibCandidateType1 conCandidateType2 132 | ] |> List.concat 133 | 134 | let addOperandByType opcode = function 135 | | 0 -> 136 | [opcode] 137 | | 1 -> 138 | modrmCandidates |> addBefore opcode 139 | | 2 -> 140 | conCandidateType1 |> addBefore opcode 141 | | 3 -> 142 | conCandidateType2 |> addBefore opcode 143 | | 4 -> 144 | conCandidateType3 |> addBefore opcode 145 | | 5 -> 146 | conCandidateType1 |> mixTwoLists modrmCandidates |> addBefore opcode 147 | | 6 -> 148 | conCandidateType2 |> mixTwoLists modrmCandidates |> addBefore opcode 149 | | 7 -> 150 | conCandidateType3 |> mixTwoLists modrmCandidates |> addBefore opcode 151 | | _ -> [] 152 | 153 | let getType arch opcode = 154 | let size = (String.length opcode) / 2 155 | let archStr = 156 | match arch with 157 | | X86 -> "x86" 158 | | X64 -> "x64" 159 | let arg = sprintf "-i %s -s %d -a %s -m gettype" opcode size archStr 160 | let args = [xedPath ; arg] 161 | procRetValue args 162 | 163 | let checkInsn arch insn = 164 | let size = (String.length insn) / 2 165 | let archStr = 166 | match arch with 167 | | X86 -> "x86" 168 | | X64 -> "x64" 169 | let arg = sprintf "-i %s -s %d -a %s -m checkinsn" insn size archStr 170 | let args =[xedPath ; arg] 171 | procRetValue args 172 | 173 | let allGen arch = 174 | match arch with 175 | | X86 -> 176 | opcodeCandidates32 177 | |> List.fold 178 | (fun pool opcode -> 179 | seq [ 180 | getType arch opcode 181 | |> addOperandByType opcode 182 | |> mixTwoLists (genPrefixCandidates arch) ; 183 | pool 184 | ] |> List.concat) 185 | [] 186 | |> List.filter (fun insn -> checkInsn arch insn = 1) 187 | | X64 -> 188 | opcodeCandidates64 189 | |> List.fold 190 | (fun pool opcode -> 191 | seq [ 192 | getType arch opcode 193 | |> addOperandByType opcode 194 | |> mixTwoLists (genPrefixCandidates arch) ; 195 | pool 196 | ] |> List.concat) 197 | [] 198 | |> List.filter (fun insn -> checkInsn arch insn = 1) 199 | 200 | let blackListGen arch path = 201 | let target = readLinesToList path 202 | match arch with 203 | | X86 -> 204 | opcodeCandidates32 205 | |> List.filter (fun x -> List.contains x target |> not) 206 | |> List.fold 207 | (fun pool opcode -> 208 | seq [ 209 | getType arch opcode 210 | |> addOperandByType opcode 211 | |> mixTwoLists (genPrefixCandidates arch) ; 212 | pool 213 | ] |> List.concat) 214 | [] 215 | |> List.filter (fun insn -> checkInsn arch insn = 1) 216 | | X64 -> 217 | opcodeCandidates64 218 | |> List.filter (fun x -> List.contains x target |> not) 219 | |> List.fold 220 | (fun pool opcode -> 221 | seq [ 222 | getType arch opcode 223 | |> addOperandByType opcode 224 | |> mixTwoLists (genPrefixCandidates arch) ; 225 | pool 226 | ] |> List.concat) 227 | [] 228 | |> List.filter (fun insn -> checkInsn arch insn = 1) 229 | 230 | let whiteListGen arch path = 231 | readLinesToList path 232 | |> List.fold 233 | (fun pool opcode -> 234 | seq [ 235 | getType arch opcode 236 | |> addOperandByType opcode 237 | |> mixTwoLists (genPrefixCandidates arch) ; 238 | pool 239 | ] |> List.concat) 240 | [] 241 | |> List.filter (fun insn -> checkInsn arch insn = 1) 242 | 243 | let loadInsn (arch : ArchOption) = 244 | arch.toString 245 | |> sprintf "insn_%s" 246 | |> readLinesToList 247 | 248 | let saveInsn (arch : ArchOption) insnList = 249 | arch.toString 250 | |> sprintf "insn_%s" 251 | |> writeListToFile insnList 252 | 253 | let streamGen options = 254 | let arch = options.archOption 255 | match options.streamOption with 256 | | ALL -> allGen arch |> saveInsn arch ; [] 257 | | BLACK -> blackListGen arch options.streamFile |> saveInsn arch ; [] 258 | | WHITE -> whiteListGen arch options.streamFile |> saveInsn arch ; [] 259 | | USE -> loadInsn options.archOption 260 | -------------------------------------------------------------------------------- /src/MeanDiff/StreamGen.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.StreamGen 2 | 3 | open CmdOpt 4 | 5 | val streamGen : CmdOpts -> string list 6 | -------------------------------------------------------------------------------- /src/MeanDiff/Symbolic.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.Symbolic 2 | 3 | open Graph 4 | open Tree 5 | open Type 6 | open UIR 7 | 8 | type Context = Map 9 | 10 | type Summary = Map> 11 | 12 | type SummaryInfo = Summary * Map * Summary 13 | 14 | let getIdxFromMemMap expr memMap = 15 | let memMap = 16 | if memMap |> Map.containsKey expr 17 | then 18 | memMap 19 | else 20 | let idx = memMap.Count 21 | memMap |> Map.add expr idx 22 | memMap, (memMap.Item expr) 23 | 24 | let initRegisterContext context reg = 25 | context |> Map.add reg (Var reg) 26 | 27 | let initContext inVars context = 28 | inVars |> Set.fold initRegisterContext context 29 | 30 | let rec executeExpr memMap (context : Context) = function 31 | | Var (reg) -> 32 | memMap, context, (context.Item reg) 33 | | Load (addr, size) -> 34 | let memMap, context, addr = addr |> executeExpr memMap context 35 | let memMap, idx = memMap |> getIdxFromMemMap addr 36 | let reg = (sprintf "mem%d" idx), size 37 | let context = 38 | if context |> Map.containsKey reg 39 | then 40 | context 41 | else 42 | context |> Map.add reg (Var reg) 43 | memMap, context, (context.Item reg) 44 | | UnOp (op, expr) -> 45 | let memMap, context, expr = expr |> executeExpr memMap context 46 | memMap, context, UnOp (op, expr) 47 | | BinOp (op, expr1, expr2) -> 48 | let memMap, context, expr1 = expr1 |> executeExpr memMap context 49 | let memMap, context, expr2 = expr2 |> executeExpr memMap context 50 | memMap, context, BinOp (op, expr1, expr2) 51 | | RelOp (op, expr1, expr2) -> 52 | let memMap, context, expr1 = expr1 |> executeExpr memMap context 53 | let memMap, context, expr2 = expr2 |> executeExpr memMap context 54 | memMap, context, RelOp (op, expr1, expr2) 55 | | Cast (op, size, expr) -> 56 | let memMap, context, expr = expr |> executeExpr memMap context 57 | memMap, context, Cast (op, size, expr) 58 | | Ite (cond, thenExpr, elseExpr) -> 59 | let memMap, context, cond = cond |> executeExpr memMap context 60 | let memMap, context, thenExpr = thenExpr |> executeExpr memMap context 61 | let memMap, context, elseExpr = elseExpr |> executeExpr memMap context 62 | memMap, context, Ite (cond, thenExpr, elseExpr) 63 | | expr -> memMap, context, expr 64 | 65 | let executeStmt memMap context = function 66 | | Move (reg, expr) -> 67 | let memMap, context, expr = expr |> executeExpr memMap context 68 | let context = context |> Map.add reg expr 69 | memMap, context, None, None 70 | | Store (addr, expr) -> 71 | let memMap, context, expr = expr |> executeExpr memMap context 72 | let size = expr |> getSizeFromExpr 73 | let memMap, context, addr = addr |> executeExpr memMap context 74 | let memMap, idx = memMap |> getIdxFromMemMap addr 75 | let reg = (sprintf "mem%d" idx), size 76 | let context = context |> Map.add reg expr 77 | memMap, context, None, None 78 | | CJump (cond, _, _) -> 79 | let memMap, context, cond = cond |> executeExpr memMap context 80 | memMap, context, Some cond, None 81 | | End (addr) -> 82 | let memMap, context, addr = addr |> executeExpr memMap context 83 | memMap, context, None, Some addr 84 | | _ -> memMap, context, None, None 85 | 86 | let findNodeIdByLabel targetLbl graph nodeId (lbl, _) = 87 | match lbl with 88 | | Some (lbl) -> targetLbl = lbl 89 | | None -> false 90 | 91 | let getDestination cfg nodeId = 92 | let blockId, stmtId = nodeId 93 | let _, stmt = nodeId |> getNode cfg 94 | match stmt with 95 | | CJump (_, thenLbl, elseLbl) -> 96 | let thenNodeId = cfg |> findNodeId (findNodeIdByLabel thenLbl) 97 | let elseNodeId = cfg |> findNodeId (findNodeIdByLabel elseLbl) 98 | [thenNodeId ; elseNodeId] 99 | | End (_) -> [] 100 | | _ -> [(blockId, stmtId + 1)] 101 | 102 | let rec execution cfg memMap (context, visited) nodeId = 103 | let _, stmt = nodeId |> getNode cfg 104 | let memMap, context, cond, addr = stmt |> executeStmt memMap context 105 | let visited = visited |> Set.add nodeId 106 | let dests = nodeId |> getDestination cfg 107 | match dests with 108 | | [ dest0 ; dest1 ] -> 109 | if (visited |> Set.contains dest0) || (visited |> Set.contains dest1) 110 | then 111 | raise LoopDetected 112 | let memMap, leftNode = 113 | dest0 |> execution cfg memMap (context, visited) 114 | let memMap, rightNode = 115 | dest1 |> execution cfg memMap (context, visited) 116 | match cond with 117 | | Some cond -> 118 | memMap, InternalNode (cond, leftNode, rightNode) 119 | | None -> raise ConditionNotSet 120 | | [ dest ] -> 121 | if visited |> Set.contains dest then raise LoopDetected 122 | dest |> execution cfg memMap (context, visited) 123 | | [] -> 124 | match addr with 125 | | Some addr -> 126 | memMap, LeafNode (context, addr) 127 | | None -> raise AddressNotSet 128 | | _ -> raise InvalidDestination 129 | 130 | let treeToSummaryLeaf (context, _) = (* XXX *) 131 | context 132 | |> Map.fold (fun map reg expr -> map |> Map.add reg (LeafNode expr)) Map.empty 133 | 134 | let collectReg leftSummary rightSummary = 135 | let leftReg = 136 | leftSummary |> Map.fold (fun set k _ -> set |> Set.add k) Set.empty 137 | let rightReg = 138 | rightSummary |> Map.fold (fun set k _ -> set |> Set.add k) Set.empty 139 | Set.union leftReg rightReg 140 | 141 | let unionSummary leftSummary rightSummary cond summary reg = 142 | let leftExist = leftSummary |> Map.containsKey reg 143 | let rightExist = rightSummary |> Map.containsKey reg 144 | match leftExist, rightExist with 145 | | true, true -> 146 | let leftTree = leftSummary.Item reg 147 | let rightTree = rightSummary.Item reg 148 | summary 149 | |> Map.add reg (InternalNode (cond, leftTree, rightTree)) 150 | | true, false -> 151 | let leftTree = leftSummary.Item reg 152 | let rightTree = LeafNode (Var reg) 153 | summary 154 | |> Map.add reg (InternalNode (cond, leftTree, rightTree)) 155 | | false, true -> 156 | let leftTree = LeafNode (Var reg) 157 | let rightTree = rightSummary.Item reg 158 | summary 159 | |> Map.add reg (InternalNode (cond, leftTree, rightTree)) 160 | | _ -> summary 161 | 162 | let treeToSummaryInternal leftSummary rightSummary cond = 163 | let regs = collectReg leftSummary rightSummary 164 | regs |> Set.fold (unionSummary leftSummary rightSummary cond) Map.empty 165 | 166 | let treeToSummary tree = 167 | tree |> treeFoldPostorder treeToSummaryLeaf treeToSummaryInternal 168 | 169 | let findOutVar var reg = 170 | var = reg 171 | 172 | let filterOutVar outVars (var : Reg) _ = 173 | let name, _ = var 174 | if name.StartsWith "mem" 175 | then 176 | true 177 | else 178 | outVars |> Set.exists (findOutVar var) 179 | 180 | let filterMem (var : Reg) _ = 181 | let name, _ = var 182 | name.StartsWith "mem" 183 | 184 | let getTypeFromTreeLeaf expr = 185 | expr |> getSizeFromExpr 186 | 187 | let getTypeFromTreeInternal leftType rightType _ = 188 | if leftType = 0us || rightType = 0us 189 | then 190 | 0us 191 | else 192 | leftType 193 | 194 | let getTypeFromTree tree = 195 | tree |> treeFoldPostorder getTypeFromTreeLeaf getTypeFromTreeInternal 196 | 197 | let filterUndefined _ tree = 198 | let ty = tree |> getTypeFromTree 199 | ty <> 0us 200 | 201 | let rec optimizeMemAddrRec = function 202 | | UnOp (op, expr) -> 203 | let expr = expr |> optimizeMemAddrRec 204 | UnOp (op, expr) 205 | | BinOp (op, expr1, expr2) -> 206 | match op with 207 | | ADD -> 208 | let expr1, expr2 = 209 | match expr1, expr2 with 210 | | Num (_, _), _ -> 211 | expr2 |> optimizeMemAddrRec, expr1 |> optimizeMemAddrRec 212 | | expr1, BinOp (ADD, expr2, Num (value, size)) 213 | | expr1, BinOp (ADD, Num (value, size), expr2) -> 214 | let expr1 = expr1 |> optimizeMemAddrRec 215 | let expr2 = expr2 |> optimizeMemAddrRec 216 | let expr1 = BinOp (ADD, expr1, expr2) |> optimizeMemAddrRec 217 | expr1, Num (value, size) 218 | | _ -> 219 | let expr1 = expr1 |> optimizeMemAddrRec 220 | let expr2 = expr2 |> optimizeMemAddrRec 221 | expr1, expr2 222 | if expr1 = expr2 223 | then 224 | let size = expr1 |> getSizeFromExpr 225 | BinOp (SHL, expr1, Num (1UL, size)) 226 | else 227 | match expr2 with 228 | | Num (0UL, _) -> expr1 229 | | _ -> BinOp (op, expr1, expr2) 230 | | UMUL -> 231 | let expr1 = expr1 |> optimizeMemAddrRec 232 | let expr2 = expr2 |> optimizeMemAddrRec 233 | let expr1, expr2 = 234 | match expr1 with 235 | | Num (_, _) -> expr2, expr1 236 | | _ -> expr1, expr2 237 | match expr1, expr2 with 238 | | BinOp (SDIV, expr1, Num (32UL, 32us)), Num (4UL, 32us) -> 239 | BinOp (SSHR, expr1, Num (3UL, 32us)) 240 | | expr1, Num (1UL, _) -> expr1 241 | | expr1, Num (2UL, _) -> 242 | let size = expr1 |> getSizeFromExpr 243 | BinOp (SHL, expr1, Num (1UL, size)) 244 | | _ -> BinOp (op, expr1, expr2) 245 | | SHL 246 | | USHR 247 | | SSHR -> 248 | let expr1 = expr1 |> optimizeMemAddrRec 249 | let expr2 = expr2 |> optimizeMemAddrRec 250 | match expr2 with 251 | | Num (value, _) -> 252 | let size = expr1 |> getSizeFromExpr 253 | BinOp (op, expr1, Num (value, size)) 254 | | _ -> 255 | BinOp (op, expr1, expr2) 256 | | _ -> 257 | let expr1 = expr1 |> optimizeMemAddrRec 258 | let expr2 = expr2 |> optimizeMemAddrRec 259 | BinOp (op, expr1, expr2) 260 | | RelOp (op, expr1, expr2) -> 261 | let expr1 = expr1 |> optimizeMemAddrRec 262 | let expr2 = expr2 |> optimizeMemAddrRec 263 | RelOp (op, expr1, expr2) 264 | | Cast (op, size, expr) -> 265 | let expr = expr |> optimizeMemAddrRec 266 | let exprSize = expr |> getSizeFromExpr 267 | if size = exprSize 268 | then 269 | expr 270 | else 271 | Cast (op, size, expr) 272 | | Ite (cond, thenExpr, elseExpr) -> 273 | let cond = cond |> optimizeMemAddrRec 274 | let thenExpr = thenExpr |> optimizeMemAddrRec 275 | let elseExpr = elseExpr |> optimizeMemAddrRec 276 | Ite (cond, thenExpr, elseExpr) 277 | | expr -> expr 278 | 279 | let optimizeMemAddr map addr idx = 280 | let addr = addr |> optimizeMemAddrRec 281 | map |> Map.add addr idx 282 | 283 | let symbolicExecution inVars outVars cfg = 284 | let context = Map.empty |> initContext inVars 285 | let memMap, tree = 286 | cfg 287 | |> findNodeId (findNodeIdByLabel "Label_Start") 288 | |> execution cfg Map.empty (context, Set.empty) 289 | // optimize memMap 290 | let memMap = 291 | memMap |> Map.fold optimizeMemAddr Map.empty 292 | let filteredSummary = 293 | tree 294 | |> treeToSummary 295 | |> Map.filter (filterOutVar outVars) 296 | let startTime = System.DateTime.Now 297 | let memSummary = 298 | filteredSummary 299 | |> Map.filter filterMem 300 | let curTime = System.DateTime.Now 301 | if (System.DateTime.Compare((startTime.AddSeconds 10.0), curTime)) = -1 302 | then raise TimeOut 303 | let regSummary = 304 | filteredSummary 305 | |> Map.filter (fun k v -> not (filterMem k v)) 306 | let curTime = System.DateTime.Now 307 | if (System.DateTime.Compare((startTime.AddSeconds 10.0), curTime)) = -1 308 | then raise TimeOut 309 | let undefinedVars = 310 | regSummary 311 | |> Map.filter (fun k v -> not (filterUndefined k v)) 312 | |> Map.toSeq 313 | |> Seq.map fst 314 | |> Set.ofSeq 315 | let curTime = System.DateTime.Now 316 | if (System.DateTime.Compare((startTime.AddSeconds 10.0), curTime)) = -1 317 | then raise TimeOut 318 | let regSummary = 319 | regSummary |> Map.filter filterUndefined 320 | let curTime = System.DateTime.Now 321 | if (System.DateTime.Compare((startTime.AddSeconds 10.0), curTime)) = -1 322 | then raise TimeOut 323 | (memSummary, memMap, regSummary), undefinedVars 324 | -------------------------------------------------------------------------------- /src/MeanDiff/Symbolic.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.Symbolic 2 | 3 | open Graph 4 | open Tree 5 | open UIR 6 | 7 | type Summary = Map> 8 | 9 | type SummaryInfo = Summary * Map * Summary 10 | 11 | val symbolicExecution : 12 | Set 13 | -> Set 14 | -> Graph<('c * int), (string option * Stmt)> 15 | -> SummaryInfo * Set 16 | -------------------------------------------------------------------------------- /src/MeanDiff/Tree.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.Tree 2 | 3 | type Tree<'a, 'b> = 4 | | LeafNode of 'a 5 | | InternalNode of 'b * Tree<'a, 'b> * Tree<'a, 'b> 6 | 7 | let rec treeFoldPostorder foldFuncLeaf foldFuncInternal = function 8 | | LeafNode (leafData) -> 9 | foldFuncLeaf leafData 10 | | InternalNode (internalData, leftTree, rightTree) -> 11 | let leftAcc = 12 | leftTree |> treeFoldPostorder foldFuncLeaf foldFuncInternal 13 | let rightAcc = 14 | rightTree |> treeFoldPostorder foldFuncLeaf foldFuncInternal 15 | foldFuncInternal leftAcc rightAcc internalData 16 | -------------------------------------------------------------------------------- /src/MeanDiff/Tree.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.Tree 2 | 3 | type Tree<'a, 'b> = 4 | | LeafNode of 'a 5 | | InternalNode of 'b * Tree<'a, 'b> * Tree<'a, 'b> 6 | 7 | val treeFoldPostorder : 8 | ('a -> 'c) -> ('c -> 'c -> 'b -> 'c) -> Tree<'a, 'b> -> 'c 9 | -------------------------------------------------------------------------------- /src/MeanDiff/Type.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.Type 2 | 3 | open UIR 4 | 5 | module SymbTable = 6 | type Table = Map 7 | 8 | let createTable = Map.empty 9 | 10 | let checkElem symb (table : Table) = table.TryFind symb 11 | 12 | let setElem symb size (table : Table) = table.Add(symb, size) 13 | 14 | let getElem symb (table : Table) = table.Item symb 15 | 16 | let rec getSizeFromExpr = function 17 | | Num (_, size) 18 | | Var (_, size) -> 19 | size 20 | | Load (addr, size) -> 21 | let addrSize = addr |> getSizeFromExpr 22 | if addrSize <> 0us 23 | then 24 | size 25 | else 26 | 0us 27 | | UnOp (_, expr) -> expr |> getSizeFromExpr 28 | | BinOp (op, expr1, expr2) -> 29 | let size1 = expr1 |> getSizeFromExpr 30 | let size2 = expr2 |> getSizeFromExpr 31 | if size1 <> 0us && size2 <> 0us 32 | then 33 | if op = CONCAT 34 | then 35 | size1 + size2 36 | else 37 | size1 38 | else 39 | 0us 40 | | RelOp (_, expr1, expr2) -> 41 | let size1 = expr1 |> getSizeFromExpr 42 | let size2 = expr2 |> getSizeFromExpr 43 | if size1 <> 0us && size2 <> 0us 44 | then 45 | 1us 46 | else 47 | 0us 48 | | Cast (_, size, expr) -> 49 | let exprSize = expr |> getSizeFromExpr 50 | if exprSize <> 0us 51 | then 52 | size 53 | else 54 | 0us 55 | | Ite (cond, thenExpr, elseExpr) -> 56 | let condSize = cond |> getSizeFromExpr 57 | let thenSize = thenExpr |> getSizeFromExpr 58 | let elseSize = elseExpr |> getSizeFromExpr 59 | if condSize = 1us && thenSize <> 0us && elseSize <> 0us 60 | then 61 | thenSize 62 | else 63 | 0us 64 | | Undefined -> 0us 65 | 66 | let getTypeReg symbTable (name, size) = 67 | match SymbTable.checkElem name symbTable with 68 | | Some (oldSize) -> 69 | if oldSize = size 70 | then 71 | size, symbTable 72 | else 73 | printfn "%A" (name, size) 74 | raise VariableSizeMismatch 75 | | None -> size, (SymbTable.setElem name size symbTable) 76 | 77 | let rec getTypeExpr symbTable = function 78 | | Num (_, size) -> size, symbTable 79 | | Var (reg) -> reg |> getTypeReg symbTable 80 | | Load (addr, size) -> 81 | let size1, symbTable = addr |> getTypeExpr symbTable 82 | if size1 = 0us 83 | then 84 | 0us, symbTable 85 | else 86 | size, symbTable 87 | | UnOp (_, expr) -> expr |> getTypeExpr symbTable 88 | | BinOp (CONCAT, expr1, expr2) -> 89 | let size1, symbTable = expr1 |> getTypeExpr symbTable 90 | let size2, symbTable = expr2 |> getTypeExpr symbTable 91 | if size1 = 0us || size2 = 0us 92 | then 93 | 0us, symbTable 94 | else 95 | size1 + size2, symbTable 96 | | BinOp (SHL, expr1, expr2) 97 | | BinOp (USHR, expr1, expr2) 98 | | BinOp (SSHR, expr1, expr2) -> 99 | let size1, symbTable = expr1 |> getTypeExpr symbTable 100 | let size2, symbTable = expr2 |> getTypeExpr symbTable 101 | if size1 = 0us || size2 = 0us 102 | then 103 | 0us, symbTable 104 | else 105 | if size1 >= size2 106 | then 107 | size1, symbTable 108 | else 109 | raise OperandSizeMismatch 110 | | BinOp (_, expr1, expr2) -> 111 | let size1, symbTable = expr1 |> getTypeExpr symbTable 112 | let size2, symbTable = expr2 |> getTypeExpr symbTable 113 | if size1 = 0us || size2 = 0us 114 | then 115 | 0us, symbTable 116 | else 117 | if size1 = size2 118 | then 119 | size1, symbTable 120 | else 121 | raise OperandSizeMismatch 122 | | RelOp (_, expr1, expr2) -> 123 | let size1, symbTable = expr1 |> getTypeExpr symbTable 124 | let size2, symbTable = expr2 |> getTypeExpr symbTable 125 | if size1 = 0us || size2 = 0us 126 | then 127 | 0us, symbTable 128 | else 129 | if size1 = size2 130 | then 131 | 1us, symbTable 132 | else 133 | raise OperandSizeMismatch 134 | | Cast (LOW, size, expr) 135 | | Cast (HIGH, size, expr) -> 136 | let size1, symbTable = expr |> getTypeExpr symbTable 137 | if size1 = 0us 138 | then 139 | 0us, symbTable 140 | else 141 | if size <= size1 142 | then 143 | size, symbTable 144 | else 145 | raise InvalidCastSize 146 | | Cast (ZERO, size, expr) 147 | | Cast (SIGN, size, expr) -> 148 | let size1, symbTable = expr |> getTypeExpr symbTable 149 | if size1 = 0us 150 | then 151 | 0us, symbTable 152 | else 153 | if size1 <= size 154 | then 155 | size, symbTable 156 | else 157 | raise InvalidCastSize 158 | | Ite (cond, thenExpr, elseExpr) -> 159 | let size1, symbTable = cond |> getTypeExpr symbTable 160 | let size2, symbTable = thenExpr |> getTypeExpr symbTable 161 | let size3, symbTable = elseExpr |> getTypeExpr symbTable 162 | if size1 = 0us || size2 = 0us || size3 = 0us 163 | then 164 | 0us, symbTable 165 | else 166 | if size1 = 1us 167 | then 168 | if size2 = size3 169 | then 170 | size2, symbTable 171 | else 172 | raise OperandSizeMismatch 173 | else 174 | raise OperandSizeMismatch 175 | | Undefined -> 0us, symbTable 176 | 177 | let typeCheckStmt symbTable = function 178 | | Start (_, _, _) -> symbTable 179 | | Move (reg, expr) -> 180 | let regSize, symbTable = reg |> getTypeReg symbTable 181 | let exprSize, symbTable = expr |> getTypeExpr symbTable 182 | if exprSize = 0us 183 | then 184 | symbTable 185 | else 186 | if regSize = exprSize 187 | then 188 | symbTable 189 | else 190 | raise OperandSizeMismatch 191 | | Store (addr, expr) -> 192 | let _, symbTable = addr |> getTypeExpr symbTable 193 | let _, symbTable = expr |> getTypeExpr symbTable 194 | symbTable 195 | | Label (_) -> symbTable 196 | | CJump (cond, _, _) -> 197 | let size, symbTable = cond |> getTypeExpr symbTable 198 | if size = 0us 199 | then 200 | symbTable 201 | else 202 | if size = 1us 203 | then 204 | symbTable 205 | else 206 | raise OperandSizeMismatch 207 | | End (addr) -> 208 | let _, symbTable = addr |> getTypeExpr symbTable 209 | symbTable 210 | | Unrecognized -> symbTable 211 | 212 | let typeCheck = function 213 | | Stmts (sl) -> 214 | sl |> List.fold typeCheckStmt (SymbTable.createTable) |> ignore 215 | | Uninterpretable 216 | | Incapable -> () 217 | -------------------------------------------------------------------------------- /src/MeanDiff/Type.fsi: -------------------------------------------------------------------------------- 1 | module MeanDiff.Type 2 | 3 | open UIR 4 | 5 | val getSizeFromExpr : Expr -> Size 6 | 7 | val typeCheck : AST -> unit 8 | -------------------------------------------------------------------------------- /src/MeanDiff/UIR.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.UIR 2 | 3 | ////////////////////////////////////////// 4 | // Unified Intermediate Representation // 5 | ////////////////////////////////////////// 6 | 7 | 8 | ////////////////// 9 | // Basic Types // 10 | ////////////////// 11 | 12 | type Value = uint64 13 | type Size = uint16 // 16bits are enough to represent a size 14 | type Symbol = string // Symbol is used for both register names and labels 15 | 16 | 17 | ////////////////////// 18 | // Endian Constants // 19 | ////////////////////// 20 | 21 | type EndianT = 22 | | BE 23 | | LE 24 | 25 | 26 | //////////////////////// 27 | // Operator Constants // 28 | //////////////////////// 29 | 30 | type UnOpT = // Unary Operator 31 | | NEG 32 | | NOT 33 | 34 | type BinOpT = // Binary Operator 35 | | ADD 36 | | SUB 37 | | UMUL 38 | | SMUL 39 | | UDIV 40 | | SDIV 41 | | UMOD 42 | | SMOD 43 | | SHL 44 | | USHR 45 | | SSHR 46 | | AND 47 | | OR 48 | | XOR 49 | | CONCAT 50 | 51 | type RelOpT = // Relational Operator 52 | | EQ 53 | | NEQ 54 | | ULT 55 | | SLT 56 | | ULE 57 | | SLE 58 | 59 | type CastOpT = // Casting Operator 60 | | LOW 61 | | HIGH 62 | | ZERO 63 | | SIGN 64 | 65 | 66 | //////////////////// 67 | // Variable Type // 68 | //////////////////// 69 | 70 | type Reg = Symbol * Size 71 | 72 | 73 | //////////////// 74 | // Expression // 75 | //////////////// 76 | 77 | type Expr = 78 | | Num of Value * Size // value, size 79 | | Var of Reg // reg 80 | | Load of Expr * Size // addr, size 81 | | UnOp of UnOpT * Expr // op, expr 82 | | BinOp of BinOpT * Expr * Expr // op, expr1, expr2 83 | | RelOp of RelOpT * Expr * Expr // op, expr1, expr2 84 | | Cast of CastOpT * Size * Expr // op, size, expr 85 | | Ite of Expr * Expr * Expr // cond, thenExpr, elseExpr 86 | | Undefined // Undefined Value case defined in Manual 87 | 88 | 89 | //////////////// 90 | // Statement // 91 | //////////////// 92 | 93 | type Stmt = 94 | | Start of Value * Size * EndianT // addr, len, endian 95 | | Move of Reg * Expr // reg, expr 96 | | Store of Expr * Expr // addr, expr 97 | | Label of Symbol // lbl 98 | | CJump of Expr * Symbol * Symbol // cond, thenLbl, elseLbl 99 | | End of Expr // addr 100 | | Unrecognized // Statement that is not currently supported by UIR 101 | 102 | 103 | ////////////////////////// 104 | // Abstract Syntax Tree // 105 | ////////////////////////// 106 | 107 | type AST = 108 | | Stmts of Stmt list // When lifting is success 109 | | Uninterpretable // When lifting is failed because of 110 | // lifter 111 | | Incapable // When lifting is failed because of 112 | // translator 113 | let getStmts = function 114 | | Stmts (sl) -> sl 115 | | _ -> [] 116 | -------------------------------------------------------------------------------- /src/MeanDiff/Utils.fs: -------------------------------------------------------------------------------- 1 | module MeanDiff.Utils 2 | 3 | open System.Diagnostics 4 | open System.IO 5 | open System.Text.RegularExpressions 6 | 7 | let readLinesToList = File.ReadLines >> List.ofSeq 8 | 9 | let readLinesToSet = File.ReadLines >> Set.ofSeq 10 | 11 | let writeListToFile lineList path = 12 | let lineArray = lineList |> Array.ofList 13 | File.WriteAllLines(path, lineArray) 14 | 15 | let writeToFile name text = File.WriteAllText(name, text) 16 | 17 | let isHexStr hexStr = 18 | let re = new Regex("^(([A-Fa-f0-9]{2})*)$") 19 | re.IsMatch hexStr 20 | 21 | let toHexStr = sprintf "%02x" 22 | 23 | let procRetValue (args : string list) = 24 | if List.length args <> 2 then raise OperandLengthUnmatched 25 | let p = new Process() 26 | p.StartInfo.FileName <- args.[0] 27 | p.StartInfo.Arguments <- args.[1] 28 | p.StartInfo.UseShellExecute <- false 29 | p.Start() |> ignore 30 | p.WaitForExit() 31 | p.ExitCode 32 | 33 | let procStdOutStr (args : string list) = 34 | if List.length args <> 2 then raise OperandLengthUnmatched 35 | let p = new Process() 36 | p.StartInfo.FileName <- args.[0] 37 | p.StartInfo.Arguments <- args.[1] 38 | p.StartInfo.UseShellExecute <- false 39 | p.StartInfo.RedirectStandardOutput <- true 40 | p.Start() |> ignore 41 | let s = sprintf "%s" (p.StandardOutput.ReadToEnd()) 42 | p.WaitForExit() 43 | s 44 | -------------------------------------------------------------------------------- /src/MeanDiff/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/ReleaseNotes.md: -------------------------------------------------------------------------------- 1 | ### New in 0.0.1 2 | * Initial release 3 | -------------------------------------------------------------------------------- /src/build.fsx: -------------------------------------------------------------------------------- 1 | // Include Fake library 2 | #r "./packages/FAKE/tools/FakeLib.dll" 3 | 4 | open Fake 5 | open Fake.AssemblyInfoFile 6 | open System 7 | open System.IO 8 | 9 | // Properties 10 | let prodName = "MeanDiff" 11 | let prodDesc = "MeanDiff: BBIR testing tool" 12 | let licenseStr = "Copyright (c) KAIST, since 2017" 13 | let releaseNotes = 14 | ReadFile "ReleaseNotes.md" 15 | |> ReleaseNotesHelper.parseReleaseNotes 16 | 17 | let buildDir = "./build/" 18 | let buildMode = getBuildParamOrDefault "mode" "Debug" 19 | 20 | let createAsmInfo path title product guid = 21 | CreateFSharpAssemblyInfo path 22 | [ 23 | Attribute.Title title 24 | Attribute.Product product 25 | Attribute.Description prodDesc 26 | Attribute.Version releaseNotes.AssemblyVersion 27 | Attribute.FileVersion releaseNotes.AssemblyVersion 28 | Attribute.Guid guid 29 | Attribute.Copyright licenseStr 30 | ] 31 | 32 | let buildProj projName guid = 33 | let projDir = projName 34 | let projFile = projName + ".fsproj" 35 | let platform = if Environment.Is64BitOperatingSystem then "x64" else "x86" 36 | let isMSBuild = (Path.GetFileName (msBuildExe)).ToLower().StartsWith("msbuild") 37 | let setParams defaults = 38 | { 39 | defaults with 40 | Verbosity = Some Normal 41 | Targets = ["Build"] 42 | Properties = 43 | [ 44 | "Platform", platform 45 | "Optimize", if buildMode = "Debug" then "False" else "True" 46 | "DebugSymbols", "True" 47 | "Configuration", buildMode 48 | "DefineConstants", getBuildParamOrDefault "define" "" 49 | "AllowedReferenceRelatedFileExtensions", "none" 50 | "TargetFrameworkVersion", getBuildParamOrDefault "framework" "v4.5" 51 | ] 52 | ToolsVersion = if isMSBuild then None else Some "12.0" 53 | } 54 | 55 | createAsmInfo (projDir @@ "AssemblyInfo.fs") projName prodName guid 56 | build setParams (projDir @@ projFile) |> DoNothing 57 | 58 | // Targets 59 | Target "Clean" (fun _ -> 60 | CleanDir buildDir 61 | Directory.Delete buildDir 62 | CleanDir "./MeanDiff/obj/" 63 | Directory.Delete "./MeanDiff/obj/" 64 | File.Delete "./MeanDiff/AssemblyInfo.fs" 65 | ) 66 | 67 | Target "Package" (fun _ -> 68 | RestorePackages () 69 | ) 70 | 71 | Target "MeanDiff" (fun _ -> 72 | buildProj "MeanDiff" "346faf23-b624-4861-ae72-0efb43ad4b68" 73 | ) 74 | 75 | Target "All" DoNothing 76 | 77 | // Dependencies 78 | "Package" ==> "All" 79 | "MeanDiff" ==> "All" 80 | 81 | // Start build 82 | RunTargetOrDefault "All" 83 | --------------------------------------------------------------------------------