├── LICENSE ├── README.md ├── cmd.go ├── docs ├── index.md ├── mkdocs.yml └── readTheDocs.md ├── finding.go ├── iocs.go ├── magicRules.go ├── main.go ├── radarePipe.go ├── shell.go ├── ssdeep.go ├── supportFunc.go ├── workspace.go └── yaraPipe.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 wolfvan 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # YaraRET 3 | 4 | # Introduction 5 | 6 | YaraRET is a carving tool based in Radare2 and Yara and written in Go. It provides 58 magic number's yara rules for detecting 58 types of files. 7 | 8 | This tool is based on the idea of a first stage detecting files using its magic numbers and a second stage, selecting or discarding those detected files using Yara, IoC or its entropy value. 9 | After that, it is able to generate the hash, the ssdeep (and check it over anothers). 10 | Also provides an integration with VirusTotal. 11 | 12 | 13 | In order to deal with forensics cases based on weak clues, YaraRET provides different modes for raw disk handling. 14 | 15 | 16 | 17 | # Install 18 | 19 | For a compiled bin, you can download last release from Github. 20 | 21 | Also, you can download git repo and build it. 22 | 23 | #### Dependencies 24 | 25 | Yara 26 | Radare2 27 | 28 | github.com/abiosoft/ishell 29 | github.com/docopt/docopt-go 30 | github.com/glaslos/ssdeep 31 | github.com/hillu/go-yara 32 | github.com/radare/r2pipe-go 33 | github.com/williballenthin/govt 34 | 35 | 36 | 37 | 38 | 39 | # Usage 40 | 41 | YaraRET provides diferent modes for handling different forensics cases. 42 | 43 | If you are interested in get a file from a yara rule, you can execute the following command: 44 | 45 | 46 | 47 | $ ./yaraRET yara myYaraRule rawdisk myRaw maxsize 3000 48 | 49 | 50 | 51 | If you are interested in get a file from an IoC like a domain or hash from any kind of file like STIX or txt 52 | 53 | $ ./yaraRET ioc ./myIOC.stix rawdisk myRaw maxsize 3000 54 | 55 | 56 | 57 | 58 | For a complex analysis, YaraRET provides a shell mode which allows an analysis at the tool's opening 59 | 60 | $ ./yaraRET rawdisk myRaw shell 61 | 62 | 63 | >> start all 64 | >> set pe 65 | >> show - 66 | 67 | 68 | # Features 69 | 70 | - Radare2 integration 71 | - SSdeep distance checking 72 | - VirusTotal API integration 73 | - Scripting 74 | - YaraForensics Ruleset 75 | - Entropy 76 | - Boot Sector analysis 77 | 78 | 79 | This tool was introduced in this talk at r2con 2018 80 | 81 | - https://www.youtube.com/watch?v=trLVw9J-mfw 82 | 83 | - https://github.com/radareorg/r2con2018/blob/master/talks/08-YaraRET/NotAnotherRET.pdf 84 | 85 | -------------------------------------------------------------------------------- /cmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders ") 125 | } else { 126 | f1, err := os.OpenFile(OutputFile, os.O_APPEND|os.O_WRONLY, 0644) 127 | if err != nil { 128 | fmt.Println("err") 129 | } 130 | f1.WriteString("[") 131 | f1.Close() 132 | for _, elem := range sliceNewResults { 133 | count = count+1 134 | myJson := &newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Ssdeep: elem.Ssdeep, Hash: elem.Hash, Size: elem.Size, Comment: elem.Comment} 135 | b, err := json.Marshal(myJson) 136 | 137 | if err != nil { 138 | fmt.Println(err) 139 | return 140 | } 141 | 142 | 143 | f, err := os.OpenFile(OutputFile, os.O_APPEND|os.O_WRONLY, 0600) 144 | if err != nil { 145 | panic(err) 146 | } 147 | 148 | 149 | if _, err = f.WriteString(string(b)); err != nil { 150 | panic(err) 151 | } 152 | 153 | if count == len(sliceNewResults){ 154 | last = true 155 | } 156 | 157 | if last { 158 | 159 | }else{ 160 | if _, err = f.WriteString(","); err != nil { 161 | panic(err) 162 | } 163 | 164 | } 165 | f.Close() 166 | } 167 | fmt.Println(count) 168 | fmt.Println(len(sliceNewResults)) 169 | 170 | f, err := os.OpenFile(OutputFile, os.O_APPEND|os.O_WRONLY, 0600) 171 | if err != nil { 172 | panic(err) 173 | } 174 | if _, err = f.WriteString("]"); err != nil { 175 | panic(err) 176 | } 177 | f.Close() 178 | 179 | 180 | fmt.Println("[+] Saved as " + OutputFile) 181 | } 182 | 183 | } 184 | 185 | func openCmd(argument []string, rawdisk string) { 186 | 187 | 188 | 189 | 190 | var myOwnResults []newResult 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | file, e := ioutil.ReadFile(workspace + "/" + argument[0]) 200 | 201 | if e != nil { 202 | fmt.Printf("File error: %v\n", e) 203 | os.Exit(1) 204 | } 205 | 206 | json.Unmarshal(file, &myOwnResults) 207 | 208 | var allRules string 209 | for _, element := range myOwnResults { 210 | allRules = allRules + element.Rule + " " 211 | 212 | } 213 | wordCount(allRules) 214 | 215 | sliceNewResults = myOwnResults 216 | 217 | } 218 | 219 | func vtiCmd(argument []string, rawdisk string) { 220 | 221 | if len(vtiAPI) < 4 { 222 | fmt.Println("Please set the API key") 223 | } else { 224 | apikey := vtiAPI 225 | 226 | 227 | if len(argument) > 0 { 228 | vt, err := virustotal.NewVirusTotal(apikey) 229 | if err != nil { 230 | log.Fatal(err) 231 | } 232 | 233 | switch option := argument[0]; option { 234 | case "scan": 235 | var result *virustotal.ScanResponse 236 | 237 | 238 | for _, elem := range sliceSet { 239 | fmt.Printf("Uploading %s to VirusTotal: ", (elem.Rule + "_" + strconv.Itoa(elem.Index))) 240 | 241 | file, err := os.Open((elem.Rule + "_" + strconv.Itoa(elem.Index))) 242 | 243 | if err != nil { 244 | log.Fatal(err) 245 | } 246 | 247 | defer file.Close() 248 | 249 | result, err = vt.Scan((elem.Rule + "_" + strconv.Itoa(elem.Index)), file) 250 | 251 | if err != nil { 252 | log.Fatal(err) 253 | } 254 | 255 | fmt.Printf("%s\n", result) 256 | 257 | } 258 | 259 | 260 | case "report": 261 | for _, elem := range sliceSet { 262 | fmt.Println("[+] Checking for this: "+elem.Hash) 263 | 264 | result, err := vt.Report(elem.Hash) 265 | 266 | if err != nil { 267 | log.Fatal(err) 268 | } 269 | 270 | fmt.Printf("%s\n", result) 271 | 272 | } 273 | default: 274 | fmt.Println("Usage:") 275 | fmt.Println("") 276 | fmt.Println("go run ./bin/vt.go --apikey {key} (--debug) scan {file} {file} ..") 277 | fmt.Println("go run ./bin/vt.go --apikey {key} (--debug) rescan {hash} {hash} ..") 278 | fmt.Println("go run ./bin/vt.go --apikey {key} (--debug) report 99017f6eebbac24f351415dd410d522d") 279 | fmt.Println("go run ./bin/vt.go --apikey {key} (--debug) scan-url {url} {url} ..") 280 | fmt.Println("go run ./bin/vt.go --apikey {key} (--debug) report-url www.google.com") 281 | fmt.Println("go run ./bin/vt.go --apikey {key} (--debug) ipaddress 90.156.201.27") 282 | fmt.Println("go run ./bin/vt.go --apikey {key} (--debug) domain 027.ru") 283 | fmt.Println("go run ./bin/vt.go --apikey {key} (--debug) --resource 99017f6eebbac24f351415dd410d522d comment \"How to disinfect you from this file.. #disinfect #zbot\"") 284 | 285 | } 286 | 287 | } 288 | } 289 | 290 | } 291 | 292 | func showCmd(argument []string, rawdisk string) { 293 | 294 | var rulesStr string 295 | 296 | switch option := argument[0]; option { 297 | case "-": 298 | for _, elem := range sliceSet { 299 | 300 | fmt.Println("File:" + elem.Rule) 301 | fmt.Println("\tIndex:" + strconv.Itoa(elem.Index)) 302 | fmt.Println("\tOffset Header:" + strconv.Itoa(int(elem.OffsetHeader))) 303 | fmt.Println("\tOffset Footer:" + strconv.Itoa(int(elem.OffsetFooter))) 304 | if len(elem.Yara) > 0 { 305 | for _, elem1 := range elem.Yara { 306 | rulesStr = rulesStr + " " + elem1 307 | } 308 | fmt.Println("\tYara:" + rulesStr) 309 | rulesStr = "" 310 | } 311 | 312 | if len(elem.Ssdeep) > 0 { 313 | fmt.Println("\tSSDeep:" + elem.Ssdeep) 314 | 315 | } 316 | 317 | if len(elem.Hash) > 0 { 318 | fmt.Println("\tHash:" + elem.Hash) 319 | 320 | } 321 | 322 | if len(elem.Comment) > 0 { 323 | fmt.Println("\tComments:" + elem.Comment) 324 | 325 | } 326 | 327 | if elem.OffsetFooter > 0 { 328 | fmt.Println("\tSize:" + strconv.Itoa(int(elem.Size))) 329 | 330 | } 331 | if len(elem.Tag) > 0 { 332 | fmt.Println("\tTag:" + elem.Tag) 333 | 334 | } 335 | if elem.Entropy > 0 { 336 | fmt.Println("\tEntropy:" + strconv.Itoa(int(elem.Entropy))) 337 | 338 | } 339 | fmt.Println("\n") 340 | 341 | } 342 | 343 | case "all": 344 | 345 | for _, elem := range sliceNewResults { 346 | fmt.Println("File:" + elem.Rule) 347 | fmt.Println("\tIndex:" + strconv.Itoa(elem.Index)) 348 | fmt.Println("\tOffset Header:" + strconv.Itoa(int(elem.OffsetHeader))) 349 | fmt.Println("\tOffset Footer:" + strconv.Itoa(int(elem.OffsetFooter))) 350 | if len(elem.Yara) > 0 { 351 | fmt.Println("\tYara:\n") 352 | fmt.Println(elem.Yara) 353 | 354 | } 355 | 356 | if len(elem.Ssdeep) > 0 { 357 | fmt.Println("\tSSDeep:" + elem.Ssdeep) 358 | 359 | } 360 | fmt.Println("\n") 361 | } 362 | 363 | case "support": 364 | if argument[0] == "support" { 365 | fmt.Println("[-]Header Support:") 366 | for _, elem := range headersupport { 367 | fmt.Println("\t" + elem) 368 | } 369 | fmt.Println("\n[-]Footer Support:") 370 | for _, elem2 := range footersupport { 371 | fmt.Println("\t" + elem2) 372 | } 373 | } 374 | case "info": 375 | var allRules string 376 | if debug { 377 | fmt.Println("[*] Into stats") 378 | } 379 | for _, element := range sliceSet { 380 | allRules = allRules + element.Rule + " " 381 | 382 | } 383 | wordCount(allRules) 384 | default: 385 | for _, elem := range sliceSet { 386 | if strings.Contains(elem.Rule, option) { 387 | fmt.Println("File:" + elem.Rule) 388 | fmt.Println("\tIndex:" + strconv.Itoa(elem.Index)) 389 | fmt.Println("\tOffset Header:" + strconv.Itoa(int(elem.OffsetHeader))) 390 | fmt.Println("\tOffset Footer:" + strconv.Itoa(int(elem.OffsetFooter))) 391 | if len(elem.Yara) > 0 { 392 | for _, elem1 := range elem.Yara { 393 | rulesStr = rulesStr + " " + elem1 394 | } 395 | fmt.Println("\tYara:" + rulesStr) 396 | rulesStr = "" 397 | } 398 | 399 | if len(elem.Ssdeep) > 0 { 400 | fmt.Println("\tSSDeep:" + elem.Ssdeep) 401 | 402 | } 403 | 404 | if len(elem.Hash) > 0 { 405 | fmt.Println("\tHash:" + elem.Hash) 406 | 407 | } 408 | 409 | if len(elem.Comment) > 0 { 410 | fmt.Println("\tComments:" + elem.Comment) 411 | 412 | } 413 | 414 | if elem.OffsetFooter > 0 { 415 | fmt.Println("\tSize:" + strconv.Itoa(int(elem.Size))) 416 | 417 | } 418 | fmt.Println("\n") 419 | 420 | } 421 | } 422 | 423 | } 424 | 425 | } 426 | 427 | 428 | func footerCmd(argument []string, rawdisk string) { 429 | 430 | fmt.Println(dataSelected) 431 | 432 | 433 | 434 | } 435 | 436 | 437 | 438 | 439 | func set2Cmd(argument []string, rawdisk string) { 440 | 441 | maxsize64, err := strconv.ParseUint(maxSizeDump, 10, 32) 442 | if err != nil { 443 | print("ERROR: ", err) 444 | } 445 | var resultStruct newResult 446 | supportedFooter := []string{"pdf","jpg","gif","doc", "mft"} 447 | var tmpslice []newResult 448 | if _, err := strconv.Atoi(argument[0]); err == nil { 449 | 450 | for _, elem := range sliceSet{ 451 | if argument[0] == strconv.Itoa(elem.Index) { 452 | tmpslice = append(tmpslice, elem) 453 | 454 | } 455 | } 456 | sliceSet = tmpslice 457 | }else{ 458 | 459 | 460 | 461 | switch option := argument[0]; option { 462 | case "all": 463 | sliceSet = sliceNewResults 464 | case "yara": 465 | setSliceYara(argument[1]) 466 | updateFirstResults() 467 | case "entropy": 468 | setSliceEntropy(argument[1:]) 469 | case "footer": 470 | 471 | if len(argument)<2{ 472 | 473 | flagg := false 474 | if dataSelected == "pe"{ 475 | fmt.Println("[+] Setting a footer for pe") 476 | if len(sliceSet) < 2 { 477 | for _, elem:= range sliceSet{ 478 | fmt.Println(rawdisk) 479 | dumpRadare(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), elem.Rule, strconv.Itoa(elem.Index)) 480 | uniqPE() 481 | updateFirstResults() 482 | 483 | } 484 | } else { 485 | multPE(rawdisk) 486 | } 487 | }else{ 488 | if stringInSlice(dataSelected, supportedFooter){ 489 | footers := findFooter(dataSelected,rawdisk) 490 | for _, elem:= range footers{ 491 | for index2, elem2 := range sliceSet{ 492 | if len(sliceSet)==1{ 493 | if flagg == false{ 494 | if elem.offset > elem2.OffsetHeader{ 495 | resultStruct = newResult{Rule: elem2.Rule, OffsetHeader: elem2.OffsetHeader, OffsetFooter: elem.offset, Data: elem2.Data, Yara: elem2.Yara, Ioc: elem2.Ioc, Index: elem2.Index, Hash: elem2.Hash, Size: elem.offset-elem2.OffsetHeader, Ssdeep: elem2.Ssdeep} 496 | tmpslice = append(tmpslice, resultStruct) 497 | flagg = true 498 | sliceSet = tmpslice 499 | } 500 | 501 | } 502 | }else{ 503 | if index2 < len(sliceSet)-1{ 504 | 505 | if elem.offset > elem2.OffsetHeader && elem.offset 1{ 542 | maxSizeDump = argument[1] 543 | } 544 | default: 545 | dataSelected = argument[0] 546 | setSlice(argument[0]) 547 | } 548 | } 549 | 550 | if len(tmpslice)>1{ 551 | sliceSet = tmpslice 552 | updateFirstResults() 553 | } 554 | 555 | } 556 | 557 | 558 | func outputCmd(argument []string, rawdisk string) { 559 | 560 | OutputFile = argument[0] 561 | 562 | f, err := os.Create(OutputFile) 563 | if err != nil { 564 | panic(err) 565 | } 566 | defer f.Close() 567 | 568 | } 569 | 570 | func hashCmd(argument []string, rawdisk string) { 571 | 572 | var tmpslice []newResult 573 | if len(argument) < 1 { 574 | 575 | for _, elem1 := range sliceSet { 576 | a := getHashSelected(rawdisk, elem1.OffsetHeader, elem1.Size) 577 | 578 | resultStruct := newResult{Rule: elem1.Rule, OffsetHeader: elem1.OffsetHeader, OffsetFooter: elem1.OffsetFooter, Data: elem1.Data, Yara: elem1.Yara, Ioc: elem1.Ioc, Index: elem1.Index, Hash: a, Size: (elem1.OffsetFooter - elem1.OffsetHeader)} 579 | tmpslice = append(tmpslice, resultStruct) 580 | 581 | } 582 | } 583 | sliceSet = tmpslice 584 | updateFirstResults() 585 | 586 | 587 | 588 | } 589 | 590 | func ssdeepCmd(argument []string, rawdisk string) { 591 | var tmpsliceIOC []newResult 592 | 593 | if len(argument) < 1 { 594 | checkSsdeep(rawdisk) 595 | } else { 596 | 597 | for _, elem := range sliceSet { 598 | ssdeep1 := checkEverySsdeep(elem) 599 | 600 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size, Ssdeep: ssdeep1} 601 | 602 | tmpsliceIOC = append(tmpsliceIOC, resultStruct) 603 | } 604 | 605 | sliceSet = tmpsliceIOC 606 | 607 | updateFirstResults() 608 | } 609 | 610 | if len(argument) > 0 { 611 | if argument[0] == "path" { 612 | 613 | path := argument[1] 614 | var _, err = os.Stat(workspace + "/" + argument[1]) 615 | 616 | 617 | if os.IsNotExist(err) { 618 | } else { 619 | files, err := ioutil.ReadDir(path) 620 | if err != nil { 621 | log.Fatal(err) 622 | } 623 | for _, j := range files { 624 | for _, elem2 := range sliceSet { 625 | score := checkSsdeepDistance(elem2.Ssdeep, path+j.Name()) 626 | if score > 20 { 627 | fmt.Println(" [-] Match! - " + j.Name() + " with " + elem2.Rule + "_" + strconv.Itoa(elem2.Index) + " - Score:" + strconv.Itoa(score)) 628 | } 629 | } 630 | } 631 | 632 | 633 | } 634 | } 635 | } 636 | 637 | } 638 | 639 | func entropyCmd2(argument []string, rawdisk string) { 640 | var tmpsliceIOC []newResult 641 | 642 | 643 | for _, elem := range(sliceSet){ 644 | fmt.Println("entrop a") 645 | valueInt := getEntropyValue(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), strconv.Itoa(int(elem.Size))) 646 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size, Ssdeep: elem.Ssdeep, Entropy: valueInt} 647 | tmpsliceIOC = append(tmpsliceIOC, resultStruct) 648 | 649 | } 650 | sliceSet = tmpsliceIOC 651 | updateFirstResults() 652 | } 653 | 654 | 655 | func getEntropyValue(rawdisk string, header string, size string) int64{ 656 | var valueInt int64 657 | 658 | dumpRadare(rawdisk, header, "tmpentropy", "2") 659 | 660 | 661 | r2p, err := r2pipe.NewPipe("./tmpentropy_2") 662 | if err != nil { 663 | print("ERROR: ", err) 664 | } 665 | defer r2p.Close() 666 | 667 | r2p.Cmd("b "+size) 668 | 669 | 670 | disasm, err := r2p.Cmd("p=e") 671 | if err != nil { 672 | print("ERROR: ", err) 673 | } else { 674 | if len(disasm)>1{ 675 | value := strings.Split(disasm, " ")[2] 676 | valueInt, err = strconv.ParseInt(value, 16, 64) 677 | if err != nil { 678 | print("ERROR: ", err) 679 | } 680 | 681 | } 682 | os.Remove(workspace + "/tmpentropy_2") 683 | os.Remove(workspace + "/tmp") 684 | 685 | } 686 | r2p.Close() 687 | return valueInt 688 | 689 | 690 | 691 | 692 | } 693 | 694 | 695 | 696 | 697 | func entropyCmd(argument []string, rawdisk string) { 698 | 699 | r2p, err := r2pipe.NewPipe(rawdisk) 700 | if err != nil { 701 | print("ERROR: ", err) 702 | } 703 | defer r2p.Close() 704 | 705 | disasm, err := r2p.Cmd("b 2000") 706 | if err != nil { 707 | print("ERROR: ", err) 708 | } else { 709 | disasm := "" 710 | print(disasm, "") 711 | } 712 | 713 | disasm, err = r2p.Cmd("p=") 714 | if err != nil { 715 | print("ERROR: ", err) 716 | } else { 717 | disasm := "" 718 | print(disasm, "") 719 | } 720 | 721 | sliceDisas := strings.Split(disasm, "\n") 722 | for _, i := range sliceDisas { 723 | valueprev, err := strconv.ParseUint(strings.Split(i, " ")[2], 16, 64) 724 | if err != nil { 725 | print("ERROR: ", err) 726 | } 727 | 728 | if valueprev > 150 { 729 | fmt.Println("Abnormal value " + strconv.Itoa(int(valueprev)) + " at " + strings.Split(i, " ")[0]) 730 | } 731 | 732 | 733 | 734 | } 735 | 736 | } 737 | 738 | func yaraforensicsCmd(argument []string, rawdisk string) { 739 | 740 | 741 | if _, err := os.Stat( workspace+"/yara-forensics/yara-forensics_index.yar"); err == nil { 742 | 743 | resultsMagic := searchYara(rawdisk, workspace+"/yara-forensics/yara-forensics_index.yar") 744 | 745 | sliceNewResults := generateNewResultYaraForensics(resultsMagic) 746 | 747 | fmt.Println("[+] Calculating data") 748 | var allRules string 749 | for _, element := range sliceNewResults { 750 | allRules = allRules + element.Rule + " " 751 | 752 | } 753 | wordCount(allRules) 754 | sliceSet = sliceNewResults 755 | }else{ 756 | fmt.Println("[-] Please, build an index for rules in /yara-forensics/yara-forensics_index.yar") 757 | } 758 | } 759 | 760 | func runCmd(argument []string, rawdisk string) { 761 | script := argument[0] 762 | 763 | dat, err := ioutil.ReadFile(script) 764 | if err != nil { 765 | panic(err) 766 | } 767 | datSlice := strings.Split(string(dat), "\n") 768 | for _, elem := range datSlice { 769 | 770 | 771 | command := strings.Split(string(elem), " ") 772 | 773 | switch option := command[0]; option { 774 | case "start": 775 | startCmd(command[1:], rawdisk) 776 | 777 | case "set": 778 | set2Cmd(command[1:], rawdisk) 779 | case "yara": 780 | if command[1] == "+" { 781 | yaraCmd(command[1]) 782 | } else { 783 | yaraLightCmd(command[1:], rawdisk) 784 | } 785 | case "hash": 786 | hashCmd(command[1:], rawdisk) 787 | case "ssdeep": 788 | ssdeepCmd(command[1:], rawdisk) 789 | case "save": 790 | saveCmd(command[1:], rawdisk) 791 | case "open": 792 | openCmd(command[1:], rawdisk) 793 | case "ioc": 794 | searchOpenIOCCmd2(rawdisk, command[1]) 795 | case "vti": 796 | vtiCmd(command[1:], rawdisk) 797 | case "~": 798 | radareCmd(command[1:], rawdisk) 799 | case "show": 800 | showCmd(command[1:], rawdisk) 801 | case "unset": 802 | unsetCmd(command[1:], rawdisk) 803 | case "entropy": 804 | entropyCmd2(command[1:], rawdisk) 805 | } 806 | } 807 | 808 | } 809 | 810 | 811 | func yaraCmd(argument string) { 812 | 813 | rawdisk = totrawdisk 814 | var tmpslice []newResult 815 | var rulesIn []string 816 | if _, err := os.Stat(argument); err == nil { 817 | fmt.Println("[+] Deep scanning for match") 818 | 819 | if len(sliceSet) < 2 { 820 | resultsYara := searchYara(rawdisk, argument) 821 | for _, elem := range resultsYara { 822 | fmt.Println("Rule:" + elem.rule) 823 | fmt.Println("Offset:" + strconv.Itoa(int(elem.offset))) 824 | fmt.Println("\n") 825 | updateResultsYara(resultsYara) 826 | updateFirstResults() 827 | } 828 | } else { 829 | 830 | firstRaw := rawdisk 831 | for _, elem := range sliceSet { 832 | rawdisk = firstRaw 833 | if elem.OffsetFooter == 0 { 834 | dumpRadare(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), elem.Rule, strconv.Itoa(elem.Index)) 835 | rawdisk = elem.Rule + "_" + strconv.Itoa(elem.Index) 836 | resultsYara := searchYara(rawdisk, argument) 837 | 838 | 839 | 840 | 841 | rulesIn = elem.Yara 842 | for _, elem1 := range resultsYara { 843 | if stringInSlice(elem1.rule, rulesIn) == false { 844 | 845 | rulesIn = append(rulesIn, elem1.rule) 846 | fmt.Println("\t[-] " + elem1.rule + " at " + elem.Rule + "_" + strconv.Itoa(elem.Index)) 847 | 848 | } 849 | } 850 | 851 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: rulesIn, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size} 852 | tmpslice = append(tmpslice, resultStruct) 853 | rulesIn = nil 854 | 855 | var _, err = os.Stat(workspace + "/" + rawdisk) 856 | 857 | 858 | if os.IsNotExist(err) { 859 | } else { 860 | os.Remove(workspace + "/" + rawdisk) 861 | } 862 | 863 | 864 | 865 | 866 | 867 | } else { 868 | dumpRadareFooter(rawdisk, elem.OffsetHeader, elem.OffsetFooter+uint64(len(elem.Data)), elem.Rule, strconv.Itoa(elem.Index)) 869 | rawdisk = elem.Rule + "_" + strconv.Itoa(elem.Index) 870 | resultsYara := searchYara(rawdisk, argument) 871 | rulesIn = elem.Yara 872 | for _, elem1 := range resultsYara { 873 | if stringInSlice(elem1.rule, rulesIn) == false { 874 | rulesIn = append(rulesIn, elem1.rule) 875 | 876 | } 877 | } 878 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: rulesIn, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size} 879 | tmpslice = append(tmpslice, resultStruct) 880 | rulesIn = nil 881 | 882 | } 883 | 884 | err := os.Remove(workspace + "/" + rawdisk) 885 | if err != nil { 886 | 887 | } 888 | 889 | } 890 | sliceSet = tmpslice 891 | } 892 | 893 | 894 | 895 | 896 | 897 | updateFirstResults() 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | } else { 918 | fmt.Println("Yara rule does not exist") 919 | } 920 | } 921 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 2 | # YaraRET 3 | 4 | # Introduction 5 | 6 | YaraRET is a carving tool based in Radare2 and Yara and written in Go. It provides 58 magic number's yara rules for detecting 58 types of files. 7 | 8 | This tool is based on the idea of a first stage detecting files using its magic numbers and a second stage, selecting or discarding those detected files using Yara, IoC or its entropy value. 9 | After that, it is able to generate the hash, the ssdeep (and check it over anothers). 10 | Also provides an integration with VirusTotal. 11 | 12 | 13 | In order to deal with forensics cases based on weak clues, YaraRET provides different modes for raw disk handling. 14 | 15 | 16 | 17 | # Install 18 | 19 | For a compiled bin, you can download last release from Github. 20 | 21 | Also, you can download git repo and build it. 22 | 23 | #### Dependencies 24 | 25 | Yara 26 | Radare2 27 | 28 | github.com/abiosoft/ishell 29 | github.com/docopt/docopt-go 30 | github.com/glaslos/ssdeep 31 | github.com/hillu/go-yara 32 | github.com/radare/r2pipe-go 33 | github.com/williballenthin/govt 34 | 35 | 36 | 37 | 38 | 39 | # Usage 40 | 41 | YaraRET provides diferent modes for handling different forensics cases. 42 | 43 | If you are interested in get a file from a yara rule, you can execute the following command: 44 | 45 | 46 | 47 | $ ./yaraRET yara myYaraRule rawdisk myRaw maxsize 3000 48 | 49 | 50 | 51 | If you are interested in get a file from an IoC like a domain or hash from any kind of file like STIX or txt 52 | 53 | $ ./yaraRET ioc ./myIOC.stix rawdisk myRaw maxsize 3000 54 | 55 | 56 | 57 | 58 | For a complex analysis, YaraRET provides a shell mode which allows an analysis at the tool's opening 59 | 60 | $ ./yaraRET rawdisk myRaw shell 61 | 62 | 63 | >> start all 64 | >> set pe 65 | >> show - 66 | 67 | 68 | # Features 69 | 70 | - Radare2 integration 71 | - SSdeep distance checking 72 | - VirusTotal API integration 73 | - Scripting 74 | - YaraForensics Ruleset 75 | - Entropy 76 | - Boot Sector analysis 77 | 78 | 79 | This tool was introduced in this talk at r2con 2018 80 | 81 | - https://www.youtube.com/watch?v=trLVw9J-mfw 82 | 83 | - https://github.com/radareorg/r2con2018/blob/master/talks/08-YaraRET/NotAnotherRET.pdf 84 | 85 | -------------------------------------------------------------------------------- /docs/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: YaraRET Documentation 2 | strict: false 3 | theme: readthedocs 4 | docs_dir: './docs' 5 | pages: 6 | - Home: 7 | - Index: './index.md' 8 | - Command Reference: './readTheDocs.md' 9 | -------------------------------------------------------------------------------- /docs/readTheDocs.md: -------------------------------------------------------------------------------- 1 | 2 | start all: YaraRET looks for all headers in YaraRET 3 | 4 | start {file type}: Only initialize the specified file type 5 | 6 | - Supported headers 7 | ``` 8 | 9 | threegp sevenzip amazonkindleupdate 10 | appleworks5 appleworks6 avi 11 | bmp bzip canonraw 12 | crx dalvik dat 13 | dba deb dmg 14 | doc elf64 flac 15 | flash gif gzip 16 | is javaclass jpg 17 | kodakcineon macho microsoftOffice 18 | midi mkv mp3 19 | mpeg ost pcap 20 | pcapng pdf pe 21 | png pds pst 22 | pyc rar rpm 23 | rtf tape tar 24 | tarzip tiff utf8 25 | vmdk wasm wav 26 | woff xar xml 27 | xz zip zlib 28 | 29 | 30 | ``` 31 | 32 | 33 | 34 | ``` 35 | yara {yaraFile}: Run yara over the selected structures. 36 | ``` 37 | ``` 38 | ioc {iocFile}: Run any kind of IoC over selected structures. 39 | ``` 40 | ``` 41 | hash: Get the hash of selected structures. 42 | ``` 43 | ``` 44 | dump: Exports selected structures. 45 | ``` 46 | ``` 47 | save: Saves all obtained information in a json. 48 | ``` 49 | ``` 50 | open: Opens saved information 51 | ``` 52 | ``` 53 | show: Puts in the screen all selected structures 54 | ``` 55 | ``` 56 | tag: Command for adding information in the structure. 57 | ``` 58 | ``` 59 | yaraforensics: YaraRET runs the ruleset of Yara Forensics repository. 60 | ``` 61 | ``` 62 | ~ {radareCommand}: Runs radare command over selected structure. 63 | ``` 64 | ``` 65 | vti key: Command for putting the VirusTotal API Key 66 | ``` 67 | ``` 68 | vti scan: Uploads selected structure to VirusTotal 69 | ``` 70 | ``` 71 | vti report: Checks the hash to VirusTotal 72 | ``` 73 | ``` 74 | ssdeep: Calculates the ssdeep value for selected structure. 75 | ``` 76 | ``` 77 | ssdeep path {pathOfFiles} : Checks ssdeep of selected structures with all ssdeeps 78 | ``` 79 | ``` 80 | run {script}: YaraRET allows running commands written in a simple text file. It helps when you know that analysis is going to take too much time. 81 | ``` 82 | ``` 83 | entropy: Calculate the entropy of selected structures. 84 | ``` 85 | ``` 86 | upload: YaraRET sends the selected structure to specified server. 87 | ``` 88 | ``` 89 | set {file type}: In case that all data had been initialized, this command selects only one type of files for running nexts commands. 90 | ``` 91 | ``` 92 | set footer: In case that our file type has a footer in its structure YaraRET will find the end of the file and the size. If doesn’t have a footer YaraRET will take the specified maximum size. 93 | Special case with PE format, which is calculated with binary header. 94 | ``` 95 | - Supported footers 96 | 97 | ``` 98 | pdf jpg 99 | gif doc 100 | mft 101 | ``` 102 | 103 | ``` 104 | set footer generic: If we don’t want to spend so much time calculating the real footer of the file, we can run this command for selecting the specified maximum size. It’s a good option if we don’t have any idea of what we are looking for. 105 | ``` 106 | 107 | 108 | ``` 109 | set yara {rule}: Selects the structures which have matched with specified rule 110 | ``` 111 | ``` 112 | set ioc {ioc}: Selects the structures which have matched with specified ioc 113 | ``` 114 | ``` 115 | set entropy < | >: Selects the structures which were greater or lesser than specified value 116 | ``` 117 | ``` 118 | var {globalVariable} : Change the value of global variables. 119 | ``` 120 | ``` 121 | var maxsize {value}: Changes the value of the maxsize used in footer finding. 122 | ``` 123 | ``` 124 | var history: After this command, every command is going to be saved in a file. Very useful if this 125 | ``` 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /finding.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | 22 | 23 | package main 24 | 25 | import ( 26 | "fmt" 27 | // "fmt" 28 | // // "encoding/gob" 29 | yara "github.com/hillu/go-yara" 30 | // // "net" 31 | // "github.com/radare/r2pipe-go" 32 | // "net/url" 33 | // "flag" 34 | // "encoding/json" 35 | // "log" 36 | // "github.com/dutchcoders/go-virustotal" 37 | // "io/ioutil" 38 | //"strconv" 39 | // "strings" 40 | // "os" 41 | ) 42 | 43 | func findAllData(rawdisk string)[]result{ 44 | 45 | 46 | var v []result 47 | 48 | supported := []string{"threegp","sevenzip","amazonkindleupdate","appleworks5","appleworks6","avi","bmp","bzip","canonraw","crx","dalvik","dat","dba","deb","dmg","doc","elf64","flac","flash","gif","gzip","is","javaclass","jpg","kodakcineon","macho","microsoftOffice","midi","mkv","mp3","mpeg","ost","pcap","pcapng","pdf","pe","png","pds","pst","pyc","rar","rpm","rtf","tape","tar","tarzip","tiff","utf8","vmdk","wasm","wav","woff","xar","xml","xz","zip","zlib"} 49 | 50 | 51 | for _, elem1 := range supported{ 52 | //count := count+1 53 | comp, err := yara.NewCompiler() 54 | if err != nil { 55 | fmt.Println(err) 56 | } 57 | body := returnBody(elem1) 58 | condition := returnConditionOnly() 59 | rule := body+condition 60 | //rule := buildRule("0", "0", elem1) 61 | comp.AddString(rule, "") 62 | //fmt.Println(rule) 63 | rules, err := comp.GetRules() 64 | if err != nil { 65 | fmt.Println(err) 66 | } 67 | matches, err := rules.ScanFile(rawdisk, 0, 0) 68 | for _, matches := range matches { 69 | for _, stringf := range matches.Strings { 70 | s := result{rule: matches.Rule, offset: stringf.Offset, Data: stringf.Data} 71 | v = append(v, s) 72 | //fmt.Println(s) 73 | //fmt.Println("[+] Match! "+s.rule) 74 | } 75 | } 76 | } 77 | //fmt.Println(v) 78 | return v 79 | } 80 | 81 | func findOneData(rawdisk string, filetype string)[]result{ 82 | 83 | //for initialize only one filetype 84 | var v []result 85 | 86 | 87 | 88 | comp, err := yara.NewCompiler() 89 | if err != nil { 90 | fmt.Println(err) 91 | } 92 | body := returnBody(filetype) 93 | 94 | condition := returnConditionOnly() 95 | rule := body+condition 96 | //rule := buildRule("0", "0", elem1) 97 | comp.AddString(rule, "") 98 | //fmt.Println(rule) 99 | rules, err := comp.GetRules() 100 | if err != nil { 101 | fmt.Println(err) 102 | } 103 | matches, err := rules.ScanFile(rawdisk, 0, 0) 104 | for _, matches := range matches { 105 | for _, stringf := range matches.Strings { 106 | s := result{rule: matches.Rule, offset: stringf.Offset, Data: stringf.Data} 107 | v = append(v, s) 108 | //fmt.Println(s) 109 | //fmt.Println("[+] Match! "+s.rule) 110 | } 111 | } 112 | //fmt.Println(v) 113 | return v 114 | } 115 | 116 | 117 | 118 | 119 | 120 | func returnConditionOnly()string{ 121 | condition :=`condition: 122 | $a 123 | } 124 | ` 125 | return condition 126 | } -------------------------------------------------------------------------------- /iocs.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | 22 | 23 | package main 24 | 25 | import ( 26 | "fmt" 27 | // "encoding/gob" 28 | // "net" 29 | "bufio" 30 | "github.com/radare/r2pipe-go" 31 | "log" 32 | "os" 33 | "regexp" 34 | "strconv" 35 | ) 36 | 37 | func searchOpenIOCCmd2(rawdisk string, openioc string){ 38 | var tmpsliceIOC []newResult 39 | 40 | var ips []string 41 | var domains []string 42 | var index int 43 | //var rule string 44 | 45 | ips = parseIP(openioc) 46 | 47 | 48 | f, err := os.Create(workspace + "/rule_openioc.yar") 49 | if err != nil { 50 | panic(err) 51 | } 52 | defer f.Close() 53 | for _, elem := range ips { 54 | index = index + 1 55 | 56 | file, err := os.OpenFile(workspace+"/rule_openioc.yar", os.O_WRONLY|os.O_APPEND, 0644) 57 | if err != nil { 58 | log.Fatalf("failed opening file: %s", err) 59 | } 60 | defer file.Close() 61 | 62 | len, err := file.WriteString("rule ip_" + strconv.Itoa(index) + ": IP\n{\n\tmeta:\n\t\tauthor = \"Joan Soriano\"\n\n\tstrings:\n\t\t$a = \"" + elem + "\"\n\n\tcondition:\n\t\t$a\n} ") 63 | if err != nil { 64 | log.Fatalf("failed writing to file: %s", err) 65 | fmt.Println(len) 66 | } 67 | 68 | iocStruct := ioc{rule: "ip_" + strconv.Itoa(index), Data: elem, OffsetHeader: 0, match: false, indexMatch: 0, domain: false} 69 | sliceIOC = append(sliceIOC, iocStruct) 70 | 71 | } 72 | 73 | domains = parseDomains(openioc) 74 | 75 | 76 | for _, elem := range domains { 77 | index = index + 1 78 | 79 | file, err := os.OpenFile(workspace+"/rule_openioc.yar", os.O_WRONLY|os.O_APPEND, 0644) 80 | if err != nil { 81 | log.Fatalf("failed opening file: %s", err) 82 | } 83 | defer file.Close() 84 | 85 | len, err := file.WriteString("rule domain_" + strconv.Itoa(index) + ": DOMAIN\n{\n\tmeta:\n\t\tauthor = \"Joan Soriano\"\n\n\tstrings:\n\t\t$a = \"" + elem + "\"\n\n\tcondition:\n\t\t$a\n} ") 86 | if err != nil { 87 | log.Fatalf("failed writing to file: %s", err) 88 | fmt.Println(len) 89 | } 90 | 91 | iocStruct := ioc{rule: "domain_" + strconv.Itoa(index), Data: elem, OffsetHeader: 0, match: false, indexMatch: 0, domain: true} 92 | sliceIOC = append(sliceIOC, iocStruct) 93 | } 94 | 95 | 96 | 97 | resultsToT := searchYara(rawdisk, "./rule_openioc.yar") 98 | fmt.Println("[+] " + strconv.Itoa(len(resultsToT)) + " match found") 99 | 100 | 101 | for _, elem:= range sliceSet{ 102 | flagg := false 103 | for _, elem2 := range resultsToT{ 104 | if elem2.offset < elem.OffsetFooter && elem2.offset > elem.OffsetHeader{ 105 | fmt.Println("[+] Match "+string(elem2.Data)+" in "+elem.Rule+"_"+strconv.Itoa(elem.Index)) 106 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: string(elem.Data[:]), Index: elem.Index, Hash: elem.Hash, Size: elem.Size} 107 | tmpsliceIOC = append(tmpsliceIOC, resultStruct) 108 | flagg = true 109 | } 110 | if flagg == false{ 111 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size} 112 | tmpsliceIOC = append(tmpsliceIOC, resultStruct) 113 | } 114 | } 115 | } 116 | sliceSet = tmpsliceIOC 117 | 118 | 119 | } 120 | 121 | 122 | func searchOpenIOCCmd(rawdisk string, openioc string, maxsize string, filetype string) { 123 | var ips []string 124 | var domains []string 125 | var index int 126 | //var rule string 127 | //var mylastheader uint64 128 | 129 | ips = parseIP(openioc) 130 | 131 | if xor == true { 132 | ips = appendXORioc(ips) 133 | } 134 | f, err := os.Create(workspace + "/rule_openioc.yar") 135 | if err != nil { 136 | panic(err) 137 | } 138 | defer f.Close() 139 | for _, elem := range ips { 140 | index = index + 1 141 | 142 | file, err := os.OpenFile(workspace+"/rule_openioc.yar", os.O_WRONLY|os.O_APPEND, 0644) 143 | if err != nil { 144 | log.Fatalf("failed opening file: %s", err) 145 | } 146 | defer file.Close() 147 | 148 | len, err := file.WriteString("rule ip_" + strconv.Itoa(index) + ": IP\n{\n\tmeta:\n\t\tauthor = \"Joan Soriano\"\n\n\tstrings:\n\t\t$a = \"" + elem + "\"\n\n\tcondition:\n\t\t$a\n} ") 149 | if err != nil { 150 | log.Fatalf("failed writing to file: %s", err) 151 | fmt.Println(len) 152 | } 153 | 154 | iocStruct := ioc{rule: "ip_" + strconv.Itoa(index), Data: elem, OffsetHeader: 0, match: false, indexMatch: 0, domain: false} 155 | sliceIOC = append(sliceIOC, iocStruct) 156 | 157 | } 158 | 159 | domains = parseDomains(openioc) 160 | if xor == true { 161 | domains = appendXORioc(domains) 162 | } 163 | 164 | for _, elem := range domains { 165 | index = index + 1 166 | 167 | file, err := os.OpenFile(workspace+"/rule_openioc.yar", os.O_WRONLY|os.O_APPEND, 0644) 168 | if err != nil { 169 | log.Fatalf("failed opening file: %s", err) 170 | } 171 | defer file.Close() 172 | 173 | len, err := file.WriteString("rule domain_" + strconv.Itoa(index) + ": DOMAIN\n{\n\tmeta:\n\t\tauthor = \"Joan Soriano\"\n\n\tstrings:\n\t\t$a = \"" + elem + "\"\n\n\tcondition:\n\t\t$a\n} ") 174 | if err != nil { 175 | log.Fatalf("failed writing to file: %s", err) 176 | fmt.Println(len) 177 | } 178 | 179 | iocStruct := ioc{rule: "domain_" + strconv.Itoa(index), Data: elem, OffsetHeader: 0, match: false, indexMatch: 0, domain: true} 180 | sliceIOC = append(sliceIOC, iocStruct) 181 | } 182 | 183 | 184 | 185 | extractFromYara(rawdisk, "./rule_openioc.yar", maxsize, filetype) 186 | 187 | } 188 | 189 | func printSliceIOC(matchIOC []result) { 190 | 191 | for _, elem := range matchIOC { 192 | 193 | fmt.Println("[+] Match!") 194 | fmt.Println("\t[-] File:" + elem.rule) 195 | fmt.Println("\t[-] IoC:" + string(elem.Data[:])) 196 | fmt.Println("\t[-] Offset:" + strconv.Itoa(int(elem.offset)) + "\n") 197 | 198 | } 199 | } 200 | 201 | func updateMatchIOC(resultsIOC []result) { 202 | 203 | //sliceIOC = [] 204 | var tmpsliceIOC []ioc 205 | 206 | //tmpsliceIOC := sliceIOC 207 | //fmt.Println(resultsIOC) 208 | //fmt.Println(sliceIOC) 209 | //sliceIOC = nil 210 | 211 | for _, elem := range resultsIOC { 212 | for _, elem1 := range sliceIOC { 213 | if elem.rule == elem1.rule { 214 | //fmt.Println("hiii") 215 | iocStruct := ioc{rule: elem1.rule, Data: elem1.Data, OffsetHeader: elem.offset, match: true, indexMatch: 1, domain: elem1.domain} 216 | //fmt.Println(iocStruct) 217 | tmpsliceIOC = append(tmpsliceIOC, iocStruct) 218 | } 219 | } 220 | } 221 | sliceIOC = tmpsliceIOC 222 | //fmt.Println(sliceIOC) 223 | 224 | } 225 | 226 | func updateResultsIOC() { 227 | 228 | //sliceIOC = [] 229 | var tmpsliceIOC []newResult 230 | //fmt.Print(sliceNewResults) 231 | //fmt.Println(sliceIOC) 232 | //tmpsliceIOC := sliceIOC 233 | //fmt.Println(resultsIOC) 234 | //fmt.Println(sliceIOC) 235 | //sliceIOC = nil 236 | 237 | for _, elem := range sliceIOC { 238 | for _, elem1 := range sliceNewResults { 239 | if elem.OffsetHeader > elem1.OffsetHeader && elem.OffsetHeader < elem1.OffsetFooter { 240 | resultStruct := newResult{Rule: elem1.Rule, OffsetHeader: elem1.OffsetHeader, OffsetFooter: elem1.OffsetFooter, Data: elem1.Data, Yara: elem1.Yara, Ioc: elem.Data, Index: elem1.Index, Hash: elem1.Hash, Size: elem1.Size} 241 | tmpsliceIOC = append(tmpsliceIOC, resultStruct) 242 | } 243 | } 244 | } 245 | 246 | //printStructure(sliceNewResults) 247 | //fmt.Println(sliceNewResults) 248 | 249 | } 250 | 251 | func parseIP(openioc string) []string { 252 | 253 | var ips []string 254 | 255 | regex := regexp.MustCompile(`(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}`) 256 | 257 | //fmt.Printf("Pattern: %v\n", re.String()) // print pattern 258 | //fmt.Println(re.MatchString(str1)) // true 259 | 260 | // submatchall := re.FindAllString(str1, -1) 261 | // for _, element := range submatchall { 262 | // fmt.Println(element) 263 | // } 264 | 265 | file, err := os.Open(openioc) 266 | if err != nil { 267 | fmt.Println(err) 268 | } 269 | defer file.Close() 270 | 271 | scanner := bufio.NewScanner(file) 272 | scanner.Split(bufio.ScanLines) 273 | 274 | // This is our buffer now 275 | var lines []string 276 | 277 | for scanner.Scan() { 278 | lines = append(lines, scanner.Text()) 279 | } 280 | 281 | //fmt.Println("read lines:") 282 | for _, line := range lines { 283 | if regex.MatchString(line) { 284 | submatchall := regex.FindAllString(line, -1) 285 | for _, element := range submatchall { 286 | //fmt.Println(element) 287 | ips = append(ips, element) 288 | //fmt.Printf("%s\n", string(buf)) 289 | } 290 | } 291 | //fmt.Println(line) 292 | } 293 | 294 | // fh, err := os.Open(file) 295 | // f := bufio.NewReader(fh) 296 | 297 | // if err != nil { 298 | // fmt.Print("error") 299 | // } 300 | // defer fh.Close() 301 | 302 | // buf := make([]byte, 1024) 303 | // for { 304 | // buf, _ , err = f.ReadLine() 305 | // if err != nil { 306 | // fmt.Print("error") 307 | // } 308 | 309 | // s := string(buf) 310 | // if regex.MatchString(s) { 311 | // ips = append(ips,s) 312 | // fmt.Printf("%s\n", string(buf)) 313 | // } 314 | // } 315 | //var ips = []string{"pe","elf64"} 316 | //fmt.Println(ips) 317 | return ips 318 | } 319 | 320 | func parseDomains(openioc string) []string { 321 | 322 | var domains []string 323 | 324 | regex := regexp.MustCompile(`^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z 325 | ]{2,3})$`) 326 | 327 | //fmt.Printf("Pattern: %v\n", re.String()) // print pattern 328 | //fmt.Println(re.MatchString(str1)) // true 329 | 330 | // submatchall := re.FindAllString(str1, -1) 331 | // for _, element := range submatchall { 332 | // fmt.Println(element) 333 | // } 334 | 335 | file, err := os.Open(openioc) 336 | if err != nil { 337 | fmt.Println(err) 338 | } 339 | defer file.Close() 340 | 341 | scanner := bufio.NewScanner(file) 342 | scanner.Split(bufio.ScanLines) 343 | 344 | // This is our buffer now 345 | var lines []string 346 | 347 | for scanner.Scan() { 348 | lines = append(lines, scanner.Text()) 349 | } 350 | 351 | //fmt.Println("read lines:") 352 | for _, line := range lines { 353 | if regex.MatchString(line) { 354 | submatchall := regex.FindAllString(line, -1) 355 | for _, element := range submatchall { 356 | //fmt.Println(element) 357 | domains = append(domains, element) 358 | //fmt.Printf("%s\n", string(buf)) 359 | } 360 | } 361 | //fmt.Println(line) 362 | } 363 | 364 | // fh, err := os.Open(file) 365 | // f := bufio.NewReader(fh) 366 | 367 | // if err != nil { 368 | // fmt.Print("error") 369 | // } 370 | // defer fh.Close() 371 | 372 | // buf := make([]byte, 1024) 373 | // for { 374 | // buf, _ , err = f.ReadLine() 375 | // if err != nil { 376 | // fmt.Print("error") 377 | // } 378 | 379 | // s := string(buf) 380 | // if regex.MatchString(s) { 381 | // ips = append(ips,s) 382 | // fmt.Printf("%s\n", string(buf)) 383 | // } 384 | // } 385 | //var ips = []string{"pe","elf64"} 386 | //fmt.Println(ips) 387 | return domains 388 | } 389 | 390 | func appendXORioc(ioc []string) []string { 391 | 392 | var tmpXor []string 393 | 394 | for _, elem := range ioc { 395 | 396 | r2p, err := r2pipe.NewPipe("-") 397 | if err != nil { 398 | print("ERROR: ", err) 399 | } 400 | defer r2p.Close() 401 | 402 | disasm, err := r2p.Cmd("oo+") 403 | if err != nil { 404 | print("ERROR: ", err) 405 | } else { 406 | print(disasm, "") 407 | } 408 | 409 | disasm, err = r2p.Cmd("w " + elem) 410 | if err != nil { 411 | print("ERROR: ", err) 412 | } else { 413 | print(disasm, "") 414 | } 415 | 416 | disasm, err = r2p.Cmd("b " + strconv.Itoa(len(elem))) 417 | if err != nil { 418 | print("ERROR: ", err) 419 | } else { 420 | print(disasm, "") 421 | } 422 | 423 | for i := 1; i < 90; i++ { 424 | if i < 10 { 425 | disasm, err = r2p.Cmd("wox 0x0" + strconv.Itoa(i)) 426 | if err != nil { 427 | print("ERROR: ", err) 428 | } else { 429 | print(disasm, "") 430 | } 431 | 432 | } else { 433 | disasm, err = r2p.Cmd("wox 0x" + strconv.Itoa(i)) 434 | if err != nil { 435 | print("ERROR: ", err) 436 | } else { 437 | print(disasm, "") 438 | } 439 | } 440 | 441 | disasm2, err := r2p.Cmd("ps") 442 | if err != nil { 443 | print("ERROR: ", err) 444 | } else { 445 | print(disasm, "") 446 | } 447 | if stringInSlice(disasm2, tmpXor) == false { 448 | if len(disasm2) == len(elem) { 449 | tmpXor = append(tmpXor, disasm2) 450 | } 451 | } 452 | 453 | } 454 | 455 | } 456 | 457 | for _, elem := range tmpXor { 458 | ioc = append(ioc, elem) 459 | } 460 | 461 | return ioc 462 | } 463 | -------------------------------------------------------------------------------- /magicRules.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | 22 | 23 | package main 24 | 25 | import ( 26 | yara "github.com/hillu/go-yara" 27 | "fmt" 28 | "strings" 29 | "os" 30 | "sort" 31 | "log" 32 | 33 | ) 34 | 35 | 36 | type fileDump struct{ 37 | offsetHeader uint64 38 | offsetFooter uint64 39 | filetype string 40 | rule string 41 | data []byte 42 | } 43 | 44 | 45 | type result struct { 46 | rule string 47 | offset uint64 48 | Data []byte 49 | } 50 | 51 | type offsetSorter []result 52 | 53 | func (a offsetSorter) Len() int { return len(a) } 54 | func (a offsetSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 55 | func (a offsetSorter) Less(i, j int) bool { return a[i].offset < a[j].offset } 56 | 57 | 58 | 59 | func stringInSlice(a string, list []string) bool { 60 | for _, b := range list { 61 | if b == a { 62 | return true 63 | } 64 | } 65 | return false 66 | } 67 | 68 | 69 | func yaraStage2(rawdisk string, yarafile string) []result{ 70 | 71 | var v []result 72 | 73 | comp, err := yara.NewCompiler() 74 | rules, err := comp.GetRules() 75 | if err != nil { 76 | fmt.Println(err) 77 | } 78 | matches, err := rules.ScanFile(rawdisk, 0, 0) 79 | if err != nil { 80 | fmt.Println(err) 81 | } 82 | 83 | for _, matches := range matches { 84 | for _, stringf := range matches.Strings { 85 | s := result{rule: matches.Rule, offset: stringf.Offset, Data: stringf.Data} 86 | v = append(v, s) 87 | } 88 | } 89 | sort.Sort(offsetSorter(v)) 90 | return v 91 | } 92 | 93 | 94 | 95 | 96 | 97 | 98 | func yaraStage1(rawdisk string, yarafile string) []result{ 99 | 100 | var v []result 101 | comp, err := yara.NewCompiler() 102 | f, err := os.Open(yarafile) 103 | if err != nil { 104 | log.Fatalf("Could not open rule file: %s", err) 105 | } 106 | comp.AddFile(f, "") 107 | rules, err := comp.GetRules() 108 | if err != nil { 109 | fmt.Println(err) 110 | } 111 | 112 | matches, err := rules.ScanFile(rawdisk, 0, 0) 113 | if err != nil { 114 | fmt.Println(err) 115 | } 116 | 117 | for _, matches := range matches { 118 | for _, stringf := range matches.Strings { 119 | s := result{rule: matches.Rule, offset: stringf.Offset, Data: stringf.Data} 120 | v = append(v, s) 121 | } 122 | } 123 | sort.Sort(offsetSorter(v)) 124 | return v 125 | 126 | } 127 | 128 | 129 | func findFooter(filetype string, rawdisk string) []result{ 130 | var v []result 131 | comp, err := yara.NewCompiler() 132 | if err != nil { 133 | fmt.Println(err) 134 | } 135 | rule := buildRuleAny(filetype) 136 | comp.AddString(rule, "") 137 | //fmt.Println(rule) 138 | rules, err := comp.GetRules() 139 | if err != nil { 140 | fmt.Println(err) 141 | } 142 | matches, err := rules.ScanFile(rawdisk, 0, 0) 143 | 144 | for _, matches := range matches { 145 | for _, stringf := range matches.Strings { 146 | s := result{rule: matches.Rule, offset: stringf.Offset, Data: stringf.Data} 147 | v = append(v, s) 148 | } 149 | } 150 | sort.Sort(offsetSorter(v)) 151 | return v 152 | } 153 | 154 | 155 | 156 | func buildRuleAny(filetype string) string{ 157 | body := returnBodyFooter(filetype) 158 | //body1 := strings.Replace(body,"COUNT",strconv.Itoa(count),-1) 159 | //fmt.Println(body1) 160 | condition := returnConditionAny() 161 | //fmt.Println(condition) 162 | rule := body+condition 163 | 164 | return rule 165 | 166 | } 167 | 168 | 169 | 170 | 171 | 172 | func buildRule(offset1 string, offset2 string, filetype string) string{ 173 | body := returnBody(filetype) 174 | //body1 := strings.Replace(body,"COUNT",strconv.Itoa(count),-1) 175 | //fmt.Println(body1) 176 | condition := returnCondition(offset1, offset2) 177 | //fmt.Println(condition) 178 | rule := body+condition 179 | 180 | return rule 181 | 182 | } 183 | 184 | 185 | func returnCondition(offset1 string, offset2 string)string{ 186 | 187 | condition :=`condition: 188 | $a in (OFFSET1..OFFSET2) 189 | } 190 | ` 191 | condition1 := strings.Replace(condition, "OFFSET1", offset1, -1) 192 | condition2 := strings.Replace(condition1, "OFFSET2", offset2, -1) 193 | return condition2 194 | } 195 | 196 | 197 | func returnConditionAny() string{ 198 | 199 | condition :=`condition: 200 | $a 201 | } 202 | ` 203 | return condition 204 | } 205 | 206 | 207 | 208 | func returnBody(type1 string)string{ 209 | 210 | var body string 211 | 212 | switch option := type1; option { 213 | 214 | case "threegp": 215 | 216 | body=`rule threegp_header_COUNT: THREEGP 217 | { 218 | meta: 219 | author = "Joan Soriano" 220 | 221 | strings: 222 | 223 | $a = {66 74 79 70 33 67} 224 | 225 | 226 | ` 227 | 228 | 229 | case "sevenzip": 230 | 231 | body=`rule sevenzip_header_COUNT: SEVENZIP 232 | { 233 | meta: 234 | author = "Joan Soriano" 235 | 236 | strings: 237 | 238 | $a = {37 7A BC AF 27 1C} 239 | 240 | 241 | ` 242 | 243 | 244 | case "amazonkindleupdate": 245 | 246 | body=`rule amazonkindleupdate_header_COUNT: AMAZONBIN 247 | { 248 | meta: 249 | author = "Joan Soriano" 250 | 251 | strings: 252 | 253 | $a = {53 50 30 31} 254 | 255 | 256 | 257 | ` 258 | 259 | 260 | 261 | case "appleworks5": 262 | 263 | body=`rule appleworks5_header_COUNT: APPLEWORKS5 264 | { 265 | meta: 266 | author = "Joan Soriano" 267 | 268 | strings: 269 | 270 | $a = {05 07 00 00 42 4F 42 4F} 271 | 272 | 273 | 274 | ` 275 | 276 | 277 | 278 | case "appleworks6": 279 | 280 | body=`rule appleworks6_header_COUNT: APPLEWORKS6 281 | { 282 | meta: 283 | author = "Joan Soriano" 284 | 285 | strings: 286 | 287 | $a = {06 07 E1 00 42 4F 42 4F} 288 | 289 | 290 | 291 | ` 292 | 293 | 294 | 295 | case "avi": 296 | 297 | body=`rule avi_header_COUNT: AVI 298 | { 299 | meta: 300 | author = "Joan Soriano" 301 | 302 | strings: 303 | 304 | $a = {52 49 46 46 ?? ?? ?? ?? 41 56 49 20} 305 | 306 | 307 | ` 308 | 309 | 310 | 311 | case "bmp": 312 | 313 | body=`rule bmp_header_COUNT: BMP 314 | { 315 | meta: 316 | author = "Joan Soriano" 317 | 318 | strings: 319 | 320 | $a = {42 4D ?? ?? ?? 00 } 321 | 322 | 323 | 324 | ` 325 | 326 | 327 | 328 | case "bzip": 329 | 330 | body=`rule bzip_header_COUNT: BZIP 331 | { 332 | meta: 333 | author = "Joan Soriano" 334 | 335 | strings: 336 | 337 | $a = {42 5A 68} 338 | 339 | 340 | 341 | ` 342 | 343 | 344 | 345 | case "canonraw": 346 | 347 | body=`rule canonraw_header_COUNT: CANONRAW 348 | { 349 | meta: 350 | author = "Joan Soriano" 351 | 352 | strings: 353 | 354 | $a = {49 49 2A 00 10 00 00 00} 355 | 356 | 357 | ` 358 | 359 | 360 | 361 | case "crx": 362 | 363 | body=`rule crx_header_COUNT: CRX 364 | { 365 | meta: 366 | author = "Joan Soriano" 367 | 368 | strings: 369 | 370 | $a = {05 07 00 00 42 4F 42 4F} 371 | 372 | 373 | 374 | ` 375 | 376 | 377 | 378 | case "dalvik": 379 | 380 | body=`rule dalvik_header_COUNT: DALVIK 381 | { 382 | meta: 383 | author = "Joan Soriano" 384 | 385 | strings: 386 | 387 | $a = {64 65 78 0A 30 33 35 00} 388 | 389 | 390 | ` 391 | 392 | 393 | 394 | case "dat": 395 | 396 | body=`rule dat_header_COUNT: DAT 397 | { 398 | meta: 399 | author = "Joan Soriano" 400 | 401 | strings: 402 | 403 | $a = {50 4D 4F 43 43 4D 4F 43} 404 | 405 | 406 | 407 | ` 408 | 409 | 410 | case "dba": 411 | 412 | body=`rule dba_header_COUNT: PALMDESKTOP 413 | { 414 | meta: 415 | author = "Joan Soriano" 416 | 417 | strings: 418 | 419 | $a = {BE BA FE CA} 420 | 421 | 422 | 423 | 424 | ` 425 | 426 | 427 | 428 | case "deb": 429 | 430 | body=`rule deb_header_COUNT: DEB 431 | { 432 | meta: 433 | author = "Joan Soriano" 434 | 435 | strings: 436 | 437 | $a = {21 3C 61 72 63 68 3E} 438 | 439 | 440 | 441 | ` 442 | 443 | 444 | 445 | case "dmg": 446 | 447 | body=`rule dmg_header_COUNT: DMG 448 | { 449 | meta: 450 | author = "Joan Soriano" 451 | 452 | strings: 453 | 454 | $a = {78 01 73 0D 62 62 60} 455 | 456 | 457 | 458 | ` 459 | 460 | 461 | case "doc": 462 | 463 | body=`rule doc_header_COUNT: DOC 464 | { 465 | meta: 466 | author = "Joan Soriano" 467 | 468 | strings: 469 | 470 | $a = {d0 cf 11 e0 a1 b1 1a e1 00 00} 471 | 472 | 473 | 474 | ` 475 | 476 | 477 | 478 | case "elf64": 479 | 480 | body=`rule elf64_header_COUNT: ELF64 481 | { 482 | meta: 483 | author = "Joan Bono" 484 | 485 | strings: 486 | $a = { 7F 45 4C 46 } 487 | 488 | 489 | ` 490 | 491 | 492 | 493 | 494 | case "flac": 495 | 496 | body=`rule flac_header_COUNT: FLAC 497 | { 498 | meta: 499 | author = "Joan Soriano" 500 | 501 | strings: 502 | 503 | $a = {66 4C 61 43} 504 | 505 | 506 | ` 507 | 508 | 509 | 510 | case "flash": 511 | 512 | body=`rule flash_header_COUNT: FLASH 513 | { 514 | meta: 515 | author = "Joan Soriano" 516 | 517 | strings: 518 | 519 | $a = {46 57 53} 520 | 521 | 522 | ` 523 | 524 | 525 | 526 | case "gif": 527 | 528 | body=`rule gif_header_COUNT: GIF 529 | { 530 | meta: 531 | author = "Joan Soriano" 532 | 533 | strings: 534 | 535 | $a = {ff d8 ff e0 00 10} 536 | 537 | 538 | ` 539 | 540 | 541 | 542 | case "gzip": 543 | 544 | body=`rule gzip_header_COUNT: GZIP 545 | { 546 | meta: 547 | author = "Joan Soriano" 548 | 549 | strings: 550 | 551 | $a = {1F 8B} 552 | 553 | 554 | ` 555 | 556 | 557 | 558 | 559 | 560 | case "is": 561 | 562 | body=`rule isoheader: ISO 563 | { 564 | meta: 565 | author = "Joan Soriano" 566 | 567 | strings: 568 | 569 | $a = {43 44 30 30 31} 570 | 571 | 572 | ` 573 | 574 | 575 | 576 | case "javaclass": 577 | 578 | body=`rule javaclass_header_COUNT: JAVA 579 | { 580 | meta: 581 | author = "Joan Soriano" 582 | 583 | strings: 584 | 585 | $a = {CA FE BA BE} 586 | 587 | 588 | 589 | ` 590 | 591 | 592 | 593 | case "jpg": 594 | 595 | body=`rule jpg_header_COUNT: JPG 596 | { 597 | meta: 598 | author = "Joan Soriano" 599 | 600 | strings: 601 | 602 | $a = {ff d8 ff e0 00 10} 603 | 604 | 605 | 606 | 607 | ` 608 | 609 | 610 | 611 | case "kodakcineon": 612 | 613 | body=`rule kodakcineon_header_COUNT: KODAKCINEON 614 | { 615 | meta: 616 | author = "Joan Soriano" 617 | 618 | strings: 619 | 620 | $a = {80 2A 5F D7} 621 | 622 | 623 | ` 624 | 625 | 626 | 627 | case "macho": 628 | 629 | body=`rule macho_header_COUNT: MACHO 630 | { 631 | meta: 632 | author = "Joan Soriano" 633 | 634 | strings: 635 | 636 | $a = {FE ED FA CE} 637 | 638 | 639 | 640 | ` 641 | case "mft": 642 | 643 | body=`rule mft_header_COUNT: MFT 644 | { 645 | meta: 646 | author = "Joan Soriano" 647 | 648 | strings: 649 | 650 | $a = {46 49 4C 45 30} 651 | 652 | 653 | 654 | ` 655 | case "microsoftOffice": 656 | 657 | body=`rule microsoftOffice_header_COUNT: MICROSOFTOFFICE 658 | { 659 | meta: 660 | author = "Joan Soriano" 661 | 662 | strings: 663 | 664 | $a = {D0 CF 11 E0 A1 B1 1A E1} 665 | 666 | 667 | ` 668 | 669 | 670 | 671 | case "midi": 672 | 673 | body=`rule midi_header_COUNT: MIDI 674 | { 675 | meta: 676 | author = "Joan Soriano" 677 | 678 | strings: 679 | 680 | $a = {4D 54 68 64} 681 | 682 | 683 | ` 684 | 685 | 686 | case "mkv": 687 | 688 | body=`rule mkv_header_COUNT: MKV 689 | { 690 | meta: 691 | author = "Joan Soriano" 692 | 693 | strings: 694 | 695 | $a = {1A 45 DF A3} 696 | 697 | 698 | ` 699 | 700 | 701 | case "mp3": 702 | 703 | body=`rule mp3_header_COUNT: MP3 704 | { 705 | meta: 706 | author = "Joan Soriano" 707 | 708 | strings: 709 | 710 | $a = {FF FB} 711 | 712 | 713 | ` 714 | 715 | 716 | 717 | case "mpeg": 718 | 719 | body=`rule mpeg_header_COUNT: MPEG 720 | { 721 | meta: 722 | author = "Joan Soriano" 723 | 724 | strings: 725 | 726 | $a = {00 00 01 BA} 727 | 728 | 729 | 730 | ` 731 | 732 | 733 | 734 | case "ost": 735 | 736 | body=`rule ost_header_COUNT: BMP 737 | { 738 | meta: 739 | author = "Joan Soriano" 740 | 741 | strings: 742 | 743 | $a = { 21 42 44 4e} 744 | 745 | 746 | 747 | ` 748 | 749 | 750 | 751 | case "pcap": 752 | 753 | body=`rule pcap_header_COUNT: PCAP 754 | { 755 | meta: 756 | author = "Joan Soriano" 757 | 758 | strings: 759 | 760 | $a = {a1 b2 c3 d4} 761 | 762 | 763 | 764 | 765 | ` 766 | 767 | 768 | 769 | case "pcapng": 770 | 771 | body=`rule pcapng_header_COUNT: PCAPNG 772 | { 773 | meta: 774 | author = "Joan Soriano" 775 | 776 | strings: 777 | 778 | $a = {0a 0d 0d 0a} 779 | 780 | 781 | 782 | ` 783 | 784 | 785 | 786 | case "pdf": 787 | 788 | body=`rule pdf_header_COUNT: PDF 789 | { 790 | meta: 791 | author = "Joan Soriano" 792 | 793 | strings: 794 | $a = "%PDF" 795 | 796 | 797 | ` 798 | 799 | 800 | 801 | case "pe": 802 | 803 | body=`rule pe_header_COUNT: EXE 804 | { 805 | meta: 806 | author = "Joan Soriano" 807 | 808 | strings: 809 | $a = { 4d 5a ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 21 ?? ??} 810 | 811 | 812 | ` 813 | 814 | 815 | case "png": 816 | 817 | body=`rule png_header_COUNT: PNG 818 | { 819 | meta: 820 | author = "Joan Soriano" 821 | 822 | strings: 823 | 824 | $a = {89 50 4E 47 0D 0A 1A 0A} 825 | 826 | 827 | 828 | ` 829 | 830 | 831 | 832 | case "pds": 833 | 834 | body=`rule pds_header_COUNT: PSD 835 | { 836 | meta: 837 | author = "Joan Soriano" 838 | 839 | strings: 840 | 841 | $a = {38 42 50 53} 842 | 843 | 844 | ` 845 | 846 | 847 | 848 | case "pst": 849 | 850 | body=`rule pst_header_COUNT: BMP 851 | { 852 | meta: 853 | author = "Joan Soriano" 854 | 855 | strings: 856 | 857 | $a = { 21 42 4e a5 6f b5 a6} 858 | 859 | 860 | 861 | ` 862 | 863 | 864 | 865 | case "pyc": 866 | 867 | body=`rule pyc_header_COUNT: PYC 868 | { 869 | meta: 870 | author = "Joan Soriano" 871 | 872 | strings: 873 | $a = { 03 f3 0d 0a } 874 | 875 | 876 | ` 877 | 878 | 879 | 880 | 881 | case "rar": 882 | 883 | body=`rule rar_header_COUNT: RAR 884 | { 885 | meta: 886 | author = "Joan Soriano" 887 | 888 | strings: 889 | 890 | $a = {52 61 72 21 1A 07 00} 891 | 892 | 893 | 894 | ` 895 | 896 | 897 | 898 | case "rpm": 899 | 900 | body=`rule rpm_header_COUNT: RPM 901 | { 902 | meta: 903 | author = "Joan Soriano" 904 | 905 | strings: 906 | 907 | $a = {ed ab ee db} 908 | 909 | 910 | 911 | ` 912 | 913 | 914 | 915 | case "rtf": 916 | 917 | body=`rule rtf_header_COUNT: RTF 918 | { 919 | meta: 920 | author = "Joan Soriano" 921 | 922 | strings: 923 | 924 | $a = {7B 5C 72 74 66 31} 925 | 926 | 927 | 928 | ` 929 | 930 | 931 | 932 | case "tape": 933 | 934 | body=`rule tape_header_COUNT: TAPE 935 | { 936 | meta: 937 | author = "Joan Soriano" 938 | 939 | strings: 940 | 941 | $a = {54 41 50 45} 942 | 943 | 944 | 945 | ` 946 | 947 | 948 | 949 | case "tar": 950 | 951 | body=`rule tar_header_COUNT: TAR 952 | { 953 | meta: 954 | author = "Joan Soriano" 955 | 956 | strings: 957 | 958 | $a = {75 73 74 61 72 00 30 30} 959 | 960 | 961 | ` 962 | 963 | 964 | case "tarzip": 965 | 966 | body=`rule tarzip_header_COUNT: TARZIP 967 | { 968 | meta: 969 | author = "Joan Soriano" 970 | 971 | strings: 972 | 973 | $a = {1F 9D} 974 | 975 | 976 | 977 | 978 | ` 979 | 980 | 981 | 982 | case "tiff": 983 | 984 | body=`rule tiff_header_COUNT: TIFF 985 | { 986 | meta: 987 | author = "Joan Soriano" 988 | 989 | strings: 990 | 991 | $a = {49 49 2A 00} 992 | 993 | 994 | ` 995 | 996 | 997 | 998 | case "utf8": 999 | 1000 | body=`rule utf8_header_COUNT: UTF8 1001 | { 1002 | meta: 1003 | author = "Joan Soriano" 1004 | 1005 | strings: 1006 | 1007 | $a = {EF BB BF} 1008 | 1009 | 1010 | 1011 | ` 1012 | 1013 | 1014 | 1015 | case "vmdk": 1016 | 1017 | body=`rule vmdk_header_COUNT: VMDK 1018 | { 1019 | meta: 1020 | author = "Joan Soriano" 1021 | 1022 | strings: 1023 | 1024 | $a = {4B 44 4D} 1025 | 1026 | 1027 | ` 1028 | 1029 | 1030 | 1031 | case "wasm": 1032 | 1033 | body=`rule wasm_header_COUNT: WASM 1034 | { 1035 | meta: 1036 | author = "Joan Soriano" 1037 | 1038 | strings: 1039 | 1040 | $a = {00 61 73 6d} 1041 | 1042 | 1043 | ` 1044 | 1045 | 1046 | case "wav": 1047 | 1048 | body=`rule wav_header_COUNT: WAV 1049 | { 1050 | meta: 1051 | author = "Joan Soriano" 1052 | 1053 | strings: 1054 | 1055 | $a = {52 49 46 46 ?? ?? ?? ?? 57 41 56 45} 1056 | 1057 | 1058 | ` 1059 | 1060 | 1061 | 1062 | case "woff": 1063 | 1064 | body=`rule woff_header_COUNT: WOFF 1065 | { 1066 | meta: 1067 | author = "Joan Soriano" 1068 | 1069 | strings: 1070 | 1071 | $a = {77 4F 46 46} 1072 | 1073 | 1074 | ` 1075 | 1076 | 1077 | case "xar": 1078 | 1079 | body=`rule xar_header_COUNT: XAR 1080 | { 1081 | meta: 1082 | author = "Joan Soriano" 1083 | 1084 | strings: 1085 | 1086 | $a = {78 61 72 21} 1087 | 1088 | 1089 | 1090 | ` 1091 | 1092 | 1093 | case "xml": 1094 | 1095 | body=`rule xml_header_COUNT: XML 1096 | { 1097 | meta: 1098 | author = "Joan Soriano" 1099 | 1100 | strings: 1101 | 1102 | $a = {3c 3f 78 6d 6c 20} 1103 | 1104 | 1105 | ` 1106 | 1107 | 1108 | case "xz": 1109 | 1110 | body=`rule xz_header_COUNT: XZ 1111 | { 1112 | meta: 1113 | author = "Joan Soriano" 1114 | 1115 | strings: 1116 | 1117 | $a = {FD 37 7A 58 5A 00 00} 1118 | 1119 | 1120 | ` 1121 | 1122 | 1123 | case "zip": 1124 | 1125 | body=`rule zip_header_COUNT: ZIP 1126 | { 1127 | meta: 1128 | author = "Joan Soriano" 1129 | 1130 | strings: 1131 | $a = { 50 4b 03 04} 1132 | 1133 | 1134 | ` 1135 | 1136 | 1137 | case "zlib": 1138 | 1139 | body=`rule zlib_header_COUNT: ZLIB 1140 | { 1141 | meta: 1142 | author = "Joan Soriano" 1143 | 1144 | strings: 1145 | 1146 | $a = {78 01} 1147 | 1148 | 1149 | ` 1150 | } 1151 | return body 1152 | } 1153 | 1154 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1155 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1156 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1157 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1158 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1159 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1160 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1161 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1162 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1163 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1164 | 1165 | 1166 | 1167 | func returnBodyFooter(type1 string)string{ 1168 | 1169 | var body string 1170 | 1171 | switch option := type1; option { 1172 | 1173 | case "pdf": 1174 | 1175 | body=`rule pdf_footer_COUNT: PDF 1176 | { 1177 | meta: 1178 | author = "Joan Soriano" 1179 | 1180 | strings: 1181 | 1182 | $a = {25 45 4f 46 0d} 1183 | 1184 | 1185 | ` 1186 | 1187 | 1188 | case "jpg": 1189 | 1190 | body=`rule jpg_footer_COUNT: JPG 1191 | { 1192 | meta: 1193 | author = "Joan Soriano" 1194 | 1195 | strings: 1196 | 1197 | $a = {ff d9} 1198 | 1199 | 1200 | ` 1201 | 1202 | 1203 | case "gif": 1204 | 1205 | body=`rule gif_footer_COUNT: AMAZONBIN 1206 | { 1207 | meta: 1208 | author = "Joan Soriano" 1209 | 1210 | strings: 1211 | 1212 | $a = {00 3b} 1213 | 1214 | 1215 | 1216 | ` 1217 | 1218 | case "mft": 1219 | 1220 | body=`rule mft_footer_COUNT: MFT 1221 | { 1222 | meta: 1223 | author = "Joan Soriano" 1224 | 1225 | strings: 1226 | 1227 | $a = {79 47 11} 1228 | 1229 | 1230 | 1231 | ` 1232 | 1233 | 1234 | case "doc": 1235 | 1236 | body=`rule doc_footer_COUNT: APPLEWORKS5 1237 | { 1238 | meta: 1239 | author = "Joan Soriano" 1240 | 1241 | strings: 1242 | 1243 | $a = {d0 cf 11 e0 a1 b1 1a e1 00 00} 1244 | 1245 | 1246 | 1247 | ` 1248 | 1249 | } 1250 | return body 1251 | } 1252 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | 22 | package main 23 | 24 | import ( 25 | "fmt" 26 | "log" 27 | "os" 28 | docopt "github.com/docopt/docopt-go" 29 | ) 30 | 31 | 32 | 33 | var rawdisk string 34 | 35 | var totIndex string 36 | 37 | var verbose bool 38 | 39 | var OutputFile = "" 40 | 41 | var vtiAPI = "" 42 | 43 | var historyFile = "" 44 | 45 | var totrawdisk string 46 | 47 | var footersupport []string 48 | 49 | var headersupport []string 50 | 51 | var maxSizeDump = "50000" 52 | 53 | var maxsize string 54 | 55 | var filetype string 56 | 57 | var dataSelected string 58 | 59 | var xor bool 60 | 61 | var workspace string 62 | 63 | var supported = []string{"threegp","sevenzip","amazonkindleupdate","appleworks5","appleworks6","avi","bmp","bzip","canonraw","crx","dalvik","dat","dba","deb","dmg","doc","elf64","flac","flash","gif","gzip","is","javaclass","jpg","kodakcineon","macho","microsoftOffice","midi","mkv","mp3","mpeg","ost","pcap","pcapng","pdf","pe","png","pds","pst","pyc","rar","rpm","rtf","tape","tar","tarzip","tiff","utf8","vmdk","wasm","wav","woff","xar","xml","xz","zip","zlib"} 64 | 65 | var hashlist []string 66 | 67 | type newResult1 struct { 68 | Rule string 69 | } 70 | 71 | var resultsMagicINIT []result 72 | 73 | 74 | type ioc struct { 75 | rule string 76 | Data string 77 | OffsetHeader uint64 78 | match bool 79 | indexMatch int 80 | domain bool 81 | } 82 | 83 | type ssdeepSlice struct { 84 | Name string 85 | Ssdeep string 86 | } 87 | 88 | type stats struct { 89 | rule string 90 | total int 91 | } 92 | 93 | type unMarshal struct { 94 | newresult newResult 95 | } 96 | 97 | var Footer string 98 | 99 | var sliceIOC []ioc 100 | var sliceIOCmatched []ioc 101 | 102 | type newResult struct { 103 | Rule string `json:"Rule"` 104 | OffsetHeader uint64 `json:"OffsetHeader"` 105 | OffsetFooter uint64 `json:"OffsetFooter"` 106 | Data []byte `json:"Data"` 107 | Yara []string `json:"Yara"` 108 | Ioc string `json:"Ioc"` 109 | Index int `json:"Index"` 110 | Ssdeep string `json:"Ssdeep"` 111 | Hash string `json:"Hash"` 112 | Size uint64 `json:"Size"` 113 | Comment string `json:"Comment"` 114 | Tag string `json:"Tag"` 115 | Entropy int64 `json:"Entropy"` 116 | } 117 | 118 | var sliceNewResults []newResult 119 | 120 | var sliceSet []newResult 121 | 122 | 123 | var magicPath string = "./magicrules/" 124 | 125 | func main() { 126 | 127 | usage := `YaraRET - Carving binaries with Yara & Radare. 128 | 129 | Usage: 130 | yararet rawdisk yarafile maxsize 131 | yararet rawdisk ioc 132 | yararet rawdisk ioc maxsize [ --xor] 133 | yararet rawdisk hash filetype [ --sections ] [ --vti ] 134 | yararet rawdisk ioc maxsize filetype [ --xor] 135 | yararet -h | --help 136 | yararet rawdisk shell 137 | yararet --version 138 | 139 | Options: 140 | -h --help Show this screen. 141 | -s --shell Runs interactive shell 142 | 143 | ` 144 | version := "1.0" 145 | arguments, _ := docopt.Parse(usage, nil, true, version, false) 146 | totrawdisk = arguments[""].(string) 147 | fmt.Println("\n\n██╗ ██╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗████████╗\n╚██╗ ██╔╝██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝╚══██╔══╝\n ╚████╔╝ ███████║██████╔╝███████║██████╔╝█████╗ ██║ \n ╚██╔╝ ██╔══██║██╔══██╗██╔══██║██╔══██╗██╔══╝ ██║ \n ██║ ██║ ██║██║ ██║██║ ██║██║ ██║███████╗ ██║ \n ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═╝\n\n") 148 | 149 | dir, err := os.Getwd() 150 | if err != nil { 151 | log.Fatal(err) 152 | } 153 | workspace = dir 154 | 155 | if arguments["shell"].(bool) { 156 | rawdisk := arguments[""].(string) 157 | runShell(rawdisk) 158 | } 159 | 160 | if arguments["hash"].(bool) { 161 | rawdisk := arguments[""].(string) 162 | filetype = arguments[""].(string) 163 | hashes := arguments[""].(string) 164 | runHash(rawdisk, filetype, hashes) 165 | } 166 | 167 | if arguments["ioc"].(bool) { 168 | rawdisk := arguments[""].(string) 169 | maxsize = arguments[""].(string) 170 | ioc := arguments[""].(string) 171 | //filetype = arguments[""].(string) 172 | xor = arguments["--xor"].(bool) 173 | filetype := "pyc" 174 | searchOpenIOCCmd(rawdisk, ioc, maxsize, filetype) 175 | } 176 | 177 | if arguments["yarafile"].(bool) { 178 | rawdisk := arguments[""].(string) 179 | yarafile := arguments[""].(string) 180 | maxsize = arguments[""].(string) 181 | //filetype = arguments[""].(string) 182 | //filetype = arguments[""].(string) 183 | extractFromYara(rawdisk, yarafile, maxsize, filetype) 184 | } 185 | } -------------------------------------------------------------------------------- /radarePipe.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | 22 | 23 | package main 24 | 25 | import ( 26 | "fmt" 27 | // "encoding/gob" 28 | // "net" 29 | "bufio" 30 | "github.com/radare/r2pipe-go" 31 | "strconv" 32 | "strings" 33 | "os" 34 | ) 35 | 36 | 37 | 38 | func searchRadare(resultsToT []result, rawdisk string, filetype string, maxsize string) { 39 | var rulesMatched []string 40 | //magicRules := magicPath+filetype+".yar" 41 | //fmt.Println(magicRules) 42 | //fmt.Println(len(resultsToT)) 43 | //defer r2p4.Close() 44 | 45 | indexNum := 0 46 | r2p, err := r2pipe.NewPipe(rawdisk) 47 | if err != nil { 48 | print("ERROR: ", err) 49 | } 50 | 51 | defer r2p.Close() 52 | for _, elem := range resultsToT { 53 | //fmt.Println(elem) 54 | //fmt.Println(elem.offset) 55 | if stringInSlice(elem.rule, rulesMatched) == false { 56 | rulesMatched = append(rulesMatched, elem.rule) 57 | indexNum += 1 58 | pathFile := "/tmp/" 59 | nameFile := elem.rule + strconv.Itoa(int(indexNum)) 60 | //fmt.Println(pathFile) 61 | //fmt.Println(nameFile) 62 | //fmt.Println(elem.offset) 63 | disasm, err := r2p.Cmd("s " + strconv.Itoa(int(elem.offset))) 64 | if err != nil { 65 | print("ERROR: ", err) 66 | } else { 67 | print(disasm, "") 68 | } 69 | disasm2, err := r2p.Cmd("s -" + maxsize) 70 | if err != nil { 71 | print("ERROR: ", err) 72 | } else { 73 | print(disasm2, "") 74 | } 75 | maxsizeInt, err := strconv.ParseFloat(maxsize, 64) 76 | if err != nil { 77 | } 78 | //fmt.Println(maxsizeInt) 79 | //maxsize2 := maxsizeInt*2 80 | disasm3, err := r2p.Cmd("wtf " + pathFile + nameFile + " " + strconv.FormatFloat(maxsizeInt*2, 'f', 6, 64)) 81 | if err != nil { 82 | print("ERROR: ", err) 83 | } else { 84 | print(disasm3, "") 85 | } 86 | 87 | resultsMagic := searchYara(pathFile+nameFile, "./magicrules/magicrules_header.yar") 88 | //fmt.Println(resultsMagic) 89 | 90 | for _, elem2 := range resultsMagic { 91 | //fmt.Println(pathFile+nameFile) 92 | r2p2, err := r2pipe.NewPipe(pathFile + nameFile) 93 | if err != nil { 94 | print("ERROR: ", err) 95 | } 96 | 97 | defer r2p2.Close() 98 | 99 | disasm4, err := r2p2.Cmd("s " + strconv.Itoa(int(elem2.offset))) 100 | if err != nil { 101 | print("ERROR: ", err) 102 | print(disasm4, "") 103 | } else { 104 | disasm4 := "" 105 | print(disasm4, "") 106 | ///fmt.Println() 107 | } 108 | 109 | //hexAddr := strings.Split(disasm99," ")[1] 110 | 111 | //fmt.Println(hexAddr) 112 | 113 | disasm98, err := r2p2.Cmd("b " + maxsize) 114 | if err != nil { 115 | print("ERROR: ", err) 116 | } else { 117 | print(disasm98, "") 118 | } 119 | 120 | //disasm5, err := r2p2.Cmd("wtf! "+pathFile+nameFile+"_2"+" "+strconv.FormatFloat(maxsizeInt, 'f', 6, 64)) 121 | disasm5, err := r2p2.Cmd("wtf! " + pathFile + nameFile + "_2") 122 | //disasm5, err := r2p2.Cmd("wtf @"+hexAddr) 123 | if err != nil { 124 | print("ERROR: ", err) 125 | } else { 126 | disasm5 = "" 127 | print(disasm5, "") 128 | } 129 | 130 | r2p2.Close() 131 | //fmt.Println("open new file") 132 | //r2p3, err := r2pipe.NewPipe(pathFile+nameFile+"_2") 133 | r2p4, err := r2pipe.NewPipe(pathFile + nameFile + "_2") 134 | if err != nil { 135 | print("ERROR: ", err) 136 | fmt.Println("can't open") 137 | } 138 | //defer r2p4.Close() 139 | //fmt.Println("after open") 140 | 141 | disasm96, err := r2p4.Cmd("s 0x0") 142 | if err != nil { 143 | print("ERROR: ", err) 144 | } else { 145 | disasm96 = "" 146 | print(disasm96, "") 147 | } 148 | 149 | disasm6, err := r2p4.Cmd("iZ") 150 | if err != nil { 151 | print("ERROR: ", err) 152 | } else { 153 | disasm6 := "" 154 | print(disasm6, "") 155 | } 156 | 157 | //fmt.Println("calc size") 158 | disasm8, err := r2p4.Cmd("wtf " + "Exported_" + nameFile + " " + disasm6) 159 | if err != nil { 160 | print("ERROR: ", err) 161 | } else { 162 | disasm8 = "" 163 | print(disasm8, "") 164 | } 165 | 166 | if strings.Contains(elem.rule, "pe") { 167 | getSizePe("Exported_" + nameFile) 168 | } 169 | 170 | fmt.Println("\n") 171 | fmt.Println("[+] Dumped file:\n\t[-] Rule: " + elem.rule + "\n\t[-] Name: " + "Exported_" + nameFile + "\n\t[-] FileType: " + strings.Split(elem2.rule, "_")[0]) 172 | } 173 | 174 | } 175 | 176 | //fmt.Println(nameFile) 177 | 178 | } 179 | } 180 | 181 | 182 | 183 | func runHashReturn(rawdisk string, elem newResult) string { 184 | //yarafile := "./magicrules/magicrules_footer_index.yar" 185 | //var lastResult result 186 | 187 | //var newR newResult 188 | //fmt.Println(sliceNewResults) 189 | a := getHashReturn(rawdisk, elem.OffsetHeader, elem.Size) 190 | 191 | //fmt.Println(resultsHash) 192 | 193 | //fmt.Println(sliceNewResults) 194 | 195 | return a 196 | 197 | } 198 | 199 | 200 | func getHashReturn(rawdisk string, header uint64, block uint64) string { 201 | r2p, err := r2pipe.NewPipe(rawdisk) 202 | if err != nil { 203 | print("ERROR: ", err) 204 | } 205 | 206 | defer r2p.Close() 207 | 208 | // tener en cuenta que el match se hace al princpio de la cadena y 209 | //tenemos que saber cuantos bytes faltan hasta el último para generar correctamente un bloque 210 | disasm, err := r2p.Cmd("b " + strconv.Itoa(int(block))) 211 | 212 | if err != nil { 213 | print("ERROR: ", err) 214 | } else { 215 | print(disasm, "") 216 | } 217 | 218 | disasm2, err := r2p.Cmd("s " + strconv.Itoa(int(header))) 219 | 220 | if err != nil { 221 | print("ERROR: ", err) 222 | } else { 223 | print(disasm2, "") 224 | } 225 | 226 | disasm3, err := r2p.Cmd("ph md5") 227 | if err != nil { 228 | print("ERROR: ", err) 229 | } else { 230 | } 231 | return disasm3 232 | } 233 | 234 | 235 | 236 | func getHashSelected(rawdisk string, header uint64, block uint64) string { 237 | r2p, err := r2pipe.NewPipe(rawdisk) 238 | if err != nil { 239 | print("ERROR: ", err) 240 | } 241 | 242 | defer r2p.Close() 243 | 244 | // tener en cuenta que el match se hace al princpio de la cadena y 245 | //tenemos que saber cuantos bytes faltan hasta el último para generar correctamente un bloque 246 | disasm, err := r2p.Cmd("b " + strconv.Itoa(int(block))) 247 | 248 | if err != nil { 249 | print("ERROR: ", err) 250 | } else { 251 | print(disasm, "") 252 | } 253 | 254 | disasm2, err := r2p.Cmd("s "+strconv.Itoa(int(header))) 255 | 256 | if err != nil { 257 | print("ERROR: ", err) 258 | } else { 259 | print(disasm2, "") 260 | } 261 | 262 | 263 | 264 | 265 | disasm3, err := r2p.Cmd("ph md5") 266 | if err != nil { 267 | print("ERROR: ", err) 268 | } else { 269 | } 270 | return disasm3 271 | } 272 | 273 | 274 | 275 | func getHash(rawdisk string, header uint64, block uint64) { 276 | r2p, err := r2pipe.NewPipe(rawdisk) 277 | if err != nil { 278 | print("ERROR: ", err) 279 | } 280 | 281 | defer r2p.Close() 282 | 283 | // tener en cuenta que el match se hace al princpio de la cadena y 284 | //tenemos que saber cuantos bytes faltan hasta el último para generar correctamente un bloque 285 | disasm, err := r2p.Cmd("b " + strconv.Itoa(int(block))) 286 | 287 | if err != nil { 288 | print("ERROR: ", err) 289 | } else { 290 | print(disasm, "") 291 | } 292 | 293 | disasm2, err := r2p.Cmd("s " + strconv.Itoa(int(header))) 294 | 295 | if err != nil { 296 | print("ERROR: ", err) 297 | } else { 298 | print(disasm2, "") 299 | } 300 | 301 | disasm3, err := r2p.Cmd("ph md5") 302 | if err != nil { 303 | print("ERROR: ", err) 304 | } else { 305 | fmt.Println(disasm3) 306 | } 307 | //return disasm3 308 | 309 | } 310 | 311 | 312 | func dumpRadare(rawdisk string, header string, rule string, index string) { 313 | // var offset int 314 | // var i uint64 315 | r2p4, err := r2pipe.NewPipe(rawdisk) 316 | if err != nil { 317 | print("ERROR: ", err) 318 | fmt.Println("can't open") 319 | } 320 | //defer r2p4.Close() 321 | //fmt.Println("after open") 322 | r2p4.Cmd("s " + header) 323 | 324 | r2p4.Cmd("wtf ./tmp " + maxSizeDump) 325 | 326 | 327 | r2p5, err := r2pipe.NewPipe("./tmp") 328 | if err != nil { 329 | print("ERROR: ", err) 330 | fmt.Println("can't open") 331 | } 332 | 333 | r2p5.Cmd("s 0x0") 334 | 335 | disasm6, err := r2p5.Cmd("iZ") 336 | if err != nil { 337 | print("ERROR: ", err) 338 | } else { 339 | //disasm6:="" 340 | //print(disasm6, "") 341 | } 342 | 343 | //The block is hardcoded 'cause it fails with bigger blocks 344 | r2p5.Cmd("b " + maxSizeDump) 345 | 346 | 347 | Footer = disasm6 348 | //fmt.Println("calc size") 349 | r2p5.Cmd("wtf " + rule + "_" + index) 350 | 351 | 352 | //err2 := os.Remove(workspace+"/tmp") 353 | 354 | // if err2 != nil { 355 | // fmt.Println(err2) 356 | // return 357 | // } 358 | 359 | r2p4.Close() 360 | } 361 | 362 | 363 | 364 | func dumpRadareFooter(rawdisk string, header uint64, lastAddress uint64, rule string, index string) { 365 | 366 | //fmt.Println(rule) 367 | //fmt.Println(index) 368 | 369 | block := lastAddress - header 370 | //fmt.Println(block) 371 | 372 | r2p, err := r2pipe.NewPipe(rawdisk) 373 | if err != nil { 374 | print("ERROR: ", err) 375 | } 376 | 377 | defer r2p.Close() 378 | 379 | // tener en cuenta que el match se hace al princpio de la cadena y 380 | //tenemos que saber cuantos bytes faltan hasta el último para generar correctamente un bloque 381 | disasm, err := r2p.Cmd("b " + strconv.Itoa(int(block))) 382 | 383 | if err != nil { 384 | print("ERROR: ", err) 385 | } else { 386 | print(disasm, "") 387 | } 388 | 389 | disasm2, err := r2p.Cmd("s " + strconv.Itoa(int(header))) 390 | 391 | if err != nil { 392 | print("ERROR: ", err) 393 | } else { 394 | print(disasm2, "") 395 | } 396 | 397 | // disasm3, err := r2p.Cmd("px") 398 | 399 | // if err != nil { 400 | // print("ERROR: ", err) 401 | // } else { 402 | // print(disasm3, "") 403 | // } 404 | 405 | disasm3, err := r2p.Cmd("wtf " + rule + "_" + index) 406 | if err != nil { 407 | print("ERROR: ", err) 408 | } else { 409 | print(disasm3, "") 410 | } 411 | 412 | r2p.Close() 413 | 414 | } 415 | 416 | 417 | func radareCmd2(argument []string, rawdisk string, header string) { 418 | 419 | 420 | command := "" 421 | for _, b := range argument { 422 | 423 | command += b + " " 424 | } 425 | r2p, err := r2pipe.NewPipe(rawdisk) 426 | if err != nil { 427 | print("ERROR: ", err) 428 | } 429 | defer r2p.Close() 430 | // disasm, err := r2p.Cmd("s 0x0") 431 | // if err != nil { 432 | // print("ERROR: ", err) 433 | // } else { 434 | // disasm:="" 435 | // print(disasm, "") 436 | // } 437 | r2p.Cmd("s "+header) 438 | 439 | disasm2, err := r2p.Cmd(command) 440 | if err != nil { 441 | print("ERROR: ", err) 442 | } else { 443 | //disasm2:="" 444 | print(disasm2, "") 445 | } 446 | 447 | } 448 | 449 | 450 | func radareCmd(argument []string, rawdisk string) { 451 | 452 | 453 | for _, elem := range sliceSet { 454 | rawdisk = elem.Rule + "_" + strconv.Itoa(elem.Index) 455 | } 456 | if argument[0] == "!" { 457 | } else { 458 | 459 | command := "" 460 | for _, b := range argument { 461 | 462 | command += b + " " 463 | } 464 | r2p, err := r2pipe.NewPipe(rawdisk) 465 | if err != nil { 466 | print("ERROR: ", err) 467 | } 468 | defer r2p.Close() 469 | // disasm, err := r2p.Cmd("s 0x0") 470 | // if err != nil { 471 | // print("ERROR: ", err) 472 | // } else { 473 | // disasm:="" 474 | // print(disasm, "") 475 | // } 476 | fmt.Println(argument) 477 | fmt.Println(command) 478 | disasm2, err := r2p.Cmd(command) 479 | if err != nil { 480 | print("ERROR: ", err) 481 | } else { 482 | //disasm2:="" 483 | print(disasm2, "") 484 | } 485 | } 486 | 487 | } 488 | 489 | 490 | func radareSession(rawdisk string) bool { 491 | fmt.Println() 492 | r2p, err := r2pipe.NewPipe(rawdisk) 493 | if err != nil { 494 | print("ERROR: ", err) 495 | } 496 | 497 | reader := bufio.NewReader(os.Stdin) 498 | text, _ := reader.ReadString('\n') 499 | fmt.Println(text) 500 | for true { 501 | disasm, err := r2p.Cmd(text) 502 | if err != nil { 503 | print("ERROR: ", err) 504 | } else { 505 | print(disasm, "") 506 | } 507 | reader = bufio.NewReader(os.Stdin) 508 | text, _ = reader.ReadString('\n') 509 | if text == "ex" { 510 | r2p.Close() 511 | return true 512 | } 513 | 514 | } 515 | return false 516 | } 517 | 518 | 519 | 520 | func uploadRadare(rawdisk string, header string, size string, host string, port string) { 521 | 522 | r2p, err := r2pipe.NewPipe(rawdisk) 523 | if err != nil { 524 | print("ERROR: ", err) 525 | } 526 | 527 | defer r2p.Close() 528 | 529 | disasm, err := r2p.Cmd("s " + header) 530 | if err != nil { 531 | print("ERROR: ", err) 532 | } else { 533 | print(disasm, "") 534 | } 535 | disasm, err = r2p.Cmd("wts " + host + ":" + port + " " + size) 536 | if err != nil { 537 | print("ERROR: ", err) 538 | } else { 539 | print(disasm, "") 540 | } 541 | } 542 | 543 | 544 | func dumpMaxSize(elem result) { 545 | rawdisk = totrawdisk 546 | fmt.Println(elem) 547 | maxsizeInt, err := strconv.ParseFloat(maxsize, 64) 548 | if err != nil { 549 | } 550 | r2p, err := r2pipe.NewPipe(rawdisk) 551 | if err != nil { 552 | print("ERROR: ", err) 553 | } 554 | 555 | defer r2p.Close() 556 | disasm, err := r2p.Cmd("s " + strconv.Itoa(int(elem.offset))) 557 | if err != nil { 558 | print("ERROR: ", err) 559 | } else { 560 | print(disasm, "") 561 | } 562 | defer r2p.Close() 563 | disasm, err = r2p.Cmd("s -" + maxSizeDump) 564 | if err != nil { 565 | print("ERROR: ", err) 566 | } else { 567 | print(disasm, "") 568 | } 569 | disasm, err = r2p.Cmd("px") 570 | if err != nil { 571 | print("ERROR: ", err) 572 | } else { 573 | print(disasm, "") 574 | } 575 | disasm3, err := r2p.Cmd("wtf ./tmp " + strconv.FormatFloat(maxsizeInt*2, 'f', 6, 64)) 576 | if err != nil { 577 | print("ERROR: ", err) 578 | } else { 579 | print(disasm3, "") 580 | } 581 | } 582 | 583 | 584 | -------------------------------------------------------------------------------- /shell.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 0 { 53 | startCmd(c.Args, rawdisk) 54 | 55 | } else { 56 | fmt.Println("I need more arguments :(") 57 | } 58 | 59 | }, 60 | }) 61 | 62 | shell.AddCmd(&ishell.Cmd{ 63 | Name: "supported", 64 | Help: "list supported filetypes", 65 | Func: func(c *ishell.Context) { 66 | 67 | if verbose == true { 68 | 69 | command := "" 70 | for _, b := range c.Args { 71 | 72 | command += b + " " 73 | } 74 | saveCommand("start " + command) 75 | 76 | } 77 | if len(c.Args) > 0 { 78 | startCmd(c.Args, rawdisk) 79 | 80 | } else { 81 | fmt.Println("I need more arguments :(") 82 | } 83 | 84 | }, 85 | }) 86 | 87 | shell.AddCmd(&ishell.Cmd{ 88 | Name: "~", 89 | Help: "~ radare2Command", 90 | Func: func(c *ishell.Context) { 91 | var mybool bool 92 | if verbose == true { 93 | 94 | command := "" 95 | for _, b := range c.Args { 96 | 97 | command += b + " " 98 | } 99 | saveCommand("yara " + command) 100 | 101 | } 102 | if len(c.Args) > 0 { 103 | radareCmd2(c.Args, rawdisk, strconv.Itoa(int(sliceSet[0].OffsetHeader))) 104 | } else { 105 | if len(sliceSet) < 2 { 106 | for _, elem := range sliceSet { 107 | rawdisk = elem.Rule + "_" + strconv.Itoa(elem.Index) 108 | } 109 | mybool = radareSession(rawdisk) 110 | fmt.Println(mybool) 111 | } else { 112 | 113 | fmt.Println("I need more arguments :(") 114 | } 115 | } 116 | }, 117 | }) 118 | 119 | shell.AddCmd(&ishell.Cmd{ 120 | Name: "yara", 121 | Help: "yara yaraRule", 122 | Func: func(c *ishell.Context) { 123 | 124 | 125 | if verbose == true { 126 | 127 | command := "" 128 | for _, b := range c.Args { 129 | 130 | command += b + " " 131 | } 132 | saveCommand("yara " + command) 133 | 134 | } 135 | if len(c.Args) > 0 { 136 | if c.Args[0] == "+" { 137 | yaraCmd(c.Args[1]) 138 | } else { 139 | fmt.Println("[+] Running a fast scan") 140 | yaraLightCmd(c.Args, rawdisk) 141 | } 142 | } else { 143 | 144 | fmt.Println("I need more arguments :(") 145 | } 146 | 147 | }, 148 | }) 149 | 150 | 151 | shell.AddCmd(&ishell.Cmd{ 152 | Name: "resume", 153 | Help: "resume of all data", 154 | Func: func(c *ishell.Context) { 155 | 156 | 157 | 158 | var allRules string 159 | for _, element := range sliceNewResults { 160 | allRules = allRules + element.Rule + " " 161 | 162 | } 163 | wordCount(allRules) 164 | }, 165 | }) 166 | 167 | 168 | shell.AddCmd(&ishell.Cmd{ 169 | Name: "unset", 170 | Help: "unset index/filetype", 171 | Func: func(c *ishell.Context) { 172 | 173 | 174 | 175 | if verbose == true { 176 | 177 | command := "" 178 | for _, b := range c.Args { 179 | 180 | command += b + " " 181 | } 182 | saveCommand("unset " + command) 183 | 184 | } 185 | if len(c.Args) > 0 { 186 | unsetCmd(c.Args, rawdisk) 187 | 188 | } else { 189 | fmt.Println("I need more arguments :(") 190 | } 191 | 192 | }, 193 | }) 194 | 195 | shell.AddCmd(&ishell.Cmd{ 196 | Name: "run", 197 | Help: "run script", 198 | Func: func(c *ishell.Context) { 199 | 200 | 201 | 202 | if verbose == true { 203 | 204 | command := "" 205 | for _, b := range c.Args { 206 | 207 | command += b + " " 208 | } 209 | saveCommand("run " + command) 210 | 211 | } 212 | if len(c.Args) > 0 { 213 | runCmd(c.Args, rawdisk) 214 | } else { 215 | fmt.Println("I need more arguments :(") 216 | } 217 | 218 | }, 219 | }) 220 | 221 | shell.AddCmd(&ishell.Cmd{ 222 | Name: "save", 223 | Help: "save outputfile", 224 | Func: func(c *ishell.Context) { 225 | 226 | 227 | if verbose == true { 228 | 229 | command := "" 230 | for _, b := range c.Args { 231 | 232 | command += b + " " 233 | } 234 | saveCommand("save " + command) 235 | 236 | } 237 | 238 | saveCmd(c.Args, rawdisk) 239 | 240 | }, 241 | }) 242 | 243 | shell.AddCmd(&ishell.Cmd{ 244 | Name: "open", 245 | Help: "open file", 246 | Func: func(c *ishell.Context) { 247 | 248 | 249 | 250 | 251 | 252 | if verbose == true { 253 | 254 | command := "" 255 | for _, b := range c.Args { 256 | 257 | command += b + " " 258 | } 259 | saveCommand("open " + command) 260 | 261 | } 262 | if len(c.Args) > 0 { 263 | openCmd(c.Args, rawdisk) 264 | } else { 265 | fmt.Println("I need more arguments :(") 266 | } 267 | }, 268 | }) 269 | 270 | shell.AddCmd(&ishell.Cmd{ 271 | Name: "dump", 272 | Help: "dumps the selected files", 273 | Func: func(c *ishell.Context) { 274 | 275 | if verbose == true { 276 | 277 | command := "" 278 | for _, b := range c.Args { 279 | 280 | command += b + " " 281 | } 282 | saveCommand("dump " + command) 283 | 284 | } 285 | 286 | dumpCmd(rawdisk) 287 | 288 | }, 289 | }) 290 | 291 | shell.AddCmd(&ishell.Cmd{ 292 | Name: "upload", 293 | Help: "upload host port", 294 | Func: func(c *ishell.Context) { 295 | 296 | if verbose == true { 297 | 298 | command := "" 299 | for _, b := range c.Args { 300 | 301 | command += b + " " 302 | } 303 | saveCommand("dump " + command) 304 | 305 | } 306 | 307 | uploadCmd(c.Args, rawdisk) 308 | 309 | }, 310 | }) 311 | 312 | shell.AddCmd(&ishell.Cmd{ 313 | Name: "vti", 314 | Help: "vti", 315 | Func: func(c *ishell.Context) { 316 | 317 | if verbose == true { 318 | 319 | command := "" 320 | for _, b := range c.Args { 321 | 322 | command += b + " " 323 | } 324 | saveCommand("vti " + command) 325 | 326 | } 327 | 328 | if len(c.Args)>0{ 329 | switch option := c.Args[0]; option { 330 | 331 | case "key": 332 | vtiAPI = c.Args[1] 333 | default: 334 | vtiCmd(c.Args, rawdisk) 335 | } 336 | }else{ 337 | fmt.Println("[!] Please provide arguments to this call") 338 | 339 | 340 | } 341 | 342 | }, 343 | }) 344 | 345 | shell.AddCmd(&ishell.Cmd{ 346 | Name: "show", 347 | Help: "show filetype", 348 | Func: func(c *ishell.Context) { 349 | 350 | 351 | if verbose == true { 352 | 353 | command := "" 354 | for _, b := range c.Args { 355 | 356 | command += b + " " 357 | } 358 | saveCommand("show " + command) 359 | 360 | } 361 | if len(c.Args) > 0 { 362 | showCmd(c.Args, rawdisk) 363 | } else { 364 | fmt.Println("I need more arguments :(") 365 | } 366 | 367 | }, 368 | }) 369 | 370 | shell.AddCmd(&ishell.Cmd{ 371 | Name: "var", 372 | Help: "var variable", 373 | Func: func(c *ishell.Context) { 374 | 375 | 376 | if verbose == true { 377 | 378 | command := "" 379 | for _, b := range c.Args { 380 | 381 | command += b + " " 382 | } 383 | saveCommand("var " + command) 384 | 385 | } 386 | if len(c.Args) > 0 { 387 | varCmd(c.Args, rawdisk) 388 | } else { 389 | fmt.Println("I need more arguments :(") 390 | } 391 | 392 | }, 393 | }) 394 | 395 | shell.AddCmd(&ishell.Cmd{ 396 | Name: "lastitem", 397 | Help: "lastitem", 398 | Func: func(c *ishell.Context) { 399 | 400 | 401 | 402 | if verbose == true { 403 | 404 | command := "" 405 | for _, b := range c.Args { 406 | 407 | command += b + " " 408 | } 409 | saveCommand("vti " + command) 410 | 411 | } 412 | lastItemStruct() 413 | 414 | 415 | }, 416 | }) 417 | 418 | shell.AddCmd(&ishell.Cmd{ 419 | Name: "ioc", 420 | Help: "ioc file", 421 | Func: func(c *ishell.Context) { 422 | 423 | 424 | 425 | 426 | if verbose == true { 427 | 428 | command := "" 429 | for _, b := range c.Args { 430 | 431 | command += b + " " 432 | } 433 | saveCommand("ioc " + command) 434 | 435 | } 436 | if len(c.Args) > 0 { 437 | searchOpenIOCCmd2(rawdisk, c.Args[0]) 438 | 439 | 440 | } else { 441 | fmt.Println("I need more arguments :(") 442 | } 443 | 444 | 445 | }, 446 | }) 447 | 448 | shell.AddCmd(&ishell.Cmd{ 449 | Name: "output", 450 | Help: "output nameFile", 451 | Func: func(c *ishell.Context) { 452 | 453 | 454 | 455 | 456 | if verbose == true { 457 | 458 | command := "" 459 | for _, b := range c.Args { 460 | 461 | command += b + " " 462 | } 463 | saveCommand("output " + command) 464 | 465 | } 466 | if len(c.Args) > 0 { 467 | outputCmd(c.Args, rawdisk) 468 | } else { 469 | fmt.Println("I need more arguments :(") 470 | } 471 | 472 | }, 473 | }) 474 | 475 | shell.AddCmd(&ishell.Cmd{ 476 | Name: "set", 477 | Help: "selects an index or filetype", 478 | Func: func(c *ishell.Context) { 479 | 480 | if verbose == true { 481 | 482 | command := "" 483 | for _, b := range c.Args { 484 | 485 | command += b + " " 486 | } 487 | saveCommand("set " + command) 488 | 489 | } 490 | if len(c.Args) > 0 { 491 | set2Cmd(c.Args, rawdisk) 492 | } else { 493 | fmt.Println("I need more arguments :(") 494 | } 495 | 496 | }, 497 | }) 498 | 499 | shell.AddCmd(&ishell.Cmd{ 500 | Name: "hash", 501 | Help: "hash /path", 502 | Func: func(c *ishell.Context) { 503 | 504 | if verbose == true { 505 | 506 | command := "" 507 | for _, b := range c.Args { 508 | 509 | command += b + " " 510 | } 511 | saveCommand("hash " + command) 512 | 513 | } 514 | hashCmd(c.Args, rawdisk) 515 | 516 | }, 517 | }) 518 | 519 | 520 | shell.AddCmd(&ishell.Cmd{ 521 | Name: "ssdeep", 522 | Help: "ssdeep set of file/s", 523 | Func: func(c *ishell.Context) { 524 | 525 | if verbose == true { 526 | 527 | command := "" 528 | for _, b := range c.Args { 529 | 530 | command += b + " " 531 | } 532 | saveCommand("ssdeep " + command) 533 | 534 | } 535 | ssdeepCmd(c.Args, rawdisk) 536 | 537 | }, 538 | }) 539 | 540 | 541 | shell.AddCmd(&ishell.Cmd{ 542 | Name: "tag", 543 | Help: "Put a tag in selected files", 544 | Func: func(c *ishell.Context) { 545 | 546 | if verbose == true { 547 | 548 | command := "" 549 | for _, b := range c.Args { 550 | 551 | command += b + " " 552 | } 553 | saveCommand("rawdisk " + command) 554 | 555 | } 556 | 557 | if len(c.Args)>0 && len(c.Args)<2{ 558 | putTag(c.Args[0]) 559 | 560 | 561 | } 562 | 563 | 564 | }, 565 | }) 566 | 567 | 568 | shell.AddCmd(&ishell.Cmd{ 569 | Name: "entropy", 570 | Help: "entropy index/filetype", 571 | Func: func(c *ishell.Context) { 572 | 573 | if verbose == true { 574 | 575 | command := "" 576 | for _, b := range c.Args { 577 | 578 | command += b + " " 579 | } 580 | saveCommand("entropy " + command) 581 | 582 | } 583 | 584 | entropyCmd2(c.Args, rawdisk) 585 | 586 | }, 587 | }) 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | shell.AddCmd(&ishell.Cmd{ 626 | Name: "yaraforensics", 627 | Help: "yaraforensics", 628 | Func: func(c *ishell.Context) { 629 | 630 | 631 | if verbose == true { 632 | 633 | command := "" 634 | for _, b := range c.Args { 635 | 636 | command += b + " " 637 | } 638 | saveCommand("yaraforensics " + command) 639 | 640 | } 641 | yaraforensicsCmd(c.Args, rawdisk) 642 | 643 | }, 644 | }) 645 | 646 | 647 | shell.Run() 648 | } 649 | -------------------------------------------------------------------------------- /ssdeep.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | // "encoding/gob" 6 | // "net" 7 | 8 | "github.com/glaslos/ssdeep" 9 | "strconv" 10 | "os" 11 | 12 | 13 | ) 14 | 15 | func checkSsdeep(rawdisk string) { 16 | var nameFile string 17 | 18 | var tmpsliceIOC []newResult 19 | 20 | for _, elem := range sliceSet { 21 | //fmt.Println(sliceSet) 22 | 23 | if elem.OffsetFooter == 0 { 24 | fmt.Println("[-] Please, set footer before running ssdeep") 25 | 26 | //fmt.Println(rawdisk) 27 | } else { 28 | nameFile = elem.Rule + "_" + strconv.Itoa(elem.Index) 29 | var _, err = os.Stat(workspace + "/" + nameFile) 30 | 31 | if os.IsNotExist(err) { 32 | dumpRadareFooter(rawdisk, elem.OffsetHeader, elem.OffsetFooter+uint64(len(elem.Data)), elem.Rule, strconv.Itoa(elem.Index)) 33 | } 34 | h1, err := ssdeep.FuzzyFilename(rawdisk) 35 | if err != nil && !ssdeep.Force { 36 | fmt.Println(err) 37 | os.Exit(1) 38 | } 39 | os.Remove(workspace + "/" + elem.Rule + "_" + strconv.Itoa(elem.Index)) 40 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size, Ssdeep: h1} 41 | tmpsliceIOC = append(tmpsliceIOC, resultStruct) 42 | } 43 | 44 | } 45 | 46 | sliceSet = tmpsliceIOC 47 | updateFirstResults() 48 | 49 | 50 | 51 | 52 | } 53 | 54 | func checkEverySsdeep(elem newResult) string { 55 | rawdisk = totrawdisk 56 | if elem.OffsetFooter == 0 { 57 | dumpRadare(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), elem.Rule, strconv.Itoa(elem.Index)) 58 | rawdisk = elem.Rule + "_" + strconv.Itoa(elem.Index) 59 | 60 | //fmt.Println(rawdisk) 61 | } else { 62 | dumpRadareFooter(rawdisk, elem.OffsetHeader, elem.OffsetFooter+uint64(len(elem.Data)), elem.Rule, strconv.Itoa(elem.Index)) 63 | rawdisk = elem.Rule + "_" + strconv.Itoa(elem.Index) 64 | } 65 | h1, err := ssdeep.FuzzyFilename(rawdisk) 66 | if err != nil && !ssdeep.Force { 67 | fmt.Println(err) 68 | os.Exit(1) 69 | } 70 | os.Remove(workspace + "/" + rawdisk) 71 | return h1 72 | 73 | } 74 | 75 | func checkSsdeepDistance(ssdeep1 string, file string) int { 76 | 77 | var score int 78 | ssdeep2, err := ssdeep.FuzzyFilename(file) 79 | if err != nil && !ssdeep.Force { 80 | fmt.Println(err) 81 | os.Exit(1) 82 | } 83 | //fmt.Println(ssdeep1) 84 | score, err = ssdeep.Distance(ssdeep1, ssdeep2) 85 | if err != nil { 86 | fmt.Println(err) 87 | os.Exit(1) 88 | } 89 | return score 90 | 91 | } -------------------------------------------------------------------------------- /supportFunc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 2 { 92 | index += 1 93 | 94 | newR := newResult{Rule: strings.Split(elem.rule, "_")[0], OffsetHeader: lastHeader.offset, OffsetFooter: elem.offset, Data: elem.Data, Index: index, Size: (elem.offset - lastHeader.offset)} 95 | 96 | sliceNewResults = append(sliceNewResults, newR) 97 | } 98 | } 99 | 100 | } 101 | } 102 | 103 | } 104 | 105 | return sliceNewResults 106 | } 107 | 108 | func generateNewResultYaraForensics(resultsHash []result) []newResult { 109 | 110 | var sliceNewResults []newResult 111 | 112 | var index int 113 | for _, elem := range resultsHash { 114 | 115 | index += 1 116 | newR := newResult{Rule: elem.rule, OffsetHeader: elem.offset, OffsetFooter: 0, Data: elem.Data, Index: index} 117 | sliceNewResults = append(sliceNewResults, newR) 118 | 119 | } 120 | 121 | return sliceNewResults 122 | } 123 | 124 | func printStructure(structure []newResult) { 125 | 126 | for _, elem := range structure { 127 | 128 | fmt.Println("File:" + elem.Rule) 129 | fmt.Println("\tIndex:" + strconv.Itoa(elem.Index)) 130 | fmt.Println("\tOffset Header:" + strconv.Itoa(int(elem.OffsetHeader))) 131 | fmt.Println("\tOffset Footer:" + strconv.Itoa(int(elem.OffsetFooter))) 132 | fmt.Println("\n") 133 | } 134 | } 135 | 136 | 137 | 138 | 139 | func updateResultsYara(resultsYara []result) { 140 | var tmpsliceIOC []newResult 141 | var rulesIn []string 142 | 143 | for _, elem1 := range sliceSet { 144 | for _, elem := range resultsYara { 145 | if stringInSlice(elem.rule, rulesIn) == false { 146 | rulesIn = append(rulesIn, elem.rule) 147 | 148 | } else { 149 | 150 | } 151 | } 152 | 153 | resultStruct := newResult{Rule: elem1.Rule, OffsetHeader: elem1.OffsetHeader, OffsetFooter: elem1.OffsetFooter, Data: elem1.Data, Yara: rulesIn, Ioc: elem1.Ioc, Index: elem1.Index, Hash: a, Size: (elem1.OffsetFooter - elem1.OffsetHeader)} 154 | tmpsliceIOC = append(tmpsliceIOC, resultStruct) 155 | 156 | } 157 | 158 | 159 | 160 | 161 | sliceSet = tmpsliceIOC 162 | 163 | 164 | } 165 | 166 | func generateNewResultOpenIOC(resultsHash []result) []ioc { 167 | 168 | var sliceNewResults []newResult 169 | var newsliceIOC []ioc 170 | for _, elem := range resultsHash { 171 | for _, elem1 := range sliceIOC { 172 | if elem.rule == elem1.rule { 173 | 174 | 175 | elem1.OffsetHeader = elem.offset 176 | 177 | iocStruct := ioc{rule: elem1.rule, Data: elem1.Data, OffsetHeader: elem.offset, match: false, indexMatch: 0, domain: elem1.domain} 178 | newsliceIOC = append(newsliceIOC, iocStruct) 179 | 180 | } 181 | } 182 | fmt.Println(sliceNewResults) 183 | } 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | sliceIOCmatched = newsliceIOC 193 | return sliceIOCmatched 194 | } 195 | 196 | 197 | func matchIOCfiletype() { 198 | for _, elem := range sliceNewResults { 199 | for _, elem1 := range sliceIOCmatched { 200 | if elem.Rule == elem1.rule { 201 | fmt.Println(elem.Rule) 202 | } 203 | } 204 | } 205 | } 206 | 207 | func setSlice(argument string) { 208 | var tmpslice []newResult 209 | rawdisk = totrawdisk 210 | for _, elem := range sliceSet { 211 | if argument == elem.Rule { 212 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Size: (uint64(elem.OffsetFooter) - elem.OffsetHeader)} 213 | tmpslice = append(tmpslice, resultStruct) 214 | } 215 | 216 | } 217 | 218 | sliceSet = tmpslice 219 | 220 | } 221 | 222 | func setSliceYara(rule string) { 223 | var tmpslice []newResult 224 | 225 | for _, elem := range sliceSet { 226 | 227 | for _, elem1 := range elem.Yara { 228 | if rule == elem1 { 229 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Size: elem.Size} 230 | tmpslice = append(tmpslice, resultStruct) 231 | } 232 | } 233 | 234 | } 235 | 236 | sliceSet = tmpslice 237 | 238 | } 239 | 240 | func setSliceEntropy(args []string) { 241 | var tmpslice []newResult 242 | 243 | 244 | valueEntropy, err := strconv.Atoi(args[1]) 245 | if err != nil{ 246 | fmt.Println(err) 247 | } 248 | if args[0] == ">"{ 249 | for _, elem := range sliceSet { 250 | if int(elem.Entropy) > valueEntropy{ 251 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Size: elem.Size, Entropy:elem.Entropy} 252 | tmpslice = append(tmpslice, resultStruct) 253 | } 254 | } 255 | 256 | }else{ 257 | if args[0] == "<"{ 258 | for _, elem := range sliceSet { 259 | if int(elem.Entropy) < valueEntropy{ 260 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Size: elem.Size, Entropy:elem.Entropy} 261 | tmpslice = append(tmpslice, resultStruct) 262 | } 263 | } 264 | } 265 | } 266 | sliceSet = tmpslice 267 | } 268 | 269 | 270 | 271 | func unsetSliceYara(rule string) { 272 | var tmpslice []newResult 273 | for _, elem := range sliceSet { 274 | if stringInSlice(rule, elem.Yara) { 275 | } else { 276 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index} 277 | tmpslice = append(tmpslice, resultStruct) 278 | 279 | } 280 | 281 | 282 | 283 | 284 | 285 | } 286 | 287 | sliceSet = tmpslice 288 | } 289 | 290 | func updateFirstResults() { 291 | var tmpslice []newResult 292 | var flagg bool 293 | for _, elem1 := range sliceNewResults { 294 | flagg = false 295 | for _, elem := range sliceSet { 296 | 297 | if elem1.Index == elem.Index { 298 | tmpslice = append(tmpslice, elem) 299 | flagg = true 300 | } 301 | } 302 | if flagg != true{ 303 | 304 | tmpslice = append(tmpslice, elem1) 305 | } 306 | } 307 | 308 | sliceNewResults = tmpslice 309 | } 310 | 311 | 312 | 313 | func wordCount(str string) { 314 | 315 | wordList := strings.Fields(str) 316 | counts := make(map[string]int) 317 | for _, word := range wordList { 318 | _, ok := counts[word] 319 | if ok { 320 | counts[word] += 1 321 | } else { 322 | counts[word] = 1 323 | } 324 | 325 | } 326 | fmt.Println("Results") 327 | for index, elemn := range counts { 328 | fmt.Println("\t" + index + ":" + strconv.Itoa(elemn)) 329 | } 330 | fmt.Println("\n") 331 | } 332 | 333 | func startHistory() { 334 | 335 | current_time := time.Now().Unix() 336 | historyFile = workspace + "/yaraRET_" + strconv.FormatInt(current_time, 10) 337 | fmt.Println("[+] Creating history file with name "+historyFile) 338 | os.Create(historyFile) 339 | 340 | } 341 | 342 | func saveCommand(command string) { 343 | 344 | f1, err := os.OpenFile(historyFile, os.O_APPEND|os.O_WRONLY, 0644) 345 | if err != nil { 346 | fmt.Println(err) 347 | } 348 | f1.WriteString(command) 349 | f1.WriteString("\n") 350 | 351 | } 352 | 353 | 354 | func runMagicFooter(rawdisk string) uint64 { 355 | 356 | resultsMagic := searchYara(rawdisk, workspace+"/magicrules/magic_footer.yar") 357 | for _, elem := range resultsMagic { 358 | return elem.offset 359 | } 360 | fmt.Println(resultsMagic) 361 | return 0 362 | } 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | func setBoot(rawdisk string) { 374 | var tmpslice []newResult 375 | resultsYara := searchYara(rawdisk, workspace+"/magicrules/boot.yar") 376 | 377 | for index, elem := range resultsYara { 378 | if index == 1 { 379 | resultStruct := newResult{Rule: "boot", Index: 99999, OffsetHeader: 0, OffsetFooter: elem.offset, Size: elem.offset} 380 | 381 | tmpslice = append(tmpslice, resultStruct) 382 | dumpRadareFooter(rawdisk, 0, elem.offset, elem.rule, "99999") 383 | sliceSet = tmpslice 384 | updateFirstResults() 385 | } 386 | } 387 | } 388 | 389 | func handlePEFooter() { 390 | var tmpslice []newResult 391 | fmt.Println(rawdisk) 392 | for _, elem := range sliceSet { 393 | if elem.Rule == "pe" { 394 | dumpRadare(totrawdisk, strconv.Itoa(int(elem.OffsetHeader)), elem.Rule, strconv.Itoa(elem.Index)) 395 | realSize := getSizePe(elem.Rule + "_" + strconv.Itoa(elem.Index)) 396 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetHeader + uint64(realSize), Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: uint64(realSize), Ssdeep: elem.Ssdeep} 397 | tmpslice = append(tmpslice, resultStruct) 398 | var _, err = os.Stat(workspace + "/" + elem.Rule + "_" + strconv.Itoa(elem.Index)) 399 | 400 | 401 | if os.IsNotExist(err) { 402 | } else { 403 | os.Remove(workspace + "/" + elem.Rule + "_" + strconv.Itoa(elem.Index)) 404 | } 405 | fmt.Println(realSize) 406 | } 407 | sliceSet = tmpslice 408 | updateFirstResults() 409 | } 410 | 411 | } 412 | 413 | func getSizePe(file string) uint32 { 414 | 415 | f, err := pe.Open(file) 416 | if err != nil { 417 | 418 | maxsize64, err := strconv.ParseUint(maxSizeDump, 10, 32) 419 | if err != nil { 420 | print("ERROR: ", err) 421 | } 422 | return uint32(maxsize64) 423 | } else { 424 | fmt.Println(err) 425 | defer f.Close() 426 | size := f.FileHeader.SizeOfOptionalHeader 427 | var size2 uint32 428 | 429 | for _, s := range f.Sections { 430 | size2 += s.Size 431 | 432 | } 433 | 434 | sizeTot := size2 + uint32(size) 435 | 436 | return sizeTot 437 | } 438 | } 439 | 440 | func setFooterSupport() { 441 | 442 | 443 | 444 | b, err := ioutil.ReadFile(workspace + "/magicrules/magicrules_index.yar") 445 | if err != nil { 446 | fmt.Print(err) 447 | } 448 | 449 | str := string(b) 450 | list := strings.Split(str, "\n") 451 | 452 | for _, elem := range list { 453 | 454 | if strings.Contains(elem, "footer") { 455 | f := strings.Split(elem, "\"")[1] 456 | g := strings.Split(f, "_")[0] 457 | 458 | footersupport = append(footersupport, g) 459 | 460 | } 461 | } 462 | } 463 | 464 | func setHeaderSupport() { 465 | 466 | 467 | 468 | b, err := ioutil.ReadFile(workspace + "/magicrules/magicrules_index.yar") 469 | if err != nil { 470 | fmt.Print(err) 471 | } 472 | 473 | str := string(b) 474 | list := strings.Split(str, "\n") 475 | 476 | for _, elem := range list { 477 | 478 | if strings.Contains(elem, "header") { 479 | f := strings.Split(elem, "\"")[1] 480 | g := strings.Split(f, "_")[0] 481 | 482 | headersupport = append(headersupport, g) 483 | 484 | } 485 | } 486 | } 487 | 488 | func handleBMPFooter() { 489 | var tmpslice []newResult 490 | for _, elem := range sliceSet { 491 | rawdisk = totrawdisk 492 | if elem.Rule == "bmp" { 493 | dumpRadare(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), elem.Rule, strconv.Itoa(elem.Index)) 494 | realSize := getSizeBMP(elem.Rule + "_" + strconv.Itoa(elem.Index)) 495 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetHeader + uint64(realSize), Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: uint64(realSize), Ssdeep: elem.Ssdeep} 496 | tmpslice = append(tmpslice, resultStruct) 497 | var _, err = os.Stat(workspace + "/" + elem.Rule + "_" + strconv.Itoa(elem.Index)) 498 | 499 | 500 | if os.IsNotExist(err) { 501 | } else { 502 | os.Remove(workspace + "/" + elem.Rule + "_" + strconv.Itoa(elem.Index)) 503 | } 504 | } 505 | sliceSet = tmpslice 506 | updateFirstResults() 507 | } 508 | } 509 | 510 | func getSizeBMP(rawdisk string) uint32 { 511 | 512 | var hex string 513 | r2p, err := r2pipe.NewPipe(rawdisk) 514 | if err != nil { 515 | print("ERROR: ", err) 516 | } 517 | 518 | disasm, err := r2p.Cmd("b 1") 519 | if err != nil { 520 | print("ERROR: ", err) 521 | } else { 522 | print(disasm, "") 523 | } 524 | disasm, err = r2p.Cmd("s 0x0") 525 | if err != nil { 526 | print("ERROR: ", err) 527 | } else { 528 | print(disasm, "") 529 | } 530 | disasm2, err := r2p.Cmd("s 6") 531 | if err != nil { 532 | print("ERROR: ", err) 533 | } else { 534 | print(disasm2, "") 535 | } 536 | disasm99, err := r2p.Cmd("p8") 537 | if err != nil { 538 | print("ERROR: ", err) 539 | } else { 540 | print(disasm, "") 541 | } 542 | disasm2, err = r2p.Cmd("s -1") 543 | if err != nil { 544 | print("ERROR: ", err) 545 | } else { 546 | print(disasm, "") 547 | } 548 | disasm98, err := r2p.Cmd("p8") 549 | if err != nil { 550 | print("ERROR: ", err) 551 | } else { 552 | print(disasm, "") 553 | } 554 | disasm2, err = r2p.Cmd("s -1") 555 | if err != nil { 556 | print("ERROR: ", err) 557 | } else { 558 | print(disasm, "") 559 | } 560 | disasm97, err := r2p.Cmd("p8") 561 | if err != nil { 562 | print("ERROR: ", err) 563 | } else { 564 | print(disasm, "") 565 | } 566 | disasm2, err = r2p.Cmd("s -1") 567 | if err != nil { 568 | print("ERROR: ", err) 569 | } else { 570 | print(disasm, "") 571 | } 572 | disasm96, err := r2p.Cmd("p8") 573 | if err != nil { 574 | print("ERROR: ", err) 575 | } else { 576 | print(disasm, "") 577 | } 578 | hex = disasm98 + disasm99 + disasm96 + disasm97 579 | disasm3, err := r2p.Cmd("? 0x" + hex + "~int32[1]") 580 | if err != nil { 581 | print("ERROR: ", err) 582 | } else { 583 | i, err := strconv.ParseUint(disasm3, 10, 64) 584 | if err == nil { 585 | fmt.Println(i) 586 | } 587 | r2p.Close() 588 | return uint32(i) 589 | } 590 | r2p.Close() 591 | return (0) 592 | } 593 | 594 | func yaraLightCmd(argument []string, rawdisk string) { 595 | var tmpslice []newResult 596 | var rulesIn []string 597 | var _, err = os.Stat(argument[0]) 598 | 599 | if os.IsNotExist(err) { 600 | fmt.Println("[-] Please, set a valid yara rule") 601 | } else { 602 | resultsYara := searchYara(rawdisk, argument[0]) 603 | if len(resultsYara)>0{ 604 | fmt.Println("[+] Results found!") 605 | for _, elem := range sliceSet { 606 | for _, elem1 := range resultsYara { 607 | if stringInSlice(elem1.rule, rulesIn) == false { 608 | if elem1.offset > elem.OffsetHeader && elem1.offset < elem.OffsetFooter { 609 | rulesIn = append(rulesIn, elem1.rule) 610 | fmt.Println(" [-] " + elem1.rule + " at " + elem.Rule + "_" + strconv.Itoa(elem.Index)) 611 | } 612 | } 613 | } 614 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: rulesIn, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size, Ssdeep: elem.Ssdeep} 615 | tmpslice = append(tmpslice, resultStruct) 616 | rulesIn = nil 617 | } 618 | sliceSet = tmpslice 619 | updateFirstResults() 620 | } 621 | } 622 | } 623 | 624 | func handleNextOffset(tmpslice []newResult) []newResult { 625 | var tmpslice2 []newResult 626 | for index, elem := range tmpslice { 627 | fmt.Println(index) 628 | fmt.Println(elem) 629 | 630 | 631 | 632 | 633 | 634 | 635 | } 636 | 637 | return tmpslice2 638 | } 639 | 640 | func setFile(sliceSet []newResult, argument string) { 641 | rawdisk = totrawdisk 642 | if debug { 643 | fmt.Println(rawdisk) 644 | fmt.Println(argument) 645 | } 646 | for _, elem := range sliceSet { 647 | if strconv.Itoa(elem.Index) == argument { 648 | dumpRadare(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), elem.Rule, strconv.Itoa(elem.Index)) 649 | 650 | } 651 | } 652 | 653 | } 654 | 655 | func uniqPE() { 656 | var tmpslice []newResult 657 | 658 | rawdisk = totrawdisk 659 | for _, elem := range sliceSet { 660 | dumpRadare(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), elem.Rule, strconv.Itoa(elem.Index)) 661 | 662 | fmt.Println("Estoy en uniqPE") 663 | realSize := getSizePe(workspace + "/" + elem.Rule + "_" + strconv.Itoa(elem.Index)) 664 | 665 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetHeader + uint64(realSize), Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: uint64(realSize), Ssdeep: elem.Ssdeep} 666 | tmpslice = append(tmpslice, resultStruct) 667 | 668 | } 669 | sliceSet = tmpslice 670 | } 671 | 672 | 673 | func dumpCmd(rawdisk string) { 674 | 675 | for _, elem := range sliceSet { 676 | dumpRadareFooter(rawdisk, elem.OffsetHeader, elem.OffsetFooter, elem.Rule, strconv.Itoa(elem.Index)) 677 | fmt.Println("[+] File Dumpled! " + elem.Rule + "_" + strconv.Itoa(elem.Index)) 678 | 679 | } 680 | } 681 | 682 | func setFooterMaxSize() { 683 | var tmpslice []newResult 684 | maxsize64, err := strconv.ParseUint(maxSizeDump, 10, 32) 685 | if err != nil { 686 | print("ERROR: ", err) 687 | } 688 | for _, elem := range sliceSet { 689 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetHeader + uint64(maxsize64), Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: maxsize64, Ssdeep: elem.Ssdeep} 690 | tmpslice = append(tmpslice, resultStruct) 691 | } 692 | sliceSet = tmpslice 693 | } 694 | 695 | func multPE(rawdisk string) { 696 | 697 | var tmpslice []newResult 698 | 699 | 700 | 701 | 702 | var myargument []string 703 | 704 | for _, elem := range sliceSet { 705 | dumpRadare(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), elem.Rule, strconv.Itoa(elem.Index)) 706 | 707 | myargument = append(myargument, strconv.Itoa(elem.Index)) 708 | set2Cmd(myargument, rawdisk) 709 | myargument = nil 710 | 711 | realSize := getSizePe(workspace + "/" + elem.Rule + "_" + strconv.Itoa(elem.Index)) 712 | os.Remove(workspace + "/" + elem.Rule + "_" + strconv.Itoa(elem.Index)) 713 | os.Remove(workspace + "/tmp") 714 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetHeader + uint64(realSize), Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: uint64(realSize), Ssdeep: elem.Ssdeep} 715 | tmpslice = append(tmpslice, resultStruct) 716 | } 717 | //fmt.Println(tmpslice) 718 | sliceSet = tmpslice 719 | updateFirstResults() 720 | 721 | 722 | } 723 | 724 | 725 | 726 | func uploadCmd(argument []string, rawdisk string) { 727 | 728 | if len(argument)>0{ 729 | host := argument[0] 730 | port := argument[1] 731 | for _, elem := range sliceSet { 732 | uploadRadare(rawdisk, strconv.Itoa(int(elem.OffsetHeader)), strconv.Itoa(int(elem.Size)), host, port) 733 | fmt.Println("[+]File uploaded!") 734 | 735 | 736 | } 737 | }else{ 738 | fmt.Println("[!] Please, set the host and the port of the server") 739 | } 740 | } 741 | 742 | 743 | 744 | 745 | func lastItemStruct() { 746 | var tmpslice []newResult 747 | for item, elem := range sliceSet { 748 | 749 | if (item + 1) < len(sliceSet) { 750 | if (sliceSet[item+1].OffsetHeader) < elem.OffsetFooter { 751 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: sliceSet[item+1].OffsetHeader - 1, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size} 752 | tmpslice = append(tmpslice, resultStruct) 753 | } else { 754 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: sliceSet[item+1].OffsetHeader - 1, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size} 755 | tmpslice = append(tmpslice, resultStruct) 756 | } 757 | 758 | } 759 | } 760 | sliceSet = tmpslice 761 | } 762 | 763 | 764 | 765 | 766 | func putTag(argument string){ 767 | 768 | var tmpslice []newResult 769 | 770 | for _, elem := range sliceSet{ 771 | resultStruct := newResult{Rule: elem.Rule, OffsetHeader: elem.OffsetHeader, OffsetFooter: elem.OffsetFooter, Data: elem.Data, Yara: elem.Yara, Ioc: elem.Ioc, Index: elem.Index, Hash: elem.Hash, Size: elem.Size, Ssdeep: elem.Ssdeep, Tag: argument} 772 | tmpslice = append(tmpslice, resultStruct) 773 | 774 | } 775 | sliceSet = tmpslice 776 | } 777 | 778 | -------------------------------------------------------------------------------- /workspace.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | 22 | package main 23 | 24 | func varCmd(argument []string, rawdisk string) { 25 | switch option := argument[0]; option { 26 | case "maxsize": 27 | maxSizeDump = (argument[1]) 28 | case "magicpath": 29 | magicPath = argument[1] 30 | case "debug": 31 | debug = true 32 | case "history": 33 | 34 | startHistory() 35 | 36 | verbose = true 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /yaraPipe.go: -------------------------------------------------------------------------------- 1 | /* 2 | Open Source Initiative OSI - The MIT License (MIT):Licensing 3 | The MIT License (MIT) 4 | Copyright (c) 2013 DutchCoders 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | 22 | package main 23 | 24 | 25 | import ( 26 | "fmt" 27 | // "encoding/gob" 28 | // "net" 29 | "bufio" 30 | "sort" 31 | "strconv" 32 | "log" 33 | "strings" 34 | "os" 35 | yara "github.com/hillu/go-yara" 36 | ) 37 | 38 | 39 | func extractFromYara(rawdisk string, yarafile string, maxsize string, filetype string) { 40 | //var v []result 41 | var offsetExtracted []string 42 | count := 0 43 | count2 := 0 44 | //supported := []string{"threegp","sevenzip","amazonkindleupdate","appleworks5","appleworks6","avi","bmp","bzip","canonraw","crx","dalvik","dat","dba","deb","dmg","doc","elf64","flac","flash","gif","gzip","is","javaclass","jpg","kodakcineon","macho","microsoftOffice","midi","mkv","mp3","mpeg","ost","pcap","pcapng","pdf","pe","png","pds","pst","pyc","rar","rpm","rtf","tape","tar","tarzip","tiff","utf8","vmdk","wasm","wav","woff","xar","xml","xz","zip","zlib"} 45 | fmt.Println("[+] Running Yara..") 46 | resultsToT := searchYara(rawdisk, yarafile) 47 | 48 | maxsizeInt, err := strconv.ParseFloat(maxsize, 64) 49 | if err != nil { 50 | fmt.Println(err) 51 | } 52 | 53 | if len(resultsToT)==0{ 54 | 55 | fmt.Println("[!] Not results found") 56 | }else{ 57 | 58 | fmt.Println("[+] " + strconv.Itoa(len(resultsToT)) + " match found") 59 | fmt.Println("[-] Looking for magic numbers") 60 | resultsMagic := findAllData(rawdisk) 61 | 62 | for _, result := range resultsToT{ 63 | count2 = count2 +1 64 | fmt.Println("[-] Looking for magic around "+result.rule+"_"+strconv.Itoa(count2)) 65 | 66 | top := result.offset - uint64(maxsizeInt) 67 | 68 | for _, magic := range resultsMagic{ 69 | if magic.offset > top { 70 | if magic.offset < result.offset{ 71 | if stringInSlice(strconv.Itoa(int(magic.offset)), offsetExtracted){ 72 | }else{ 73 | count = count +1 74 | dumpRadareFooter(rawdisk, magic.offset, magic.offset+2*uint64(maxsizeInt), strings.Split(result.rule, "_")[0], strconv.Itoa(count)) 75 | fmt.Println("[+] Dumped file:\n\t[-] Rule: " + strings.Split(result.rule, "_")[0] + "\n\t[-] Name: " + result.rule + "\n\t[-] FileType: " + strings.Split(magic.rule, "_")[0]) 76 | offsetExtracted = append(offsetExtracted, strconv.Itoa(int(magic.offset))) 77 | } 78 | } 79 | } 80 | 81 | } 82 | } 83 | 84 | 85 | 86 | } 87 | 88 | } 89 | 90 | 91 | 92 | func searchYara(rawdisk string, yarafile string) []result { 93 | 94 | var v []result 95 | //var sortResult []result 96 | comp, err := yara.NewCompiler() 97 | f, err := os.Open(yarafile) 98 | if err != nil { 99 | log.Fatalf("Could not open rule file: %s", err) 100 | } 101 | comp.AddFile(f, "") 102 | rules, err := comp.GetRules() 103 | if err != nil { 104 | //log.Fatalf("Failed to initialize YARA compiler: %s", err) 105 | fmt.Println(err) 106 | } 107 | 108 | matches, err := rules.ScanFile(rawdisk, 0, 0) 109 | if err != nil { 110 | //fmt.Println("Error en el compilador") 111 | fmt.Println(err) 112 | } 113 | 114 | for _, matches := range matches { 115 | for _, stringf := range matches.Strings { 116 | s := result{rule: matches.Rule, offset: stringf.Offset, Data: stringf.Data} 117 | v = append(v, s) 118 | //fmt.Println(s) 119 | //fmt.Println("[+] Match! "+s.rule) 120 | } 121 | } 122 | //sortResult :=sortResultsByOffset(v) 123 | //fmt.Println(v) 124 | //sort.Sort 125 | sort.Sort(offsetSorter(v)) 126 | //sortResult =sort.Sort(offsetSorter(v)) 127 | //fmt.Println(v) 128 | return v 129 | 130 | } 131 | 132 | 133 | 134 | func runHash(rawdisk string, filetype string, hashes string) { 135 | 136 | var tmpslice []newResult 137 | var count int 138 | 139 | yarafileHeader := workspace + "/magicrules/" + filetype + "_header.yar" 140 | yarafileFooter := workspace + "/magicrules/" + filetype + "_footer.yar" 141 | //var lastResult result 142 | 143 | //var newR newResult 144 | 145 | resultsHash := searchYara(rawdisk, yarafileHeader) 146 | resultsHash2 := searchYara(rawdisk, yarafileFooter) 147 | 148 | sliceNewResults := generateNewResult(resultsHash) 149 | 150 | for index, elem := range sliceNewResults { 151 | count = count + 1 152 | result := newResult{Rule: elem.Rule, OffsetHeader: sliceNewResults[index].OffsetHeader, OffsetFooter: resultsHash2[index].offset + uint64(len(resultsHash2[index].Data)-1), Index: elem.Index} 153 | tmpslice = append(tmpslice, result) 154 | 155 | } 156 | 157 | //fmt.Println("[+] "+strconv.Itoa(count)+" "+filetype+" found") 158 | 159 | file, err := os.Open(hashes) 160 | if err != nil { 161 | fmt.Println(err) 162 | } 163 | defer file.Close() 164 | 165 | scanner := bufio.NewScanner(file) 166 | scanner.Split(bufio.ScanLines) 167 | 168 | // This is our buffer now 169 | var lines []string 170 | 171 | for scanner.Scan() { 172 | lines = append(lines, scanner.Text()) 173 | } 174 | 175 | for _, elem3 := range tmpslice { 176 | 177 | //fmt.Println("[+] Header "+strconv.Itoa(int(elem3.OffsetHeader))+" Offset:"+strconv.Itoa(int(elem3.OffsetFooter))+" :") 178 | hashTmp := getHashReturn(rawdisk, elem3.OffsetHeader, elem3.OffsetFooter) 179 | for _, elem5 := range lines { 180 | if elem5 == hashTmp { 181 | fmt.Println("[+] Match " + elem5 + " at " + strconv.Itoa(int(elem3.OffsetHeader))) 182 | } 183 | 184 | } 185 | } 186 | 187 | //fmt.Println(resultsHash) 188 | 189 | //fmt.Println(sliceNewResults) 190 | 191 | } 192 | 193 | 194 | func buildRuleOneliner(offset1 string, offset2 string, filetype string) string{ 195 | body := returnBody(filetype) 196 | body1 := strings.Replace(body,"COUNT",offset1,-1) 197 | //fmt.Println(body1) 198 | condition := returnCondition(offset1, offset2) 199 | //fmt.Println(condition) 200 | rule := body1+condition 201 | 202 | return rule 203 | 204 | } --------------------------------------------------------------------------------