本帖最后由 ind 于 2023-09-03 09:16 编辑
用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[int][]byte) for i := range originBytes { oldstr, keys := str2bytes(originBytes[i]) patchstr, patchkeys := str2bytes(newBytes[i]) 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[v : v+patchlens] tmpdata := fuzzreplace(tmpstr, patchstr, patchkeys) patchlist[v] = 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[i] = -1 }
wildaddr := 0 if len(fuzzkeys) > 0 { wildaddr = fuzzkeys[len(fuzzkeys)-1] } for i := wildaddr + 1; i < dwsublen; i++ { p[hexsub[i]] = dwsublen - i }
for i := 0; i < 256; i++ { if p[i] == -1 { p[i] = 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[j-k] != hexsub[dwsublen-k-1] { found = false break } } if found { if j < dwsrclen { offsets = append(offsets, j-dwsublen+1) if patchonce { break } } } if j < dwsrclen-dwsublen-1 { j += p[src[j+1]] } 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[i] = oldstr[i] } } return tmplist }
func replace(origin []byte, patchlist map[int][]byte) []byte { tmpdata := origin for index, new := range patchlist { copy(tmpdata[index:index+len(new)], 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[i*2 : i*2+2] if tmphex == "??" { fuzzkeys = append(fuzzkeys, i) } } tmpstr = strings.Replace(tmpstr, "??", "00", -1) binlist, _ := hex.DecodeString(tmpstr) return binlist, fuzzkeys }
|