├── vendor ├── github.com │ └── twmb │ │ └── murmur3 │ │ ├── .gitignore │ │ ├── go.mod │ │ ├── .travis.yml │ │ ├── murmur128_decl.go │ │ ├── murmur32_gen.go │ │ ├── murmur.go │ │ ├── murmur64.go │ │ ├── murmur32.go │ │ ├── LICENSE │ │ ├── murmur128_gen.go │ │ ├── murmur128.go │ │ ├── murmur128_amd64.s │ │ └── README.md └── modules.txt ├── test ├── fixture │ ├── test_Check_iconhash_url.golden │ ├── test_Check_iconhash_file.golden │ ├── test_Check_iconhash_other_url.golden │ ├── test_Check_iconhash_args_file_no_fofa.golden │ ├── test_Check_iconhash_args_other_file.golden │ ├── test_Check_iconhash_args_file.golden │ ├── test_Check_iconhash_args_other_file_uint32.golden │ ├── test_Check_iconhash_args_url.golden │ ├── test_Check_iconhash_args_file_no_fofa_no_shodan.golden │ ├── test_Check_iconhash_file_not_exist.golden │ ├── test_Check_iconhash_args_file_no_fofa_shodan.golden │ ├── test_Check_iconhash_args_url_shodan.golden │ ├── test_Check_iconhash_args_file_shodan.golden │ ├── test_Check_iconhash_help.golden │ └── test_Check_iconhash_file_other.golden ├── data │ ├── dede.ico │ ├── favicon.ico │ └── baiduimgb64.txt ├── test_helper.bash └── main.bats ├── Dockerfile ├── go.mod ├── go.sum ├── .travis.yml ├── iconhash.go ├── .github └── workflows │ ├── bats.yml │ └── release.yml ├── .goreleaser.yml ├── .gitignore ├── .golangci.yml ├── Makefile ├── README.md └── config.go /vendor/github.com/twmb/murmur3/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_url.golden: -------------------------------------------------------------------------------- 1 | -47597126 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_file.golden: -------------------------------------------------------------------------------- 1 | -1507567067 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_other_url.golden: -------------------------------------------------------------------------------- 1 | -1507567067 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_file_no_fofa.golden: -------------------------------------------------------------------------------- 1 | -1507567067 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_other_file.golden: -------------------------------------------------------------------------------- 1 | -47597126 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_file.golden: -------------------------------------------------------------------------------- 1 | icon_hash="-1507567067" 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_other_file_uint32.golden: -------------------------------------------------------------------------------- 1 | 4247370170 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_url.golden: -------------------------------------------------------------------------------- 1 | icon_hash="-47597126" 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_file_no_fofa_no_shodan.golden: -------------------------------------------------------------------------------- 1 | -1507567067 2 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_file_not_exist.golden: -------------------------------------------------------------------------------- 1 | not file or url please check 2 | -------------------------------------------------------------------------------- /test/data/dede.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Becivells/iconhash/HEAD/test/data/dede.ico -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/twmb/murmur3 2 | 3 | go 1.11 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | COPY iconhash /usr/bin/iconhash 3 | ENTRYPOINT ["/usr/bin/iconhash"] -------------------------------------------------------------------------------- /test/data/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Becivells/iconhash/HEAD/test/data/favicon.ico -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_file_no_fofa_shodan.golden: -------------------------------------------------------------------------------- 1 | http.favicon.hash:-1507567067 2 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/twmb/murmur3 v1.1.3 2 | ## explicit 3 | github.com/twmb/murmur3 4 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/becivells/iconhash 2 | 3 | go 1.14 4 | 5 | require github.com/twmb/murmur3 v1.1.3 6 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_url_shodan.golden: -------------------------------------------------------------------------------- 1 | icon_hash="-47597126" 2 | http.favicon.hash:-47597126 3 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_args_file_shodan.golden: -------------------------------------------------------------------------------- 1 | icon_hash="-1507567067" 2 | http.favicon.hash:-1507567067 3 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: go 4 | 5 | go: 6 | - "1.10" 7 | - "1.11" 8 | 9 | notifications: 10 | email: false 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/twmb/murmur3 v1.1.3 h1:D83U0XYKcHRYwYIpBKf3Pks91Z0Byda/9SJ8B6EMRcA= 2 | github.com/twmb/murmur3 v1.1.3/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.12.x" 5 | - "1.13.x" 6 | - "1.14.x" 7 | 8 | sudo: required 9 | 10 | dist: xenial 11 | 12 | 13 | before_install: 14 | - sudo add-apt-repository ppa:duggan/bats --yes 15 | - sudo apt-get update -qq 16 | - sudo apt-get install -qq bats 17 | 18 | script: 19 | - make 20 | - make test-cli -------------------------------------------------------------------------------- /test/test_helper.bash: -------------------------------------------------------------------------------- 1 | setup() { 2 | export ICONHASH_DEV_DIRNAME="${BATS_TEST_DIRNAME}/.." 3 | export ICONHASH_BIN="${ICONHASH_DEV_DIRNAME}/bin/iconhash" 4 | export TEST_DATA="${BATS_TEST_DIRNAME}/data" 5 | export BATS_TMP_DIRNAME="${BATS_TEST_DIRNAME}/tmp" 6 | export BATS_FIXTURE_DIRNAME="${BATS_TEST_DIRNAME}/fixture" 7 | export LC_ALL=C # Linux macOS 下 sort 排序问题 8 | mkdir -p "${BATS_TMP_DIRNAME}" 9 | } 10 | 11 | # golden_diff like gofmt golden file check method, use this function check output different with template 12 | golden_diff() { 13 | diff "${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden" "${BATS_FIXTURE_DIRNAME}/${BATS_TEST_NAME}.golden" 14 | } -------------------------------------------------------------------------------- /iconhash.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // PrintErr 打印错误并输出标准错误 9 | func PrintErr(err error) { 10 | if Debug { 11 | panic(err) 12 | } 13 | fmt.Printf("%s\n", err) 14 | os.Exit(1) 15 | } 16 | 17 | func main() { 18 | if HashURL != "" { 19 | content, err := FromURLGetContent(HashURL) 20 | 21 | if err != nil { 22 | PrintErr(err) 23 | } 24 | 25 | PrintResult(Mmh3Hash32(StandBase64(content))) 26 | os.Exit(0) 27 | } 28 | 29 | if Hashfile != "" { 30 | content, err := FromfileGetContent(Hashfile) 31 | 32 | if err != nil { 33 | PrintErr(err) 34 | } 35 | 36 | PrintResult(Mmh3Hash32(StandBase64(content))) 37 | os.Exit(0) 38 | } 39 | 40 | if ImageBase64 != "" { 41 | content, err := FromfileGetContent(ImageBase64) 42 | 43 | if err != nil { 44 | PrintErr(err) 45 | } 46 | 47 | PrintResult(Mmh3Hash32(SplitChar76(content))) 48 | os.Exit(0) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_help.golden: -------------------------------------------------------------------------------- 1 | Usage of bin/iconhash: 2 | -b64 string 3 | mmh3 hash image base64 from file 4 | iconhash -file test/favicon.ico 5 | -debug 6 | debug mode 7 | -file string 8 | mmh3 hash from file 9 | iconhash -file favicon.ico 10 | -fofa 11 | fofa search format (default true) 12 | -h look help 13 | iconhash favicon.ico 14 | iconhash https://www.baidu.com/favicon.ico 15 | -shodan 16 | shodan search format 17 | iconhash -file test/favicon.ico -shodan -fofa=false 18 | -skip-verify 19 | https InsecureSkipVerify (default true) 20 | -uint32 21 | uint32 22 | -url string 23 | mmh3 hash from url 24 | iconhash -url https://www.baidu.com/favicon.ico 25 | -user-agent string 26 | mmh3 hash from url (default "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11") 27 | -v version 28 | -------------------------------------------------------------------------------- /test/fixture/test_Check_iconhash_file_other.golden: -------------------------------------------------------------------------------- 1 | Usage of /Users/wenzhi/code/goland/iconhash/test/../bin/iconhash: 2 | -b64 string 3 | mmh3 hash image base64 from file 4 | iconhash -file test/favicon.ico 5 | -debug 6 | debug mode 7 | -file string 8 | mmh3 hash from file 9 | iconhash -file favicon.ico 10 | -fofa 11 | fofa search format (default true) 12 | -h look help 13 | iconhash favicon.ico 14 | iconhash https://www.baidu.com/favicon.ico 15 | -shodan 16 | shodan search format 17 | iconhash -file test/favicon.ico -shodan -fofa=false 18 | -skip-verify 19 | https InsecureSkipVerify (default true) 20 | -uint32 21 | uint32 22 | -url string 23 | mmh3 hash from url 24 | iconhash -url https://www.baidu.com/favicon.ico 25 | -user-agent string 26 | mmh3 hash from url (default "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11") 27 | -v version 28 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/murmur128_decl.go: -------------------------------------------------------------------------------- 1 | // +build go1.5,amd64 2 | 3 | package murmur3 4 | 5 | //go:noescape 6 | 7 | // Sum128 returns the murmur3 sum of data. It is equivalent to the following 8 | // sequence (without the extra burden and the extra allocation): 9 | // hasher := New128() 10 | // hasher.Write(data) 11 | // return hasher.Sum128() 12 | func Sum128(data []byte) (h1 uint64, h2 uint64) 13 | 14 | //go:noescape 15 | 16 | // SeedSum128 returns the murmur3 sum of data with digests initialized to seed1 17 | // and seed2. 18 | // 19 | // The canonical implementation allows only one uint32 seed; to imitate that 20 | // behavior, use the same, uint32-max seed for seed1 and seed2. 21 | // 22 | // This reads and processes the data in chunks of little endian uint64s; 23 | // thus, the returned hashes are portable across architectures. 24 | func SeedSum128(seed1, seed2 uint64, data []byte) (h1 uint64, h2 uint64) 25 | 26 | //go:noescape 27 | 28 | // StringSum128 is the string version of Sum128. 29 | func StringSum128(data string) (h1 uint64, h2 uint64) 30 | 31 | //go:noescape 32 | 33 | // SeedStringSum128 is the string version of SeedSum128. 34 | func SeedStringSum128(seed1, seed2 uint64, data string) (h1 uint64, h2 uint64) 35 | -------------------------------------------------------------------------------- /.github/workflows/bats.yml: -------------------------------------------------------------------------------- 1 | name: bats test 2 | 3 | on: [push, pull_request] 4 | jobs: 5 | golangci-lint: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout code 9 | uses: actions/checkout@v2 10 | - name: Run golangci-lint 11 | uses: golangci/golangci-lint-action@v2.5.2 12 | with: 13 | version: v1.40 14 | args: --timeout 5m 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - 19 | name: Checkout 20 | uses: actions/checkout@v2 21 | with: 22 | fetch-depth: 0 23 | - 24 | name: Set up Go 25 | uses: actions/setup-go@v2 26 | with: 27 | go-version: 1.16.3 28 | - 29 | name: Cache Go modules 30 | uses: actions/cache@v1 31 | with: 32 | path: ~/go/pkg/mod 33 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 34 | restore-keys: | 35 | ${{ runner.os }}-go- 36 | - 37 | name: Setup BATS 38 | uses: mig4/setup-bats@v1 39 | with: 40 | bats-version: 1.3.0 41 | - name: test bats 42 | shell: bash 43 | working-directory: ${{github.workspace}} 44 | run: | 45 | make 46 | make test-cli 47 | 48 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - 12 | name: Checkout 13 | uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | - 17 | name: Set up Go 18 | uses: actions/setup-go@v2 19 | with: 20 | go-version: 1.16.3 21 | - 22 | name: Cache Go modules 23 | uses: actions/cache@v1 24 | with: 25 | path: ~/go/pkg/mod 26 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 27 | restore-keys: | 28 | ${{ runner.os }}-go- 29 | - 30 | name: Tests 31 | run: | 32 | go mod tidy 33 | go test -v ./... 34 | - 35 | name: Docker Login 36 | uses: docker/login-action@v1 37 | with: 38 | username: ${{ secrets.DOCKERHUB_USERNAME }} 39 | password: ${{ secrets.DOCKERHUB_TOKEN }} 40 | - 41 | name: Run GoReleaser 42 | uses: goreleaser/goreleaser-action@v2 43 | if: success() && startsWith(github.ref, 'refs/tags/') 44 | with: 45 | version: latest 46 | args: release --rm-dist 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # This is an example goreleaser.yaml file with some sane defaults. 2 | # Make sure to check the documentation at http://goreleaser.com 3 | # https://goreleaser.com/customization/build/ 4 | project_name: iconhash 5 | gomod: 6 | proxy: true 7 | builds: 8 | - env: [CGO_ENABLED=0] 9 | goos: 10 | - linux 11 | - windows 12 | - darwin 13 | goarch: 14 | - amd64 15 | - 386 16 | - arm64 17 | ignore: 18 | - goos: darwin 19 | goarch: 386 20 | archives: 21 | - 22 | format_overrides: 23 | - goos: windows 24 | format: zip 25 | checksum: 26 | name_template: 'checksums.txt' 27 | snapshot: 28 | name_template: "{{ .Tag }}-next" 29 | changelog: 30 | sort: asc 31 | filters: 32 | exclude: 33 | - '^docs:' 34 | - '^test:' 35 | dockers: 36 | - image_templates: ["becivells/iconhash:{{ .Version }}"] 37 | dockerfile: Dockerfile 38 | build_flag_templates: 39 | - --label=org.opencontainers.image.title={{ .ProjectName }} 40 | - --label=org.opencontainers.image.description={{ .ProjectName }} 41 | - --label=org.opencontainers.image.url=https://github.com/becivells/iconhash 42 | - --label=org.opencontainers.image.source=https://github.com/becivells/iconhash 43 | - --label=org.opencontainers.image.version={{ .Version }} 44 | - --label=org.opencontainers.image.created={{ time "2006-01-02T15:04:05Z07:00" }} 45 | - --label=org.opencontainers.image.revision={{ .FullCommit }} 46 | - --label=org.opencontainers.image.licenses=MIT 47 | nfpms: 48 | - maintainer: becivells 49 | description: fofa shodan iconhash 50 | homepage: https://github.com/becivells/iconhash 51 | license: MIT 52 | formats: 53 | - deb 54 | - rpm -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/murmur32_gen.go: -------------------------------------------------------------------------------- 1 | package murmur3 2 | 3 | import "math/bits" 4 | 5 | // SeedSum32 returns the murmur3 sum of data with the digest initialized to 6 | // seed. 7 | // 8 | // This reads and processes the data in chunks of little endian uint32s; 9 | // thus, the returned hash is portable across architectures. 10 | func SeedSum32(seed uint32, data []byte) (h1 uint32) { 11 | return SeedStringSum32(seed, strslice(data)) 12 | } 13 | 14 | // Sum32 returns the murmur3 sum of data. It is equivalent to the following 15 | // sequence (without the extra burden and the extra allocation): 16 | // hasher := New32() 17 | // hasher.Write(data) 18 | // return hasher.Sum32() 19 | func Sum32(data []byte) uint32 { 20 | return SeedStringSum32(0, strslice(data)) 21 | } 22 | 23 | // StringSum32 is the string version of Sum32. 24 | func StringSum32(data string) uint32 { 25 | return SeedStringSum32(0, data) 26 | } 27 | 28 | // SeedStringSum32 is the string version of SeedSum32. 29 | func SeedStringSum32(seed uint32, data string) (h1 uint32) { 30 | h1 = seed 31 | clen := uint32(len(data)) 32 | for len(data) >= 4 { 33 | k1 := uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16 | uint32(data[3])<<24 34 | data = data[4:] 35 | 36 | k1 *= c1_32 37 | k1 = bits.RotateLeft32(k1, 15) 38 | k1 *= c2_32 39 | 40 | h1 ^= k1 41 | h1 = bits.RotateLeft32(h1, 13) 42 | h1 = h1*5 + 0xe6546b64 43 | } 44 | var k1 uint32 45 | switch len(data) { 46 | case 3: 47 | k1 ^= uint32(data[2]) << 16 48 | fallthrough 49 | case 2: 50 | k1 ^= uint32(data[1]) << 8 51 | fallthrough 52 | case 1: 53 | k1 ^= uint32(data[0]) 54 | k1 *= c1_32 55 | k1 = bits.RotateLeft32(k1, 15) 56 | k1 *= c2_32 57 | h1 ^= k1 58 | } 59 | 60 | h1 ^= uint32(clen) 61 | 62 | h1 ^= h1 >> 16 63 | h1 *= 0x85ebca6b 64 | h1 ^= h1 >> 13 65 | h1 *= 0xc2b2ae35 66 | h1 ^= h1 >> 16 67 | 68 | return h1 69 | } 70 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/murmur.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Sébastien Paolacci. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package murmur3 provides an amd64 native (Go generic fallback) 6 | // implementation of the murmur3 hash algorithm for strings and slices. 7 | // 8 | // Assembly is provided for amd64 go1.5+; pull requests are welcome for other 9 | // architectures. 10 | package murmur3 11 | 12 | import ( 13 | "reflect" 14 | "unsafe" 15 | ) 16 | 17 | type bmixer interface { 18 | bmix(p []byte) (tail []byte) 19 | Size() (n int) 20 | reset() 21 | } 22 | 23 | type digest struct { 24 | clen int // Digested input cumulative length. 25 | tail []byte // 0 to Size()-1 bytes view of `buf'. 26 | buf [16]byte // Expected (but not required) to be Size() large. 27 | bmixer 28 | } 29 | 30 | func (d *digest) BlockSize() int { return 1 } 31 | 32 | func (d *digest) Write(p []byte) (n int, err error) { 33 | n = len(p) 34 | d.clen += n 35 | 36 | if len(d.tail) > 0 { 37 | // Stick back pending bytes. 38 | nfree := d.Size() - len(d.tail) // nfree ∈ [1, d.Size()-1]. 39 | if nfree < len(p) { 40 | // One full block can be formed. 41 | block := append(d.tail, p[:nfree]...) 42 | p = p[nfree:] 43 | _ = d.bmix(block) // No tail. 44 | } else { 45 | // Tail's buf is large enough to prevent reallocs. 46 | p = append(d.tail, p...) 47 | } 48 | } 49 | 50 | d.tail = d.bmix(p) 51 | 52 | // Keep own copy of the 0 to Size()-1 pending bytes. 53 | nn := copy(d.buf[:], d.tail) 54 | d.tail = d.buf[:nn] 55 | 56 | return n, nil 57 | } 58 | 59 | func (d *digest) Reset() { 60 | d.clen = 0 61 | d.tail = nil 62 | d.bmixer.reset() 63 | } 64 | 65 | func strslice(slice []byte) string { 66 | var str string 67 | *(*reflect.StringHeader)(unsafe.Pointer(&str)) = reflect.StringHeader{ 68 | Data: ((*reflect.SliceHeader)(unsafe.Pointer(&slice))).Data, 69 | Len: len(slice), 70 | } 71 | return str 72 | } 73 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/murmur64.go: -------------------------------------------------------------------------------- 1 | package murmur3 2 | 3 | import ( 4 | "hash" 5 | ) 6 | 7 | // Make sure interfaces are correctly implemented. 8 | var ( 9 | _ hash.Hash = new(digest64) 10 | _ hash.Hash64 = new(digest64) 11 | _ bmixer = new(digest64) 12 | ) 13 | 14 | // digest64 is half a digest128. 15 | type digest64 digest128 16 | 17 | // SeedNew64 returns a hash.Hash64 for streaming 64 bit sums. As the canonical 18 | // implementation does not support Sum64, this uses SeedNew128(seed, seed) 19 | func SeedNew64(seed uint64) hash.Hash64 { 20 | return (*digest64)(SeedNew128(seed, seed).(*digest128)) 21 | } 22 | 23 | // New64 returns a hash.Hash64 for streaming 64 bit sums. 24 | func New64() hash.Hash64 { 25 | return SeedNew64(0) 26 | } 27 | 28 | func (d *digest64) Sum(b []byte) []byte { 29 | h1 := d.Sum64() 30 | return append(b, 31 | byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32), 32 | byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1)) 33 | } 34 | 35 | func (d *digest64) Sum64() uint64 { 36 | h1, _ := (*digest128)(d).Sum128() 37 | return h1 38 | } 39 | 40 | // Sum64 returns the murmur3 sum of data. It is equivalent to the following 41 | // sequence (without the extra burden and the extra allocation): 42 | // hasher := New64() 43 | // hasher.Write(data) 44 | // return hasher.Sum64() 45 | func Sum64(data []byte) uint64 { 46 | h1, _ := Sum128(data) 47 | return h1 48 | } 49 | 50 | // SeedSum64 returns the murmur3 sum of data with the digest initialized to 51 | // seed. 52 | // 53 | // Because the canonical implementation does not support SeedSum64, this uses 54 | // SeedSum128(seed, seed, data). 55 | func SeedSum64(seed uint64, data []byte) uint64 { 56 | h1, _ := SeedSum128(seed, seed, data) 57 | return h1 58 | } 59 | 60 | // StringSum64 is the string version of Sum64. 61 | func StringSum64(data string) uint64 { 62 | h1, _ := StringSum128(data) 63 | return h1 64 | } 65 | 66 | // SeedStringSum64 is the string version of SeedSum64. 67 | func SeedStringSum64(seed uint64, data string) uint64 { 68 | h1, _ := SeedStringSum128(seed, seed, data) 69 | return h1 70 | } 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/go,linux,macos,windows 2 | # Edit at https://www.gitignore.io/?templates=go,linux,macos,windows 3 | 4 | ### Go ### 5 | # Binaries for programs and plugins 6 | *.exe 7 | *.exe~ 8 | *.dll 9 | *.so 10 | *.dylib 11 | 12 | bin/ 13 | release/ 14 | iconhash 15 | test/tmp/ 16 | doc/blueprint/ 17 | *.iml 18 | *.swp 19 | *.log 20 | coverage.* 21 | y.output 22 | bindata.go 23 | pld-autop 24 | .DS_Store 25 | .vscode/ 26 | .idea 27 | _tools/ 28 | # Test binary, built with `go test -c` 29 | *.test 30 | 31 | # Output of the go coverage tool, specifically when used with LiteIDE 32 | *.out 33 | 34 | # Dependency directories (remove the comment below to include it) 35 | # vendor/ 36 | 37 | ### Go Patch ### 38 | /Godeps/ 39 | 40 | ### Linux ### 41 | *~ 42 | 43 | # temporary files which can be created if a process still has a handle open of a deleted file 44 | .fuse_hidden* 45 | 46 | # KDE directory preferences 47 | .directory 48 | 49 | # Linux trash folder which might appear on any partition or disk 50 | .Trash-* 51 | 52 | # .nfs files are created when an open file is removed but is still being accessed 53 | .nfs* 54 | 55 | ### macOS ### 56 | # General 57 | .DS_Store 58 | .AppleDouble 59 | .LSOverride 60 | 61 | 62 | # Thumbnails 63 | ._* 64 | 65 | # Files that might appear in the root of a volume 66 | .DocumentRevisions-V100 67 | .fseventsd 68 | .Spotlight-V100 69 | .TemporaryItems 70 | .Trashes 71 | .VolumeIcon.icns 72 | .com.apple.timemachine.donotpresent 73 | 74 | # Directories potentially created on remote AFP share 75 | .AppleDB 76 | .AppleDesktop 77 | Network Trash Folder 78 | Temporary Items 79 | .apdisk 80 | 81 | ### Windows ### 82 | # Windows thumbnail cache files 83 | Thumbs.db 84 | Thumbs.db:encryptable 85 | ehthumbs.db 86 | ehthumbs_vista.db 87 | 88 | # Dump file 89 | *.stackdump 90 | 91 | # Folder config file 92 | [Dd]esktop.ini 93 | 94 | # Recycle Bin used on file shares 95 | $RECYCLE.BIN/ 96 | 97 | # Windows Installer files 98 | *.cab 99 | *.msi 100 | *.msix 101 | *.msm 102 | *.msp 103 | 104 | # Windows shortcuts 105 | *.lnk 106 | 107 | # End of https://www.gitignore.io/api/go,linux,macos,windowsdist/ 108 | dist/ 109 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/murmur32.go: -------------------------------------------------------------------------------- 1 | package murmur3 2 | 3 | import ( 4 | "hash" 5 | "math/bits" 6 | ) 7 | 8 | // Make sure interfaces are correctly implemented. 9 | var ( 10 | _ hash.Hash = new(digest32) 11 | _ hash.Hash32 = new(digest32) 12 | ) 13 | 14 | const ( 15 | c1_32 uint32 = 0xcc9e2d51 16 | c2_32 uint32 = 0x1b873593 17 | ) 18 | 19 | // digest32 represents a partial evaluation of a 32 bites hash. 20 | type digest32 struct { 21 | digest 22 | seed uint32 23 | h1 uint32 // Unfinalized running hash. 24 | } 25 | 26 | // SeedNew32 returns a hash.Hash32 for streaming 32 bit sums with its internal 27 | // digest initialized to seed. 28 | // 29 | // This reads and processes the data in chunks of little endian uint32s; 30 | // thus, the returned hash is portable across architectures. 31 | func SeedNew32(seed uint32) hash.Hash32 { 32 | d := &digest32{seed: seed} 33 | d.bmixer = d 34 | d.Reset() 35 | return d 36 | } 37 | 38 | // New32 returns a hash.Hash32 for streaming 32 bit sums. 39 | func New32() hash.Hash32 { 40 | return SeedNew32(0) 41 | } 42 | 43 | func (d *digest32) Size() int { return 4 } 44 | 45 | func (d *digest32) reset() { d.h1 = d.seed } 46 | 47 | func (d *digest32) Sum(b []byte) []byte { 48 | h := d.Sum32() 49 | return append(b, byte(h>>24), byte(h>>16), byte(h>>8), byte(h)) 50 | } 51 | 52 | // Digest as many blocks as possible. 53 | func (d *digest32) bmix(p []byte) (tail []byte) { 54 | h1 := d.h1 55 | 56 | for len(p) >= 4 { 57 | k1 := uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 58 | p = p[4:] 59 | 60 | k1 *= c1_32 61 | k1 = bits.RotateLeft32(k1, 15) 62 | k1 *= c2_32 63 | 64 | h1 ^= k1 65 | h1 = bits.RotateLeft32(h1, 13) 66 | h1 = h1*5 + 0xe6546b64 67 | } 68 | d.h1 = h1 69 | return p 70 | } 71 | 72 | func (d *digest32) Sum32() (h1 uint32) { 73 | 74 | h1 = d.h1 75 | var k1 uint32 76 | switch len(d.tail) & 3 { 77 | case 3: 78 | k1 ^= uint32(d.tail[2]) << 16 79 | fallthrough 80 | case 2: 81 | k1 ^= uint32(d.tail[1]) << 8 82 | fallthrough 83 | case 1: 84 | k1 ^= uint32(d.tail[0]) 85 | k1 *= c1_32 86 | k1 = bits.RotateLeft32(k1, 15) 87 | k1 *= c2_32 88 | h1 ^= k1 89 | } 90 | 91 | h1 ^= uint32(d.clen) 92 | 93 | h1 ^= h1 >> 16 94 | h1 *= 0x85ebca6b 95 | h1 ^= h1 >> 13 96 | h1 *= 0xc2b2ae35 97 | h1 ^= h1 >> 16 98 | 99 | return h1 100 | } 101 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013, Sébastien Paolacci. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the library nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | Copyright 2018, Travis Bischel. 27 | All rights reserved. 28 | 29 | Redistribution and use in source and binary forms, with or without 30 | modification, are permitted provided that the following conditions are met: 31 | * Redistributions of source code must retain the above copyright 32 | notice, this list of conditions and the following disclaimer. 33 | * Redistributions in binary form must reproduce the above copyright 34 | notice, this list of conditions and the following disclaimer in the 35 | documentation and/or other materials provided with the distribution. 36 | * Neither the name of the library nor the 37 | names of its contributors may be used to endorse or promote products 38 | derived from this software without specific prior written permission. 39 | 40 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 41 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 42 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 44 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 45 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 47 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 49 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters-settings: 2 | dupl: 3 | threshold: 100 4 | exhaustive: 5 | default-signifies-exhaustive: false 6 | # funlen: 7 | # lines: 100 8 | # statements: 50 9 | goconst: 10 | min-len: 2 11 | min-occurrences: 2 12 | gocritic: 13 | enabled-tags: 14 | - diagnostic 15 | - experimental 16 | - opinionated 17 | - performance 18 | - style 19 | disabled-checks: 20 | - dupImport # https://github.com/go-critic/go-critic/issues/845 21 | - ifElseChain 22 | # gocyclo: 23 | # min-complexity: 15 24 | goimports: 25 | local-prefixes: github.com/golangci/golangci-lint 26 | golint: 27 | min-confidence: 0 28 | gomnd: 29 | settings: 30 | mnd: 31 | # don't include the "operation" and "assign" 32 | checks: argument,case,condition,return 33 | govet: 34 | check-shadowing: true 35 | settings: 36 | printf: 37 | funcs: 38 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof 39 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf 40 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf 41 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf 42 | # lll: 43 | # line-length: 140 44 | maligned: 45 | suggest-new: true 46 | misspell: 47 | locale: US 48 | nolintlint: 49 | allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space) 50 | allow-unused: false # report any unused nolint directives 51 | require-explanation: false # don't require an explanation for nolint directives 52 | require-specific: false # don't require nolint directives to be specific about which linter is being skipped 53 | 54 | linters: 55 | # please, do not use `enable-all`: it's deprecated and will be removed soon. 56 | # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint 57 | disable-all: true 58 | enable: 59 | - bodyclose 60 | - deadcode 61 | - dogsled 62 | - dupl 63 | - errcheck 64 | - exhaustive 65 | - gochecknoinits 66 | - goconst 67 | - gocritic 68 | - gofmt 69 | - goimports 70 | - golint 71 | - gomnd 72 | - goprintffuncname 73 | - gosimple 74 | - govet 75 | - ineffassign 76 | - interfacer 77 | - misspell 78 | - nakedret 79 | - noctx 80 | - nolintlint 81 | - rowserrcheck 82 | - exportloopref 83 | - staticcheck 84 | - structcheck 85 | - stylecheck 86 | - typecheck 87 | - unconvert 88 | - unparam 89 | - unused 90 | - varcheck 91 | - whitespace 92 | 93 | # don't enable: 94 | # - depguard 95 | # - asciicheck 96 | # - funlen 97 | # - gochecknoglobals 98 | # - gocognit 99 | # - gocyclo 100 | # - godot 101 | # - godox 102 | # - goerr113 103 | # - gosec 104 | # - lll 105 | # - nestif 106 | # - prealloc 107 | # - testpackage 108 | # - wsl 109 | 110 | issues: 111 | exclude-use-default: false 112 | exclude: 113 | # should have a package comment, unless it's in another file for this package (golint) 114 | - 'in another file for this package' 115 | 116 | # golangci.com configuration 117 | # https://github.com/golangci/golangci/wiki/Configuration 118 | service: 119 | golangci-lint-version: 1.33.x # use the fixed version to not introduce new linters unexpectedly 120 | prepare: 121 | - echo "here I can run custom commands, but no preparation needed for this repo" 122 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/murmur128_gen.go: -------------------------------------------------------------------------------- 1 | // +build !go1.5 !amd64 2 | 3 | package murmur3 4 | 5 | import "math/bits" 6 | 7 | // SeedSum128 returns the murmur3 sum of data with digests initialized to seed1 8 | // and seed2. 9 | // 10 | // The canonical implementation allows only one uint32 seed; to imitate that 11 | // behavior, use the same, uint32-max seed for seed1 and seed2. 12 | // 13 | // This reads and processes the data in chunks of little endian uint64s; 14 | // thus, the returned hashes are portable across architectures. 15 | func SeedSum128(seed1, seed2 uint64, data []byte) (h1 uint64, h2 uint64) { 16 | return SeedStringSum128(seed1, seed2, strslice(data)) 17 | } 18 | 19 | // Sum128 returns the murmur3 sum of data. It is equivalent to the following 20 | // sequence (without the extra burden and the extra allocation): 21 | // hasher := New128() 22 | // hasher.Write(data) 23 | // return hasher.Sum128() 24 | func Sum128(data []byte) (h1 uint64, h2 uint64) { 25 | return SeedStringSum128(0, 0, strslice(data)) 26 | } 27 | 28 | // StringSum128 is the string version of Sum128. 29 | func StringSum128(data string) (h1 uint64, h2 uint64) { 30 | return SeedStringSum128(0, 0, data) 31 | } 32 | 33 | // SeedStringSum128 is the string version of SeedSum128. 34 | func SeedStringSum128(seed1, seed2 uint64, data string) (h1 uint64, h2 uint64) { 35 | h1, h2 = seed1, seed2 36 | clen := len(data) 37 | for len(data) >= 16 { 38 | // yes, this is faster than using binary.LittleEndian.Uint64 39 | k1 := uint64(data[0]) | uint64(data[1])<<8 | uint64(data[2])<<16 | uint64(data[3])<<24 | uint64(data[4])<<32 | uint64(data[5])<<40 | uint64(data[6])<<48 | uint64(data[7])<<56 40 | k2 := uint64(data[8]) | uint64(data[9])<<8 | uint64(data[10])<<16 | uint64(data[11])<<24 | uint64(data[12])<<32 | uint64(data[13])<<40 | uint64(data[14])<<48 | uint64(data[15])<<56 41 | 42 | data = data[16:] 43 | 44 | k1 *= c1_128 45 | k1 = bits.RotateLeft64(k1, 31) 46 | k1 *= c2_128 47 | h1 ^= k1 48 | 49 | h1 = bits.RotateLeft64(h1, 27) 50 | h1 += h2 51 | h1 = h1*5 + 0x52dce729 52 | 53 | k2 *= c2_128 54 | k2 = bits.RotateLeft64(k2, 33) 55 | k2 *= c1_128 56 | h2 ^= k2 57 | 58 | h2 = bits.RotateLeft64(h2, 31) 59 | h2 += h1 60 | h2 = h2*5 + 0x38495ab5 61 | } 62 | 63 | var k1, k2 uint64 64 | switch len(data) { 65 | case 15: 66 | k2 ^= uint64(data[14]) << 48 67 | fallthrough 68 | case 14: 69 | k2 ^= uint64(data[13]) << 40 70 | fallthrough 71 | case 13: 72 | k2 ^= uint64(data[12]) << 32 73 | fallthrough 74 | case 12: 75 | k2 ^= uint64(data[11]) << 24 76 | fallthrough 77 | case 11: 78 | k2 ^= uint64(data[10]) << 16 79 | fallthrough 80 | case 10: 81 | k2 ^= uint64(data[9]) << 8 82 | fallthrough 83 | case 9: 84 | k2 ^= uint64(data[8]) << 0 85 | 86 | k2 *= c2_128 87 | k2 = bits.RotateLeft64(k2, 33) 88 | k2 *= c1_128 89 | h2 ^= k2 90 | 91 | fallthrough 92 | 93 | case 8: 94 | k1 ^= uint64(data[7]) << 56 95 | fallthrough 96 | case 7: 97 | k1 ^= uint64(data[6]) << 48 98 | fallthrough 99 | case 6: 100 | k1 ^= uint64(data[5]) << 40 101 | fallthrough 102 | case 5: 103 | k1 ^= uint64(data[4]) << 32 104 | fallthrough 105 | case 4: 106 | k1 ^= uint64(data[3]) << 24 107 | fallthrough 108 | case 3: 109 | k1 ^= uint64(data[2]) << 16 110 | fallthrough 111 | case 2: 112 | k1 ^= uint64(data[1]) << 8 113 | fallthrough 114 | case 1: 115 | k1 ^= uint64(data[0]) << 0 116 | k1 *= c1_128 117 | k1 = bits.RotateLeft64(k1, 31) 118 | k1 *= c2_128 119 | h1 ^= k1 120 | } 121 | 122 | h1 ^= uint64(clen) 123 | h2 ^= uint64(clen) 124 | 125 | h1 += h2 126 | h2 += h1 127 | 128 | h1 = fmix64(h1) 129 | h2 = fmix64(h2) 130 | 131 | h1 += h2 132 | h2 += h1 133 | 134 | return h1, h2 135 | } 136 | -------------------------------------------------------------------------------- /test/main.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load test_helper 4 | 5 | # 1. 检查版本是否为当天编译的 6 | @test "Test iconhash version" { 7 | run ${ICONHASH_BIN} -v 8 | [ "$status" -eq 0 ] 9 | [ "${lines[0]%% *}" == "Version:" ] 10 | [ "${lines[1]%% *}" == "Compile:" ] 11 | [ "${lines[2]%% *}" == "Commit:" ] 12 | [ "${lines[3]%% *}" == "Branch:" ] 13 | # [ $(expr "${lines[2]}" : "Compile: $(date +'%Y-%m-%d').*") -ne 0 ] # 检查当前版本是否为今日编译的 14 | } 15 | 16 | 17 | # 2. 执行 iconhash -h 是否正常 18 | @test "Check iconhash help" { 19 | cd ${ICONHASH_DEV_DIRNAME} && bin/iconhash 2> ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 20 | run golden_diff 21 | echo "${output}" 22 | [ $status -eq 0 ] 23 | } 24 | 25 | # 3. 检查执行 iconhash url 是否正常 26 | @test "Check iconhash url" { 27 | ${ICONHASH_BIN} https://raw.githubusercontent.com/Becivells/iconhash/master/test/data/dede.ico > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 28 | run golden_diff 29 | echo "${output}" 30 | [ $status -eq 0 ] 31 | } 32 | # 4. 检查执行 iconhash file 是否正常 33 | @test "Check iconhash file" { 34 | ${ICONHASH_BIN} ${TEST_DATA}/favicon.ico > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 35 | run golden_diff 36 | echo "${output}" 37 | [ $status -eq 0 ] 38 | } 39 | 40 | 41 | # 5. 检查执行 iconhash file not exist 是否正常 42 | @test "Check iconhash file not exist" { 43 | run ${ICONHASH_BIN} ${TEST_DATA}/favicon.ico1 > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 44 | run golden_diff 45 | echo "${output}" 46 | [ $status -eq 1 ] 47 | } 48 | 49 | # 6. 检查执行 iconhash args url 是否正常 50 | @test "Check iconhash args url" { 51 | ${ICONHASH_BIN} -url https://raw.githubusercontent.com/Becivells/iconhash/master/test/data/dede.ico > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 52 | run golden_diff 53 | echo "${output}" 54 | [ $status -eq 0 ] 55 | } 56 | 57 | # 7. 检查执行 iconhash args url shodan 是否正常 58 | @test "Check iconhash args url shodan" { 59 | ${ICONHASH_BIN} -url https://raw.githubusercontent.com/Becivells/iconhash/master/test/data/dede.ico -shodan > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 60 | run golden_diff 61 | echo "${output}" 62 | [ $status -eq 0 ] 63 | } 64 | 65 | # 8. 检查执行 iconhash args file 是否正常 66 | @test "Check iconhash args file" { 67 | ${ICONHASH_BIN} -file ${TEST_DATA}/favicon.ico > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 68 | run golden_diff 69 | echo "${output}" 70 | [ $status -eq 0 ] 71 | } 72 | 73 | # 9. 检查执行 iconhash args file shodan 是否正常 74 | @test "Check iconhash args file shodan" { 75 | ${ICONHASH_BIN} -file ${TEST_DATA}/favicon.ico -shodan > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 76 | run golden_diff 77 | echo "${output}" 78 | [ $status -eq 0 ] 79 | } 80 | 81 | # 10. 检查执行 iconhash args file no fofa shodan 是否正常 82 | @test "Check iconhash args file no fofa shodan" { 83 | ${ICONHASH_BIN} -file ${TEST_DATA}/favicon.ico -shodan -fofa=false > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 84 | run golden_diff 85 | echo "${output}" 86 | [ $status -eq 0 ] 87 | } 88 | 89 | # 11. 检查执行 iconhash args file no fofa no shodan 是否正常 90 | @test "Check iconhash args file no fofa no shodan" { 91 | ${ICONHASH_BIN} -file ${TEST_DATA}/favicon.ico -shodan=false -fofa=false > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 92 | run golden_diff 93 | echo "${output}" 94 | [ $status -eq 0 ] 95 | } 96 | 97 | # 12. 检查执行 iconhash args file no fofa 是否正常 98 | @test "Check iconhash args file no fofa" { 99 | ${ICONHASH_BIN} -file ${TEST_DATA}/favicon.ico -fofa=false > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 100 | run golden_diff 101 | echo "${output}" 102 | [ $status -eq 0 ] 103 | } 104 | 105 | 106 | # 14. 检查执行 iconhash args other file 是否正常 107 | @test "Check iconhash args other file" { 108 | ${ICONHASH_BIN} -file ${TEST_DATA}/dede.ico -fofa=false > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 109 | run golden_diff 110 | echo "${output}" 111 | [ $status -eq 0 ] 112 | } 113 | 114 | # 15. 检查执行 iconhash url 是否正常 115 | @test "Check iconhash other url" { 116 | 117 | ${ICONHASH_BIN} https://raw.githubusercontent.com/Becivells/iconhash/master/test/data/favicon.ico > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 118 | run golden_diff 119 | echo "${output}" 120 | 121 | [ $status -eq 0 ] 122 | } 123 | 124 | # 16. 检查执行 iconhash args other file uint32 是否正常 125 | @test "Check iconhash args other file uint32" { 126 | ${ICONHASH_BIN} -file ${TEST_DATA}/dede.ico -fofa=false -uint32 > ${BATS_TMP_DIRNAME}/${BATS_TEST_NAME}.golden 127 | run golden_diff 128 | echo "${output}" 129 | [ $status -eq 0 ] 130 | } -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/murmur128.go: -------------------------------------------------------------------------------- 1 | package murmur3 2 | 3 | import ( 4 | "hash" 5 | "math/bits" 6 | ) 7 | 8 | const ( 9 | c1_128 = 0x87c37b91114253d5 10 | c2_128 = 0x4cf5ad432745937f 11 | ) 12 | 13 | // Make sure interfaces are correctly implemented. 14 | var ( 15 | _ hash.Hash = new(digest128) 16 | _ Hash128 = new(digest128) 17 | _ bmixer = new(digest128) 18 | ) 19 | 20 | // Hash128 provides an interface for a streaming 128 bit hash. 21 | type Hash128 interface { 22 | hash.Hash 23 | Sum128() (uint64, uint64) 24 | } 25 | 26 | // digest128 represents a partial evaluation of a 128 bites hash. 27 | type digest128 struct { 28 | digest 29 | seed1 uint64 30 | seed2 uint64 31 | h1 uint64 // Unfinalized running hash part 1. 32 | h2 uint64 // Unfinalized running hash part 2. 33 | } 34 | 35 | // SeedNew128 returns a Hash128 for streaming 128 bit sums with its internal 36 | // digests initialized to seed1 and seed2. 37 | // 38 | // The canonical implementation allows one only uint32 seed; to imitate that 39 | // behavior, use the same, uint32-max seed for seed1 and seed2. 40 | func SeedNew128(seed1, seed2 uint64) Hash128 { 41 | d := &digest128{seed1: seed1, seed2: seed2} 42 | d.bmixer = d 43 | d.Reset() 44 | return d 45 | } 46 | 47 | // New128 returns a Hash128 for streaming 128 bit sums. 48 | func New128() Hash128 { 49 | return SeedNew128(0, 0) 50 | } 51 | 52 | func (d *digest128) Size() int { return 16 } 53 | 54 | func (d *digest128) reset() { d.h1, d.h2 = d.seed1, d.seed2 } 55 | 56 | func (d *digest128) Sum(b []byte) []byte { 57 | h1, h2 := d.Sum128() 58 | return append(b, 59 | byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32), 60 | byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1), 61 | 62 | byte(h2>>56), byte(h2>>48), byte(h2>>40), byte(h2>>32), 63 | byte(h2>>24), byte(h2>>16), byte(h2>>8), byte(h2), 64 | ) 65 | } 66 | 67 | func (d *digest128) bmix(p []byte) (tail []byte) { 68 | h1, h2 := d.h1, d.h2 69 | 70 | for len(p) >= 16 { 71 | k1 := uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 72 | k2 := uint64(p[8]) | uint64(p[9])<<8 | uint64(p[10])<<16 | uint64(p[11])<<24 | uint64(p[12])<<32 | uint64(p[13])<<40 | uint64(p[14])<<48 | uint64(p[15])<<56 73 | p = p[16:] 74 | 75 | k1 *= c1_128 76 | k1 = bits.RotateLeft64(k1, 31) 77 | k1 *= c2_128 78 | h1 ^= k1 79 | 80 | h1 = bits.RotateLeft64(h1, 27) 81 | h1 += h2 82 | h1 = h1*5 + 0x52dce729 83 | 84 | k2 *= c2_128 85 | k2 = bits.RotateLeft64(k2, 33) 86 | k2 *= c1_128 87 | h2 ^= k2 88 | 89 | h2 = bits.RotateLeft64(h2, 31) 90 | h2 += h1 91 | h2 = h2*5 + 0x38495ab5 92 | } 93 | d.h1, d.h2 = h1, h2 94 | return p 95 | } 96 | 97 | func (d *digest128) Sum128() (h1, h2 uint64) { 98 | 99 | h1, h2 = d.h1, d.h2 100 | 101 | var k1, k2 uint64 102 | switch len(d.tail) & 15 { 103 | case 15: 104 | k2 ^= uint64(d.tail[14]) << 48 105 | fallthrough 106 | case 14: 107 | k2 ^= uint64(d.tail[13]) << 40 108 | fallthrough 109 | case 13: 110 | k2 ^= uint64(d.tail[12]) << 32 111 | fallthrough 112 | case 12: 113 | k2 ^= uint64(d.tail[11]) << 24 114 | fallthrough 115 | case 11: 116 | k2 ^= uint64(d.tail[10]) << 16 117 | fallthrough 118 | case 10: 119 | k2 ^= uint64(d.tail[9]) << 8 120 | fallthrough 121 | case 9: 122 | k2 ^= uint64(d.tail[8]) << 0 123 | 124 | k2 *= c2_128 125 | k2 = bits.RotateLeft64(k2, 33) 126 | k2 *= c1_128 127 | h2 ^= k2 128 | 129 | fallthrough 130 | 131 | case 8: 132 | k1 ^= uint64(d.tail[7]) << 56 133 | fallthrough 134 | case 7: 135 | k1 ^= uint64(d.tail[6]) << 48 136 | fallthrough 137 | case 6: 138 | k1 ^= uint64(d.tail[5]) << 40 139 | fallthrough 140 | case 5: 141 | k1 ^= uint64(d.tail[4]) << 32 142 | fallthrough 143 | case 4: 144 | k1 ^= uint64(d.tail[3]) << 24 145 | fallthrough 146 | case 3: 147 | k1 ^= uint64(d.tail[2]) << 16 148 | fallthrough 149 | case 2: 150 | k1 ^= uint64(d.tail[1]) << 8 151 | fallthrough 152 | case 1: 153 | k1 ^= uint64(d.tail[0]) << 0 154 | k1 *= c1_128 155 | k1 = bits.RotateLeft64(k1, 31) 156 | k1 *= c2_128 157 | h1 ^= k1 158 | } 159 | 160 | h1 ^= uint64(d.clen) 161 | h2 ^= uint64(d.clen) 162 | 163 | h1 += h2 164 | h2 += h1 165 | 166 | h1 = fmix64(h1) 167 | h2 = fmix64(h2) 168 | 169 | h1 += h2 170 | h2 += h1 171 | 172 | return h1, h2 173 | } 174 | 175 | func fmix64(k uint64) uint64 { 176 | k ^= k >> 33 177 | k *= 0xff51afd7ed558ccd 178 | k ^= k >> 33 179 | k *= 0xc4ceb9fe1a85ec53 180 | k ^= k >> 33 181 | return k 182 | } 183 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This how we want to name the binary output 2 | # 3 | # use checkmake linter https://github.com/mrtazz/checkmake 4 | # $ checkmake Makefile 5 | 6 | BINARY=iconhash 7 | GITREPO=Becivells/iconhash 8 | GOPATH ?= $(shell go env GOPATH) 9 | # Ensure GOPATH is set before running build process. 10 | ifeq "$(GOPATH)" "" 11 | $(error Please set the environment variable GOPATH before running `make`) 12 | endif 13 | PATH := ${GOPATH}/bin:$(PATH) 14 | GCFLAGS=-gcflags "all=-trimpath=${GOPATH}" -asmflags="all=-trimpath=${GOPATH}" 15 | 16 | VERSION_TAG := $(shell git describe --tags --always) 17 | VERSION_VERSION := $(shell git log --date=iso --pretty=format:"%cd" -1) $(VERSION_TAG) 18 | VERSION_COMPILE := $(shell date +"%F %T %z") 19 | VERSION_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) 20 | VERSION_GIT_DIRTY := $(shell git diff --no-ext-diff 2>/dev/null | wc -l|sed 's/^[ \t]*//g') 21 | VERSION_DEV_PATH:= $(shell pwd) 22 | LDFLAGS=-ldflags=" -s -w -X 'main.VERSION_TAG=$(VERSION_TAG)' -X 'main.version=$(VERSION_VERSION)' -X 'main.date=$(VERSION_COMPILE)' -X 'main.Branch=$(VERSION_BRANCH)' -X 'main.GitDirty=$(VERSION_GIT_DIRTY)'" 23 | 24 | # These are the values we want to pass for VERSION and BUILD 25 | BUILD_TIME=`date +%Y%m%d%H%M` 26 | COMMIT_VERSION=`git rev-parse HEAD` 27 | PLDCNAME=pldc-$(VERSION_TAG)-$(VERSION_BRANCH)-$(VERSION_GIT_DIRTY)-$(BUILD_TIME) 28 | # colors compatible setting 29 | COLOR_ENABLE=$(shell tput colors > /dev/null; echo $$?) 30 | ifeq "$(COLOR_ENABLE)" "0" 31 | CRED=$(shell echo "\033[91m") 32 | CGREEN=$(shell echo "\033[92m") 33 | CYELLOW=$(shell echo "\033[93m") 34 | CEND=$(shell echo "\033[0m") 35 | endif 36 | 37 | .PHONY: all 38 | all: | fmt build 39 | 40 | .PHONY: go_version_check 41 | GO_VERSION_MIN=1.11 42 | # Parse out the x.y or x.y.z version and output a single value x*10000+y*100+z (e.g., 1.9 is 10900) 43 | # that allows the three components to be checked in a single comparison. 44 | VER_TO_INT:=awk '{split(substr($$0, match ($$0, /[0-9\.]+/)), a, "."); print a[1]*10000+a[2]*100+a[3]}' 45 | go_version_check: 46 | @echo "$(CGREEN)Go version check ...$(CEND)" 47 | @if test $(shell go version | $(VER_TO_INT) ) -lt \ 48 | $(shell echo "$(GO_VERSION_MIN)" | $(VER_TO_INT)); \ 49 | then printf "go version $(GO_VERSION_MIN)+ required, found: "; go version; exit 1; \ 50 | else echo "go version check pass"; fi 51 | 52 | # Code format 53 | .PHONY: fmt 54 | fmt: go_version_check 55 | @echo "$(CGREEN)Run gofmt on all source files ...$(CEND)" 56 | go generate 57 | @echo "gofmt -l -s -w ..." 58 | @ret=0 && for d in $$(go list -f '{{.Dir}}' ./... | grep -v /vendor/); do \ 59 | gofmt -l -s -w $$d/*.go || ret=$$? ; \ 60 | done ; exit $$ret 61 | 62 | # Builds the project 63 | build: fmt 64 | @echo "$(CGREEN)Building ...$(CEND)" 65 | @rm -rf bin 66 | @mkdir -p bin 67 | CGO_ENABLED=0 go build ${GCFLAGS} ${LDFLAGS} -o bin/${BINARY} 68 | @echo "build Success!" 69 | 70 | .PHONY: release 71 | release: build 72 | @echo "$(CGREEN)Cross platform building for release ...$(CEND)" 73 | @mkdir -p release 74 | @for GOOS in darwin linux windows freebsd netbsd openbsd plan9 solaris; do \ 75 | for GOARCH in amd64 386 arm; do \ 76 | for d in $$(go list -f '{{if (eq .Name "main")}}{{.ImportPath}}{{end}}' ./...); do \ 77 | b=$$(basename $${d}) ; \ 78 | if [ "$${GOOS}" = 'windows' ]; then\ 79 | echo "Building $${b}.$${GOOS}-$${GOARCH}.exe ..."; \ 80 | GOOS=$${GOOS} GOARCH=$${GOARCH} go build ${GCFLAGS} ${LDFLAGS} -v -o release/$${b}.$${GOOS}-$${GOARCH}.exe $$d 2>/dev/null ; \ 81 | cd release &&shasum $${b}.$${GOOS}-$${GOARCH}.exe>$${b}.$${GOOS}-$${GOARCH}.exe.shasum && tar -zcf $${b}.$${GOOS}-$${GOARCH}.tar.gz $${b}.$${GOOS}-$${GOARCH}.exe $${b}.$${GOOS}-$${GOARCH}.exe.shasum;\ 82 | cd ../; \ 83 | else \ 84 | echo "Building $${b}.$${GOOS}-$${GOARCH} ..."; \ 85 | GOOS=$${GOOS} GOARCH=$${GOARCH} go build ${GCFLAGS} ${LDFLAGS} -v -o release/$${b}.$${GOOS}-$${GOARCH} $$d 2>/dev/null ; \ 86 | cd release &&shasum $${b}.$${GOOS}-$${GOARCH}>$${b}.$${GOOS}-$${GOARCH}.shasum && tar -zcf $${b}.$${GOOS}-$${GOARCH}.tar.gz $${b}.$${GOOS}-$${GOARCH} $${b}.$${GOOS}-$${GOARCH}.shasum; \ 87 | cd ../; \ 88 | fi \ 89 | done ; \ 90 | done ;\ 91 | done 92 | @find ./release/ -type f -a -size 0 -exec rm {} \; 93 | 94 | .PHONY: test-cli 95 | test-cli: build 96 | @echo "$(CGREEN)Run all cli test cases ...$(CEND)" 97 | bats ./test 98 | @echo "test-cli Success!" 99 | 100 | .PHONY: clean 101 | clean: 102 | @echo "$(CGREEN)clean all ...$(CEND)" 103 | @find ./ -type f -a -name iconhash -exec rm {} \; 104 | @find ./ -name .DS_Store -a -type f -exec rm -f {} \; 105 | @find ./release/ -type f -exec rm -f {} \; 106 | @find ./tmp/ -type f -exec rm -f {} \; 107 | @find ./bin/ -type f -exec rm -f {} \; 108 | @find ./dist/ -type f -exec rm -f {} \; 109 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/murmur128_amd64.s: -------------------------------------------------------------------------------- 1 | // +build go1.5,amd64 2 | 3 | // SeedSum128(seed1, seed2 uint64, data []byte) (h1 uint64, h2 uint64) 4 | TEXT ·SeedSum128(SB), $0-56 5 | MOVQ seed1+0(FP), R12 6 | MOVQ seed2+8(FP), R13 7 | MOVQ data_base+16(FP), SI 8 | MOVQ data_len+24(FP), R9 9 | LEAQ h1+40(FP), BX 10 | JMP sum128internal<>(SB) 11 | 12 | // Sum128(data []byte) (h1 uint64, h2 uint64) 13 | TEXT ·Sum128(SB), $0-40 14 | XORQ R12, R12 15 | XORQ R13, R13 16 | MOVQ data_base+0(FP), SI 17 | MOVQ data_len+8(FP), R9 18 | LEAQ h1+24(FP), BX 19 | JMP sum128internal<>(SB) 20 | 21 | // SeedStringSum128(seed1, seed2 uint64, data string) (h1 uint64, h2 uint64) 22 | TEXT ·SeedStringSum128(SB), $0-48 23 | MOVQ seed1+0(FP), R12 24 | MOVQ seed2+8(FP), R13 25 | MOVQ data_base+16(FP), SI 26 | MOVQ data_len+24(FP), R9 27 | LEAQ h1+32(FP), BX 28 | JMP sum128internal<>(SB) 29 | 30 | // StringSum128(data string) (h1 uint64, h2 uint64) 31 | TEXT ·StringSum128(SB), $0-32 32 | XORQ R12, R12 33 | XORQ R13, R13 34 | MOVQ data_base+0(FP), SI 35 | MOVQ data_len+8(FP), R9 36 | LEAQ h1+16(FP), BX 37 | JMP sum128internal<>(SB) 38 | 39 | // Expects: 40 | // R12 == h1 uint64 seed 41 | // R13 == h2 uint64 seed 42 | // SI == &data 43 | // R9 == len(data) 44 | // BX == &[2]uint64 return 45 | TEXT sum128internal<>(SB), $0 46 | MOVQ $0x87c37b91114253d5, R14 // c1 47 | MOVQ $0x4cf5ad432745937f, R15 // c2 48 | 49 | MOVQ R9, CX 50 | ANDQ $-16, CX // cx == data_len - (data_len % 16) 51 | 52 | // for bp = 0; bp < cx; bp += 16 {... 53 | XORQ BP, BP 54 | 55 | loop: 56 | CMPQ BP, CX 57 | JE tail 58 | MOVQ (SI)(BP*1), AX 59 | MOVQ 8(SI)(BP*1), DX 60 | ADDQ $16, BP 61 | 62 | IMULQ R14, AX 63 | IMULQ R15, DX 64 | 65 | ROLQ $31, AX 66 | ROLQ $33, DX 67 | 68 | IMULQ R15, AX 69 | IMULQ R14, DX 70 | 71 | XORQ AX, R12 72 | ROLQ $27, R12 73 | ADDQ R13, R12 74 | XORQ DX, R13 75 | ROLQ $31, R13 76 | LEAQ 0x52dce729(R12)(R12*4), R12 77 | 78 | ADDQ R12, R13 79 | LEAQ 0x38495ab5(R13)(R13*4), R13 80 | 81 | JMP loop 82 | 83 | tail: 84 | MOVQ R9, CX 85 | ANDQ $0xf, CX 86 | JZ finalize // if len % 16 == 0 87 | 88 | XORQ AX, AX 89 | 90 | // poor man's binary tree jump table 91 | SUBQ $8, CX 92 | JZ tail8 93 | JG over8 94 | ADDQ $4, CX 95 | JZ tail4 96 | JG over4 97 | ADDQ $2, CX 98 | JL tail1 99 | JZ tail2 100 | JMP tail3 101 | 102 | over4: 103 | SUBQ $2, CX 104 | JL tail5 105 | JZ tail6 106 | JMP tail7 107 | 108 | over8: 109 | SUBQ $4, CX 110 | JZ tail12 111 | JG over12 112 | ADDQ $2, CX 113 | JL tail9 114 | JZ tail10 115 | JMP tail11 116 | 117 | over12: 118 | SUBQ $2, CX 119 | JL tail13 120 | JZ tail14 121 | 122 | tail15: 123 | MOVBQZX 14(SI)(BP*1), AX 124 | SALQ $16, AX 125 | 126 | tail14: 127 | MOVW 12(SI)(BP*1), AX 128 | SALQ $32, AX 129 | JMP tail12 130 | 131 | tail13: 132 | MOVBQZX 12(SI)(BP*1), AX 133 | SALQ $32, AX 134 | 135 | tail12: 136 | MOVL 8(SI)(BP*1), DX 137 | ORQ DX, AX 138 | JMP fintailhigh 139 | 140 | tail11: 141 | MOVBQZX 10(SI)(BP*1), AX 142 | SALQ $16, AX 143 | 144 | tail10: 145 | MOVW 8(SI)(BP*1), AX 146 | JMP fintailhigh 147 | 148 | tail9: 149 | MOVB 8(SI)(BP*1), AL 150 | 151 | fintailhigh: 152 | IMULQ R15, AX 153 | ROLQ $33, AX 154 | IMULQ R14, AX 155 | XORQ AX, R13 156 | 157 | tail8: 158 | MOVQ (SI)(BP*1), AX 159 | JMP fintaillow 160 | 161 | tail7: 162 | MOVBQZX 6(SI)(BP*1), AX 163 | SALQ $16, AX 164 | 165 | tail6: 166 | MOVW 4(SI)(BP*1), AX 167 | SALQ $32, AX 168 | JMP tail4 169 | 170 | tail5: 171 | MOVBQZX 4(SI)(BP*1), AX 172 | SALQ $32, AX 173 | 174 | tail4: 175 | MOVL (SI)(BP*1), DX 176 | ORQ DX, AX 177 | JMP fintaillow 178 | 179 | tail3: 180 | MOVBQZX 2(SI)(BP*1), AX 181 | SALQ $16, AX 182 | 183 | tail2: 184 | MOVW (SI)(BP*1), AX 185 | JMP fintaillow 186 | 187 | tail1: 188 | MOVB (SI)(BP*1), AL 189 | 190 | fintaillow: 191 | IMULQ R14, AX 192 | ROLQ $31, AX 193 | IMULQ R15, AX 194 | XORQ AX, R12 195 | 196 | finalize: 197 | XORQ R9, R12 198 | XORQ R9, R13 199 | 200 | ADDQ R13, R12 201 | ADDQ R12, R13 202 | 203 | // fmix128 (both interleaved) 204 | MOVQ R12, DX 205 | MOVQ R13, AX 206 | 207 | SHRQ $33, DX 208 | SHRQ $33, AX 209 | 210 | XORQ DX, R12 211 | XORQ AX, R13 212 | 213 | MOVQ $0xff51afd7ed558ccd, CX 214 | 215 | IMULQ CX, R12 216 | IMULQ CX, R13 217 | 218 | MOVQ R12, DX 219 | MOVQ R13, AX 220 | 221 | SHRQ $33, DX 222 | SHRQ $33, AX 223 | 224 | XORQ DX, R12 225 | XORQ AX, R13 226 | 227 | MOVQ $0xc4ceb9fe1a85ec53, CX 228 | 229 | IMULQ CX, R12 230 | IMULQ CX, R13 231 | 232 | MOVQ R12, DX 233 | MOVQ R13, AX 234 | 235 | SHRQ $33, DX 236 | SHRQ $33, AX 237 | 238 | XORQ DX, R12 239 | XORQ AX, R13 240 | 241 | ADDQ R13, R12 242 | ADDQ R12, R13 243 | 244 | MOVQ R12, (BX) 245 | MOVQ R13, 8(BX) 246 | RET 247 | -------------------------------------------------------------------------------- /vendor/github.com/twmb/murmur3/README.md: -------------------------------------------------------------------------------- 1 | murmur3 2 | ======= 3 | 4 | Native Go implementation of Austin Appleby's third MurmurHash revision (aka 5 | MurmurHash3). 6 | 7 | Includes assembly for amd64 for 64/128 bit hashes, seeding functions, 8 | and string functions to avoid string to slice conversions. 9 | 10 | Hand rolled 32 bit assembly was removed during 1.11, but may be reintroduced 11 | if the compiler slows down any more. As is, the compiler generates marginally 12 | slower code (by one instruction in the hot loop). 13 | 14 | The reference algorithm has been slightly hacked as to support the streaming mode 15 | required by Go's standard [Hash interface](http://golang.org/pkg/hash/#Hash). 16 | 17 | Endianness 18 | ========== 19 | 20 | Unlike the canonical source, this library **always** reads bytes as little 21 | endian numbers. This makes the hashes portable across architectures, although 22 | does mean that hashing is a bit slower on big endian architectures. 23 | 24 | Safety 25 | ====== 26 | 27 | This library used to use `unsafe` to convert four bytes to a `uint32` and eight 28 | bytes to a `uint64`, but Go 1.14 introduced checks around those types of 29 | conversions that flagged that code as erroneous when hashing on unaligned 30 | input. While the code would not be problematic on amd64, it could be 31 | problematic on some architectures. 32 | 33 | As of Go 1.14, those conversions were removed at the expense of a very minor 34 | performance hit. This hit affects all cpu architectures on for `Sum32`, and 35 | non-amd64 architectures for `Sum64` and `Sum128`. For 64 and 128, custom 36 | assembly exists for amd64 that preserves performance. 37 | 38 | Testing 39 | ======= 40 | 41 | [![Build Status](https://travis-ci.org/twmb/murmur3.svg?branch=master)](https://travis-ci.org/twmb/murmur3) 42 | 43 | Testing includes comparing random inputs against the [canonical 44 | implementation](https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp), 45 | and testing length 0 through 17 inputs to force all branches. 46 | 47 | Because this code always reads input as little endian, testing against the 48 | canonical source is skipped for big endian architectures. The canonical source 49 | just converts bytes to numbers, meaning on big endian architectures, it will 50 | use different numbers for its hashing. 51 | 52 | Documentation 53 | ============= 54 | 55 | [![GoDoc](https://godoc.org/github.com/twmb/murmur3?status.svg)](https://godoc.org/github.com/twmb/murmur3) 56 | 57 | Full documentation can be found on `godoc`. 58 | 59 | Benchmarks 60 | ========== 61 | 62 | Benchmarks below were run on an amd64 machine with _and_ without the custom 63 | assembly. The following numbers are for Go 1.14.1 and are comparing against 64 | [spaolacci/murmur3](https://github.com/spaolacci/murmur3). 65 | 66 | You will notice that at small sizes, the other library is better. This is due 67 | to this library converting to safe code for Go 1.14. At large sizes, this 68 | library is nearly identical to the other. On amd64, the 64 bit and 128 bit 69 | sums come out to ~9% faster. 70 | 71 | 32 bit sums: 72 | 73 | ``` 74 | 32Sizes/32-12 3.00GB/s ± 1% 2.12GB/s ±11% -29.24% (p=0.000 n=9+10) 75 | 32Sizes/64-12 3.61GB/s ± 3% 2.79GB/s ± 8% -22.62% (p=0.000 n=10+10) 76 | 32Sizes/128-12 3.47GB/s ± 8% 2.79GB/s ± 4% -19.47% (p=0.000 n=10+10) 77 | 32Sizes/256-12 3.66GB/s ± 4% 3.25GB/s ± 6% -11.09% (p=0.000 n=10+10) 78 | 32Sizes/512-12 3.78GB/s ± 3% 3.54GB/s ± 4% -6.30% (p=0.000 n=9+9) 79 | 32Sizes/1024-12 3.86GB/s ± 3% 3.69GB/s ± 5% -4.46% (p=0.000 n=10+10) 80 | 32Sizes/2048-12 3.85GB/s ± 3% 3.81GB/s ± 3% ~ (p=0.079 n=10+9) 81 | 32Sizes/4096-12 3.90GB/s ± 3% 3.82GB/s ± 2% -2.14% (p=0.029 n=10+10) 82 | 32Sizes/8192-12 3.82GB/s ± 3% 3.78GB/s ± 7% ~ (p=0.529 n=10+10) 83 | ``` 84 | 85 | 64/128 bit sums, non-amd64: 86 | 87 | ``` 88 | 64Sizes/32-12 2.34GB/s ± 5% 2.64GB/s ± 9% +12.87% (p=0.000 n=10+10) 89 | 64Sizes/64-12 3.62GB/s ± 5% 3.96GB/s ± 4% +9.41% (p=0.000 n=10+10) 90 | 64Sizes/128-12 5.12GB/s ± 3% 5.44GB/s ± 4% +6.09% (p=0.000 n=10+9) 91 | 64Sizes/256-12 6.35GB/s ± 2% 6.27GB/s ± 9% ~ (p=0.796 n=10+10) 92 | 64Sizes/512-12 6.58GB/s ± 7% 6.79GB/s ± 3% ~ (p=0.075 n=10+10) 93 | 64Sizes/1024-12 7.49GB/s ± 3% 7.55GB/s ± 9% ~ (p=0.393 n=10+10) 94 | 64Sizes/2048-12 8.06GB/s ± 2% 7.90GB/s ± 6% ~ (p=0.156 n=9+10) 95 | 64Sizes/4096-12 8.27GB/s ± 6% 8.22GB/s ± 5% ~ (p=0.631 n=10+10) 96 | 64Sizes/8192-12 8.35GB/s ± 4% 8.38GB/s ± 6% ~ (p=0.631 n=10+10) 97 | 128Sizes/32-12 2.27GB/s ± 2% 2.68GB/s ± 5% +18.00% (p=0.000 n=10+10) 98 | 128Sizes/64-12 3.55GB/s ± 2% 4.00GB/s ± 3% +12.47% (p=0.000 n=8+9) 99 | 128Sizes/128-12 5.09GB/s ± 1% 5.43GB/s ± 3% +6.65% (p=0.000 n=9+9) 100 | 128Sizes/256-12 6.33GB/s ± 3% 5.65GB/s ± 4% -10.79% (p=0.000 n=9+10) 101 | 128Sizes/512-12 6.78GB/s ± 3% 6.74GB/s ± 6% ~ (p=0.968 n=9+10) 102 | 128Sizes/1024-12 7.46GB/s ± 4% 7.56GB/s ± 4% ~ (p=0.222 n=9+9) 103 | 128Sizes/2048-12 7.99GB/s ± 4% 7.96GB/s ± 3% ~ (p=0.666 n=9+9) 104 | 128Sizes/4096-12 8.20GB/s ± 2% 8.25GB/s ± 4% ~ (p=0.631 n=10+10) 105 | 128Sizes/8192-12 8.24GB/s ± 2% 8.26GB/s ± 5% ~ (p=0.673 n=8+9) 106 | ``` 107 | 108 | 64/128 bit sums, amd64: 109 | 110 | ``` 111 | 64Sizes/32-12 2.34GB/s ± 5% 4.36GB/s ± 3% +85.86% (p=0.000 n=10+10) 112 | 64Sizes/64-12 3.62GB/s ± 5% 6.27GB/s ± 3% +73.37% (p=0.000 n=10+9) 113 | 64Sizes/128-12 5.12GB/s ± 3% 7.70GB/s ± 6% +50.27% (p=0.000 n=10+10) 114 | 64Sizes/256-12 6.35GB/s ± 2% 8.61GB/s ± 3% +35.50% (p=0.000 n=10+10) 115 | 64Sizes/512-12 6.58GB/s ± 7% 8.59GB/s ± 4% +30.48% (p=0.000 n=10+9) 116 | 64Sizes/1024-12 7.49GB/s ± 3% 8.81GB/s ± 2% +17.66% (p=0.000 n=10+10) 117 | 64Sizes/2048-12 8.06GB/s ± 2% 8.90GB/s ± 4% +10.49% (p=0.000 n=9+10) 118 | 64Sizes/4096-12 8.27GB/s ± 6% 8.90GB/s ± 4% +7.54% (p=0.000 n=10+10) 119 | 64Sizes/8192-12 8.35GB/s ± 4% 9.00GB/s ± 3% +7.80% (p=0.000 n=10+9) 120 | 128Sizes/32-12 2.27GB/s ± 2% 4.29GB/s ± 9% +88.75% (p=0.000 n=10+10) 121 | 128Sizes/64-12 3.55GB/s ± 2% 6.10GB/s ± 8% +71.78% (p=0.000 n=8+10) 122 | 128Sizes/128-12 5.09GB/s ± 1% 7.62GB/s ± 9% +49.63% (p=0.000 n=9+10) 123 | 128Sizes/256-12 6.33GB/s ± 3% 8.65GB/s ± 3% +36.71% (p=0.000 n=9+10) 124 | 128Sizes/512-12 6.78GB/s ± 3% 8.39GB/s ± 6% +23.77% (p=0.000 n=9+10) 125 | 128Sizes/1024-12 7.46GB/s ± 4% 8.70GB/s ± 4% +16.70% (p=0.000 n=9+10) 126 | 128Sizes/2048-12 7.99GB/s ± 4% 8.73GB/s ± 8% +9.26% (p=0.003 n=9+10) 127 | 128Sizes/4096-12 8.20GB/s ± 2% 8.86GB/s ± 6% +8.00% (p=0.000 n=10+10) 128 | 128Sizes/8192-12 8.24GB/s ± 2% 9.01GB/s ± 3% +9.30% (p=0.000 n=8+10) 129 | ``` 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fofa Shodan icon hash 计算器 2 | 3 | [![Latest release](https://img.shields.io/github/v/release/becivells/iconhash)](https://github.com/becivells/iconhash/releases/latest) 4 | [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/becivells/iconhash/bats%20test?label=bats%20CI)](https://github.com/Becivells/iconhash/actions/workflows/bats.yml) 5 | [![dev build status](https://img.shields.io/travis/becivells/iconhash/dev.svg?label=travis%20dev)](https://travis-ci.org/becivells/iconhash) 6 | [![master build status](https://img.shields.io/travis/becivells/iconhash/master.svg?label=travis%20master)](https://travis-ci.org/becivells/iconhash) 7 | ![GitHub All Releases](https://img.shields.io/github/downloads/becivells/iconhash/total) 8 | [![Docker Pulls](https://img.shields.io/docker/pulls/becivells/iconhash)](https://hub.docker.com/r/becivells/iconhash) 9 | ![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/becivells/iconhash) 10 | 11 | 12 | ## 说明 13 | 14 | 大致说一下思路首先获得 favicon.ico 文件然后进行 base64 编码,编码后的数据要求每 76 个字符加上换行符。具体原因 RFC 822 文档上有说明。然后 32 位 mmh3 hash 15 | 16 | 这里贴出来 python 的实现 17 | 18 | Python2 19 | 20 | ```shell 21 | alias ico_hash2="python2 -c \"import requests,sys,mmh3;print mmh3.hash(requests.get(sys.argv[1]).content.encode('base64'))\"" 22 | ``` 23 | 24 | Python3 25 | 26 | ```shell 27 | alias ico_hash=" python3 -c \"import requests,sys,mmh3,codecs;print('icon_hash=%s'%mmh3.hash(codecs.lookup('base64').encode(requests.get(sys.argv[1]).content)[0]))\"" 28 | ``` 29 | 30 | 31 | 32 | ## 安装下载 33 | 34 | [跳转到下载链接](https://github.com/becivells/iconhash/releases/latest) 35 | 36 | 下载后记得校验文件 37 | 38 | ``` 39 | sha1sum -c *.shasum 40 | ``` 41 | 42 | 43 | 44 | ## iconhash 用法 45 | 46 | ### 不带参数 47 | 48 | #### 1. 不带参数的 URL 49 | 50 | ```shell 51 | iconhash https://www.baidu.com/favicon.ico 52 | ``` 53 | 54 | 结果: 55 | 56 | ``` 57 | -1507567067 58 | ``` 59 | 60 | #### 2. 不带参数的 File 61 | 62 | ```shell 63 | iconhash favicon.ico 64 | ``` 65 | 66 | **结果:** 67 | 68 | ``` 69 | -1507567067 70 | ``` 71 | 72 | **需要注意不指明文件类型 iconhash 所有的参数都不能使用** 73 | 74 | ### 带参数 75 | 76 | #### 1. Icon 文件的 hash 值 77 | 78 | ```shell 79 | iconhash -file favicon.ico 80 | ``` 81 | 82 | **结果:** 83 | 84 | ``` 85 | icon_hash="-1507567067" 86 | ``` 87 | 88 | 注意默认使用 Fofa 的搜索格式如果关闭可以使用 89 | 90 | ```shell 91 | iconhash -file favicon.ico -fofa=false 92 | ``` 93 | 94 | **结果:** 95 | 96 | ``` 97 | -1507567067 98 | ``` 99 | 100 | 101 | 102 | 如果**只需要** shodan 格式 103 | 104 | ```shell 105 | iconhash -file favicon.ico -fofa=false -shodan 106 | ``` 107 | 108 | **结果:** 109 | 110 | ``` 111 | http.favicon.hash:-1507567067 112 | ``` 113 | 114 | #### 2. 链接中的 icon hash 值 115 | 116 | ``` 117 | iconhash -url https://www.baidu.com/favicon.ico 118 | ``` 119 | 120 | #### 3. base64 的 icon hash 值 121 | 122 | 格式如下所示 123 | 124 | ``` 125 | data:image/vnd.microsoft.icon;base64,AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAAAA 126 | ..... 127 | //////////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 128 | ``` 129 | 130 | **执行命令** 131 | 132 | ``` 133 | iconhash -b64 imgb64.txt 134 | ``` 135 | 136 | **结果:** 137 | 138 | ``` 139 | -1507567067 140 | ``` 141 | 142 | 对于这种类型的数据如果计算不准确可以去掉`data:image/vnd.microsoft.icon;base64,`只保留 base64 数据试试 143 | 144 | #### uint32数据 145 | 146 | 默认使用的是 int32 数据如果想获得 uint32 的值可以加参数 -uint32 147 | 148 | 149 | 150 | ## 帮助 151 | 152 | ``` 153 | Usage of ./iconhash: 154 | -b64 string 155 | mmh3 hash image base64 from file 156 | iconhash -file test/favicon.ico 157 | -file string 158 | mmh3 hash from file 159 | iconhash -file favicon.ico 160 | -fofa 161 | fofa search format (default true) 162 | -h look help 163 | iconhash favicon.ico 164 | iconhash https://www.baidu.com/favicon.ico 165 | -shodan 166 | shodan search format 167 | iconhash -file test/favicon.ico -shodan -fofa=false 168 | -uint32 169 | uint32 170 | -url string 171 | mmh3 hash from url 172 | iconhash -url https://www.baidu.com/favicon.ico 173 | -user-agent string 174 | mmh3 hash from url (default "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11") 175 | -v version 176 | ``` 177 | 178 | 179 | 180 | ### 调试模式 181 | 182 | 主要应对 url 和 image base64 的情况,如果 hash 值不一致请开启 debug 模式看错误信息 183 | 184 | ``` 185 | iconhash -url https://106.55.12.93/favicon.ico1 -debug 186 | ``` 187 | 188 | **结果:** 189 | 190 | ``` 191 | --------------------------- var value -------------------------------- 192 | h :false 193 | v :false 194 | Version :2020-05-25 12:02:03 +0800 v0.2-11-gfcbf179 195 | VERSION_TAG :v0.2-11-gfcbf179 196 | Compile :2020-05-25 21:51:38 +0800 197 | Branch :dev 198 | GitDirty :73 199 | HashURL :https://106.55.12.93/favicon.ico1 200 | Hashfile : 201 | ImageBase64 : 202 | UserAgent :Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11 203 | IsUint32 :false 204 | FofaFormat :true 205 | ShodanFormat :false 206 | InsecureSkipVerify :true 207 | Debug :true 208 | DefaultUA :Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11 209 | --------------------------- var value -------------------------------- 210 | --------------------------- start url content -------------------------------- 211 | ====> url: https://106.55.12.93/favicon.ico1 212 | ===> status code: 404 213 | ====> content: 214 | 215 | 404 Not Found 216 | 217 |

