iamok 发表于 2023-8-31 10:45:36

一个简单的支持模糊搜索patch的代码

用go的优势就是支持全平台,一套代码我们可以给mac、linux、windows的程序做patch。
代码核心函数为patch(filename string, originBytes []string, newBytes []string, patchOnce bool),4个参数分别意义为:
1.filename 为需要patch的文件路径
2.originBytes 为需要搜索的二进制字符串数组,支持??
3.newBytes 为对应替换的二进制字符串数据,支持??
4.patchOnce 为true时表示搜索替换所有结果,为false时只搜索到的第一个结果

代码比较丑,希望各位大佬们可以优化分享。

package main

import (
        "encoding/hex"
        "fmt"
        "os"
        "strings"
)

func main() {
        exe := "test.exe"
        exeOriginBytes := []string{"8B 7B 08 8B 73 10 8B C7 83 E8 01"}
        exeNewbytes := []string{"FF 43 08 FF 43 10 B0 01 33 C0 90"}
        dll := "test.dll"
        dllOriginBytes := []string{"7F ?? 7C ?? 39 75 F4 77 ?? 39 45 FC 7F ?? 7C ?? 3B F1 77 ?? 80 7D 08 00 75 ?? 8B 37"}
        dllNewBytes := []string{"7F 00 7C 00 39 75 F4 77 00 39 45 FC 7F 00 7C 00 3B F1 77 00 80 7D 08 00 EB ?? 8B 37"}
        patch(exe, exeOriginBytes, exeNewbytes, false)
        patch(dll, dllOriginBytes, dllNewBytes, false)

}

func patch(filename string, originBytes []string, newBytes []string, patchOnce bool) {
        origin, err := os.ReadFile(filename)

        if err != nil {
                fmt.Println("patch失败,未找到指定文件: " + filename)
                return
        }
        patchlist := make(map[]byte)
        for i := range originBytes {
                oldstr, keys := str2bytes(originBytes)
                patchstr, patchkeys := str2bytes(newBytes)
                patchlens := len(patchstr)
                locs := fuzzsearch(origin, oldstr, keys, patchOnce)
                if len(locs) > 0 {
                        for i, v := range locs {
                                fmt.Printf("找到patch点: %d\n", i+1)
                                tmpstr := origin
                                tmpdata := fuzzreplace(tmpstr, patchstr, patchkeys)
                                patchlist = tmpdata
                        }
                } else {
                        fmt.Printf("未找到patch点: %d\n", i+1)
                        return
                }
        }
        newFile := replace(origin, patchlist)
        err = os.WriteFile(filename, newFile, os.ModePerm)
        if err == nil {
                fmt.Println(filename + " Patch成功")
        } else {
                fmt.Println(filename + " Patch失败")
        }
}

func fuzzsearch(src []byte, hexsub []byte, fuzzkeys []int, patchonce bool) []int {
        offsets := []int{}
        dwsublen := len(hexsub)
        dwsrclen := len(src)

        p := make([]int, 256)

        for i := 0; i < 256; i++ {
                p = -1
        }

        wildaddr := 0
        if len(fuzzkeys) > 0 {
                wildaddr = fuzzkeys
        }
        for i := wildaddr + 1; i < dwsublen; i++ {
                p] = dwsublen - i
        }

        for i := 0; i < 256; i++ {
                if p == -1 {
                        p = dwsublen - wildaddr
                }
        }
        j, k := 0, 0
        j = dwsublen - 1
        found := true
        for {
                found = true
                for k = 0; k < dwsublen; k++ {
                        if !isfound(fuzzkeys, dwsublen-k-1) && src != hexsub {
                                found = false
                                break
                        }
                }
                if found {
                        if j < dwsrclen {
                                offsets = append(offsets, j-dwsublen+1)
                                if patchonce {
                                        break
                                }
                        }
                }
                if j < dwsrclen-dwsublen-1 {
                        j += p]
                } else {
                        j++
                }
                if j > dwsrclen-dwsublen {
                        break
                }
        }
        return offsets
}

func isfound(source []int, ptr int) bool {
        for _, i := range source {
                if i == ptr {
                        return true
                }
        }
        return false
}

func fuzzreplace(oldstr []byte, patchstr []byte, patchkeys []int) []byte {
        tmplist := make([]byte, len(patchstr))
        copy(tmplist, patchstr)
        for i := range tmplist {
                if isfound(patchkeys, i) {
                        tmplist = oldstr
                }
        }
        return tmplist
}

func replace(origin []byte, patchlist map[]byte) []byte {
        tmpdata := origin
        for index, new := range patchlist {
                copy(tmpdata, new)
        }
        return tmpdata
}
func str2bytes(binstr string) ([]byte, []int) {
        var fuzzkeys []int
        tmpstr := strings.Replace(binstr, " ", "", -1)
        hexlens := len(tmpstr) / 2
        for i := 0; i < hexlens; i++ {
                tmphex := tmpstr
                if tmphex == "??" {
                        fuzzkeys = append(fuzzkeys, i)
                }
        }
        tmpstr = strings.Replace(tmpstr, "??", "00", -1)
        binlist, _ := hex.DecodeString(tmpstr)
        return binlist, fuzzkeys
}


风轻云淡 发表于 2023-8-31 10:49:48

加个GUI就完美了

3yu3 发表于 2023-8-31 11:04:33

大佬,求个C#版本。。

哥又回来了 发表于 2023-8-31 13:28:44

@iamok
但是代码看着很精干,不算很复杂。

飞天梦 发表于 2023-8-31 20:40:52

谢谢分享

飘云 发表于 2023-9-1 00:20:28

Go一统江湖浓浓的GPT味啊{:lol:}

iamok 发表于 2023-9-1 09:09:58

飘云 发表于 2023-9-1 00:20
Go一统江湖浓浓的GPT味啊&#128512;

哈哈,飘总一眼就看出我这个代码的业余

不过这个还真不是gpt写的,
大概21年初的时候当时网上还是看了很多别人的代码,kmp和sunday这些都看了下
抄了匹配算法部分,支持??是按自己想法改写的,所以实现方式估计很丑很业余,也不清楚现有的类似工具是用什么形式处理的。

飘云 发表于 2023-9-1 14:18:49

iamok 发表于 2023-9-1 09:09
哈哈,飘总一眼就看出我这个代码的业余

不过这个还真不是gpt写的,


反正比我写得好~ 感谢分享~{:hug:}

small-q 发表于 2023-9-1 16:48:55

本帖最后由 small-q 于 2023-9-1 16:52 编辑

谢谢大佬分享,收藏学习

飞天 发表于 2023-9-1 21:20:17

感谢分享好东西。
页: [1]
查看完整版本: 一个简单的支持模糊搜索patch的代码