404 Not Found

218 |
nginx
219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | --------------------------- end url content -------------------------------- 229 | ---------------------------start base64 content-------------------------------- 230 | ====> base64: 231 | PGh0bWw+DQo8aGVhZD48dGl0bGU+NDA0IE5vdCBGb3VuZDwvdGl0bGU+PC9oZWFkPg0KPGJvZHk+ 232 | DQo8Y2VudGVyPjxoMT40MDQgTm90IEZvdW5kPC9oMT48L2NlbnRlcj4NCjxocj48Y2VudGVyPm5n 233 | aW54PC9jZW50ZXI+DQo8L2JvZHk+DQo8L2h0bWw+DQo8IS0tIGEgcGFkZGluZyB0byBkaXNhYmxl 234 | IE1TSUUgYW5kIENocm9tZSBmcmllbmRseSBlcnJvciBwYWdlIC0tPg0KPCEtLSBhIHBhZGRpbmcg 235 | dG8gZGlzYWJsZSBNU0lFIGFuZCBDaHJvbWUgZnJpZW5kbHkgZXJyb3IgcGFnZSAtLT4NCjwhLS0g 236 | YSBwYWRkaW5nIHRvIGRpc2FibGUgTVNJRSBhbmQgQ2hyb21lIGZyaWVuZGx5IGVycm9yIHBhZ2Ug 237 | LS0+DQo8IS0tIGEgcGFkZGluZyB0byBkaXNhYmxlIE1TSUUgYW5kIENocm9tZSBmcmllbmRseSBl 238 | cnJvciBwYWdlIC0tPg0KPCEtLSBhIHBhZGRpbmcgdG8gZGlzYWJsZSBNU0lFIGFuZCBDaHJvbWUg 239 | ZnJpZW5kbHkgZXJyb3IgcGFnZSAtLT4NCjwhLS0gYSBwYWRkaW5nIHRvIGRpc2FibGUgTVNJRSBh 240 | bmQgQ2hyb21lIGZyaWVuZGx5IGVycm9yIHBhZ2UgLS0+DQo= 241 | 242 | ---------------------------end base64 content-------------------------------- 243 | icon_hash="566218143" 244 | ``` 245 | 246 | 247 | 248 | ## 编译 or 开发 249 | 250 | 安装 make 环境,golang 环境,测试环境 [bats](https://github.com/bats-core/bats-core) 251 | 252 | 本地编译 253 | 254 | ``` 255 | make 256 | ``` 257 | 258 | 生成 release 版本 259 | 260 | ``` 261 | make release #编译版本 262 | ``` 263 | 264 | bat 测试功能 265 | 266 | ``` 267 | make test-cli 268 | ``` 269 | 270 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "crypto/tls" 6 | "encoding/base64" 7 | "flag" 8 | "fmt" 9 | "hash" 10 | "io/ioutil" 11 | "net/http" 12 | "os" 13 | "strings" 14 | "time" 15 | 16 | "github.com/twmb/murmur3" 17 | ) 18 | 19 | //nolint 20 | var ( 21 | h bool 22 | v bool 23 | version string 24 | commit string 25 | date string 26 | Branch string 27 | GitDirty string 28 | HashURL string 29 | Hashfile string 30 | ImageBase64 string 31 | UserAgent string 32 | IsUint32 bool 33 | FofaFormat bool 34 | ShodanFormat bool 35 | InsecureSkipVerify bool 36 | ReqTimeOut int = 10 37 | Debug bool 38 | DefaultUA string = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11" 39 | ) 40 | 41 | // PrintVersion 打印版本信息 42 | func PrintVersion() { 43 | fmt.Printf("Version: %s\n", version) 44 | fmt.Printf("Compile: %s\n", date) 45 | fmt.Printf("Commit: %s\n", commit) 46 | fmt.Printf("Branch: %s\n", Branch) 47 | fmt.Printf("GitDirty: %s\n", GitDirty) 48 | } 49 | 50 | //nolint:gochecknoinits // this is init 51 | func init() { 52 | flag.BoolVar(&h, "h", false, "look help \n iconhash favicon.ico \n iconhash https://www.baidu.com/favicon.ico") 53 | flag.BoolVar(&v, "v", false, "version") 54 | flag.BoolVar(&Debug, "debug", false, "debug mode") 55 | flag.BoolVar(&FofaFormat, "fofa", true, "fofa search format") 56 | flag.BoolVar(&ShodanFormat, "shodan", false, "shodan search format \n iconhash -file test/favicon.ico -shodan -fofa=false") 57 | flag.BoolVar(&IsUint32, "uint32", false, "uint32") 58 | flag.BoolVar(&InsecureSkipVerify, "skip-verify", true, "https InsecureSkipVerify") 59 | flag.StringVar(&Hashfile, "file", "", "mmh3 hash from file \n iconhash -file favicon.ico") 60 | flag.StringVar(&HashURL, "url", "", "mmh3 hash from url \n iconhash -url https://www.baidu.com/favicon.ico") 61 | flag.StringVar(&UserAgent, "user-agent", DefaultUA, "mmh3 hash from url") 62 | flag.StringVar(&ImageBase64, "b64", "", "mmh3 hash image base64 from file \n iconhash -file test/favicon.ico ") 63 | IconHashArgs := map[string]int{ 64 | "-h": 1, 65 | "-v": 1, 66 | "-fofa": 1, 67 | "-shodan": 1, 68 | "-uint32": 1, 69 | "-file": 1, 70 | "-url": 1, 71 | "-user-agent": 1, 72 | "-b64": 1, 73 | "-debug": 1, 74 | "-skip-verify": 1, 75 | } 76 | flag.Parse() 77 | 78 | if v { 79 | PrintVersion() 80 | return 81 | } 82 | 83 | if h || len(os.Args) == 1 { 84 | flag.Usage() 85 | return 86 | } 87 | // nolint 88 | if len(os.Args) == 2 { 89 | arg := os.Args[1] 90 | if _, ok := IconHashArgs[arg]; !ok { 91 | FofaFormat = false 92 | if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") { 93 | HashURL = arg 94 | } else if _, err := os.Stat(arg); err == nil { 95 | Hashfile = arg 96 | 97 | } else { 98 | fmt.Print("not file or url please check\n") 99 | os.Exit(1) 100 | } 101 | 102 | } else { 103 | flag.Usage() 104 | os.Exit(0) 105 | } 106 | 107 | } 108 | if len(os.Args) > 2 && !strings.HasPrefix(os.Args[1], "-") { 109 | flag.Usage() 110 | os.Exit(1) 111 | } 112 | 113 | if Debug { 114 | fmt.Print("--------------------------- var value --------------------------------\n") 115 | fmt.Printf("h :%t\n", h) 116 | fmt.Printf("v :%t\n", v) 117 | fmt.Printf("Version :%s\n", version) 118 | fmt.Printf("Commit :%s\n", commit) 119 | fmt.Printf("Compile :%s\n", date) 120 | fmt.Printf("HashURL :%s\n", HashURL) 121 | fmt.Printf("Hashfile :%s\n", Hashfile) 122 | fmt.Printf("ImageBase64 :%s\n", ImageBase64) 123 | fmt.Printf("UserAgent :%s\n", UserAgent) 124 | fmt.Printf("IsUint32 :%t\n", IsUint32) 125 | fmt.Printf("FofaFormat :%t\n", FofaFormat) 126 | fmt.Printf("ShodanFormat :%t\n", ShodanFormat) 127 | fmt.Printf("InsecureSkipVerify :%t\n", InsecureSkipVerify) 128 | fmt.Printf("Debug :%t\n", Debug) 129 | fmt.Printf("DefaultUA :%s\n", DefaultUA) 130 | defer fmt.Print("--------------------------- var value --------------------------------\n") 131 | } 132 | } 133 | 134 | // PrintResult 打印结果 135 | func PrintResult(result string) { 136 | if !ShodanFormat && !FofaFormat { 137 | fmt.Printf("%s\n", result) 138 | } 139 | if FofaFormat { 140 | fmt.Printf("icon_hash=\"%s\"\n", result) 141 | } 142 | 143 | if ShodanFormat { 144 | fmt.Printf("http.favicon.hash:%s\n", result) 145 | } 146 | } 147 | 148 | // FromURLGetContent 从 URL 中获取图片内容 149 | func FromURLGetContent(requrl string) (content []byte, err error) { 150 | if Debug { 151 | fmt.Print("--------------------------- start url content --------------------------------\n") 152 | fmt.Printf("====> url: %s\n", HashURL) 153 | defer fmt.Print("--------------------------- end url content --------------------------------\n") 154 | } 155 | 156 | client := &http.Client{ 157 | Timeout: time.Second * time.Duration(ReqTimeOut), 158 | Transport: &http.Transport{ 159 | TLSClientConfig: &tls.Config{InsecureSkipVerify: InsecureSkipVerify}, // param 160 | }, 161 | } 162 | 163 | req, err := http.NewRequest("GET", requrl, nil) //nolint 164 | if err != nil { 165 | return nil, err 166 | } 167 | req.Header.Set("User-Agent", UserAgent) 168 | resp, err := client.Do(req) 169 | if err != nil { 170 | return nil, err 171 | } 172 | 173 | defer resp.Body.Close() //nolint 174 | 175 | body, err := ioutil.ReadAll(resp.Body) 176 | if err != nil { 177 | return nil, err 178 | } 179 | if Debug { 180 | fmt.Printf("===> status code: %d\n", resp.StatusCode) 181 | fmt.Printf("====> content: \n%s\n", body) 182 | } 183 | 184 | return body, nil 185 | } 186 | 187 | // FromfileGetContent 从文件中获取图片内容 188 | func FromfileGetContent(path string) (content []byte, err error) { 189 | if Debug { 190 | fmt.Print("---------------------------start From file get content--------------------------------\n") 191 | defer fmt.Print("---------------------------end From file get content--------------------------------\n") 192 | } 193 | 194 | fi, err := os.Open(path) 195 | if err != nil { 196 | return nil, err 197 | } 198 | defer fi.Close() // nolint 199 | content, err = ioutil.ReadAll(fi) 200 | if Debug { 201 | fmt.Printf("====> fileContent:\n %s\n", content) 202 | } 203 | 204 | if err != nil { 205 | return nil, err 206 | } 207 | return content, nil 208 | } 209 | 210 | /* 211 | Mmh3Hash32 计算 mmh3 hash 212 | */ 213 | func Mmh3Hash32(raw []byte) string { 214 | var h32 hash.Hash32 = murmur3.New32() 215 | h32.Write(raw) 216 | if IsUint32 { 217 | return fmt.Sprintf("%d", h32.Sum32()) 218 | } 219 | return fmt.Sprintf("%d", int32(h32.Sum32())) 220 | } 221 | 222 | // StandBase64 计算 base64 的值 223 | func StandBase64(braw []byte) []byte { 224 | bckd := base64.StdEncoding.EncodeToString(braw) 225 | var buffer bytes.Buffer 226 | for i := 0; i < len(bckd); i++ { 227 | ch := bckd[i] 228 | buffer.WriteByte(ch) 229 | if (i+1)%76 == 0 { 230 | buffer.WriteByte('\n') 231 | } 232 | } 233 | buffer.WriteByte('\n') 234 | if Debug { 235 | fmt.Print("---------------------------start base64 content--------------------------------\n") 236 | fmt.Printf("====> base64:\n%s\n", buffer.String()) 237 | defer fmt.Print("---------------------------end base64 content--------------------------------\n") 238 | } 239 | return buffer.Bytes() 240 | } 241 | 242 | // SplitChar76 按照 76 字符切分 243 | func SplitChar76(braw []byte) []byte { 244 | // 去掉 data:image/vnd.microsoft.icon;base64 245 | if strings.HasPrefix(string(braw), "data:image/vnd.microsoft.icon;base64,") { 246 | braw = braw[37:] 247 | } 248 | 249 | var buffer bytes.Buffer 250 | for i := 0; i < len(braw); i++ { 251 | ch := braw[i] 252 | buffer.WriteByte(ch) 253 | if (i+1)%76 == 0 { 254 | buffer.WriteByte('\n') 255 | } 256 | } 257 | buffer.WriteByte('\n') 258 | 259 | if Debug { 260 | fmt.Print("---------------------------start base64 content--------------------------------\n") 261 | fmt.Printf("====> base64 split 76:\n %s\n", buffer.String()) 262 | defer fmt.Print("---------------------------end base64 content--------------------------------\n") 263 | } 264 | 265 | return buffer.Bytes() 266 | } 267 | -------------------------------------------------------------------------------- /test/data/baiduimgb64.txt: -------------------------------------------------------------------------------- 1 | data:image/vnd.microsoft.icon;base64,AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////6dn//+HM///48v///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+nZ///Lpf//w5n//8OZ///Dmf//w5n//8OZ///Dmf//w5n//+HM///p2f////////////////////////////////////////////////////////jy///Ssv//tH///6Vl//+IM///iDP//4gz//+IM///iDP//4gz//+WTP//tH///+nZ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4cz//5ZM//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+eWf//tH///8OZ///Dmf//w5n//8OZ///Dmf//rXL//55Z//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///rXL///jy////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////0rL//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+eWf//+PL/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////0rL//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//61y////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8OX//48///+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///6dn//////////////////////////////////////////////////////////////////////////////////////////////////////////////////7R///+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//48////Dmf//4cz////////////////////////////////////////Dmf//iDP//4gz//+IM///lkz//9Ky///48v////////////////////////////////////////////+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//7R///////////////////////////////////////////////////////////////////////////////////////////////////////////////////+PP///iDP//4gz//+IM///iDP//4gz//+IM///iDP//7R////48v//////////////////////////////////////////////////w5n//4gz//+IM///tH////jy////////////////////////////////////////////////////////iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+PP//////////////////////////////////////////////////////////////////////////////////////////////////////////////hzP//iDP//4gz//+IM///iDP//4gz//+IM///iDP//7R//////////////////////////////////////////////////////////////8OZ//+IM///jz////jy/////////////////////////////////////////////////////////////4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP///Dl////////////////////////////////////////////////////////////////////////////////////////////////////////w5n//4gz//+IM///iDP//4gz//+IM///iDP//48////48v/////////////48v//pWX//4gz//+IM///iDP//4gz///////////////////Dmf//iDP//6Vl///////////////////w5f//rXL//6Vl//+lZf//pWX//9Ky//////////////////+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///hzP///////////////////////////////////////////////////////////////////////////////////////////////////////8OZ//+IM///iDP//4gz//+IM///iDP//4gz//+8jP//////////////////pWX//4gz//+IM///iDP//4gz//+IM///////////////////w5n//4gz//+lZf//////////////////jz///4gz//+IM///iDP//4gz///Dmf//////////////////iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///4cz///////////////////////////////////////////////////////////////////////////////////////////////////////+0f///iDP//4gz//+IM///iDP//4gz//+IM///2r//////////////6dn//4gz//+IM///iDP//4gz//+IM///iDP//////////////////8OZ//+IM///pWX//////////////////4gz//+IM///iDP//4gz//+IM///w5n//////////////////4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//+HM////////////////////////////////////////////////////////////////////////////////////////////////////////w5n//4gz//+IM///iDP//4gz//+IM///iDP//+HM//////////////jy//+IM///iDP//4gz//+IM///iDP//4gz///////////////////Dmf//iDP//6Vl//////////////////+IM///iDP//4gz//+IM///iDP//8OZ//////////////////+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///p2f///////////////////////////////////////////////////////////////////////////////////////////////////////9Ky//+IM///iDP//4gz//+IM///iDP//4gz///hzP//////////////////iDP//4gz//+IM///iDP//4gz//+IM///////////////////w5n//4gz//+lZf//////////////////iDP//4gz//+IM///iDP//4gz///Dmf//////////////////iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+PP//////////////////////////////////////////////////////////////////////////////////////////////////////////////48v//iDP//4gz//+IM///iDP//4gz//+IM///0rL//////////////////48///+IM///iDP//4gz//+IM///iDP//////////////////8OZ//+IM///pWX//////////////////4gz//+IM///iDP//4gz//+IM///w5n//////////////////4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///vIz//////////////////////////////////////////////////////////////////////////////////////////////////////////////////7R///+IM///iDP//4gz//+IM///iDP//61y///////////////////Ssv//iDP//4gz//+IM///iDP//4gz///////////////////Dmf//iDP//6Vl//////////////////+IM///iDP//4gz//+IM///iDP//8OZ//////////////////+IM///iDP//4gz//+IM///iDP//4gz//+IM///jz////jy///////////////////////////////////////////////////////////////////////////////////////////////////////////////////48v//jz///4gz//+IM///iDP//4gz//+IM///4cz//////////////////9q///+lZf//pWX//6Vl//+lZf//////////////////w5n//4gz//+lZf//////////////////iDP//4gz//+IM///iDP//4gz///Dmf//////////////////iDP//4gz//+IM///iDP//4gz//+IM///iDP//9Ky/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9q///+IM///iDP//4gz//+IM///iDP//48////w5f///////////////////////////////////////////////////////8OZ//+IM///pWX//////////////////4gz//+IM///iDP//4gz//+IM///w5n//////////////////4gz//+IM///iDP//4gz//+IM///iDP//9Ky////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////0rL//4gz//+IM///iDP//4gz//+IM///jz///9q////////////////////////////////////////////////////Dmf//iDP//6Vl//////////////////+IM///iDP//4gz//+IM///iDP//8OZ//////////////////+IM///iDP//4gz//+IM///jz///+nZ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Ssv//iDP//4gz//+IM///iDP//4gz//+IM///nln//8OZ///Dmf//w5n//8OZ///Dmf//8OX/////////////w5n//4gz//+PP///pWX//6Vl//+lZf//iDP//4gz//+IM///iDP//4gz//+WTP//pWX//6Vl//+lZf//iDP//4gz//+IM///nln///Dl/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+nZ//+PP///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//+HM/////////////8OZ//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///nln///jy////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+PL//55Z//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///hzP/////////////Dmf//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///rXL///jy///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////48v//tH///4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///4cz/////////////w5n//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///tH////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+0f///iDP//4gz//+IM///iDP//4gz//+IM///iDP//+HM/////////////8OZ//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///tH///////////////////9Ky//+tcv//pWX//6Vl//+lZf//pWX//8ul///48v///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9Ky//+IM///iDP//4gz//+IM///iDP//4gz///Lpf//4cz//+HM//+0f///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///nln/////////////+PL//55Z//+IM///iDP//4gz//+IM///iDP//4gz//+IM///jz///+nZ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////y6X//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///nln///jy/////////////55Z//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+WTP//+PL///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+0f///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///jz////jy/////////////9q///+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//8ul///////////////////////////////////////////////////////////////////////////////////48v//vIz//4gz//+IM///iDP//4gz//+PP///vIz///jy/////////////////////////////55Z//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//+nZ//////////////////+0f///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+eWf/////////////////////////////////////////////////////////////////////////////48v//nln//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+eWf//+PL////////////////////////w5f//jz///4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//8OZ////////////////////////pWX//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP/////////////////////////////////////////////////////////////////////////////vIz//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//6Vl/////////////////////////////8ul//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//6Vl/////////////////////////////6Vl//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///48v//////////////////////////////////////////////////////////////////8OX//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///2r//////////////////////////////tH///4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//55Z///48v////////////////////////////+eWf//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///4cz//////////////////////////////////////////////////////////////////7yM//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//61y//////////////////////////////////+0f///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//55Z///48v//////////////////////////////////nln//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//+HM//////////////////////////////////////////////////////////////////+eWf//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+WTP///////////////////////////////////////9q///+WTP//iDP//4gz//+IM///iDP//4gz//+IM///iDP//7yM///48v///////////////////////////////////////6Vl//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///w5f//////////////////////////////////////////////////////////////////iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//////////////////////////////////////////////////9q////Dmf//pWX//6Vl//+0f///y6X///jy//////////////////////////////////////////////////+lZf//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM////////////////////////////////////////////////////////////////////////4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////vIz//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///pWX///////////////////////////////////////////////////////////////////////+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9q///+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//9Ky////////////////////////////////////////////////////////////////////////lkz//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////lkz//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//55Z/////////////////////////////////////////////////////////////////////////////61y//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//55Z/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+HM//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//55Z///48v/////////////////////////////////////////////////////////////////////////////Ssv//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///Dmf/////////////////////////////p2f//6dn/////////////////////////////////////////////////////////////4cz//7R///+lZf//pWX//7R////hzP//////////////////4cz//5ZM//+IM///iDP//4gz//+IM///iDP//7R////48v//////////////////////////////////////////////////////////////////////////////////+PL//48///+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+PP///+PL//////////////////8OZ//+PP///iDP//4gz//+PP///w5n////////////////////////////////////////48v//pWX//4gz//+IM///iDP//4gz//+IM///iDP//61y///48v//////////////////6dn//+HM///hzP//4cz///jy///////////////////////////////////////////////////////////////////////////////////////////////////Dmf//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///0rL//////////////////7R///+IM///iDP//4gz//+IM///iDP//4gz//+0f///////////////////////////////////rXL//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///nln///jy/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////55Z//+IM///iDP//4gz//+IM///iDP//4gz//+IM///tH///////////////////8OZ//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//8OZ////////////////////////4cz//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+8jP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////48v//rXL//4gz//+IM///iDP//4gz//+WTP//2r////////////////////Dl//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///8OX//////////////////7R///+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP///Dl///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w5f//0rL//8OZ///hzP/////////////////////////////Lpf//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//8ul//////////////////+lZf//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+0f///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////nln//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+eWf//////////////////jz///4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//////////////////4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///hzP////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//////////////////+WTP//iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///y6X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///////////////////pWX//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//8ul/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//////////////////8ul//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///hzP////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz///////////////////48v//jz///4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+PP///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////pWX//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+lZf///////////////////////8OZ//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///tH///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8ul//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///y6X/////////////////////////////nln//4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///jz////jy///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////48v//jz///4gz//+IM///iDP//4gz//+IM///iDP//4gz//+IM///jz////jy//////////////////////////////jy//+eWf//iDP//4gz//+IM///iDP//4gz//+IM///jz///+nZ/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8ul//+IM///iDP//4gz//+IM///iDP//4gz//+IM///iDP//9Ky////////////////////////////////////////+PL//6Vl//+IM///iDP//4gz//+IM///lkz//+nZ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////tH///4gz//+IM///iDP//4gz//+IM///iDP//7R/////////////////////////////////////////////////////////2r///7R///+tcv//0rL///jy///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////av///nln//4gz//+IM///nln//9q/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= --------------------------------------------------------------------------------