Heim > Backend-Entwicklung > Golang > Änderung des Golang-Programmsymbols

Änderung des Golang-Programmsymbols

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
Freigeben: 2023-05-10 20:37:06
Original
669 Leute haben es durchsucht

Wenn wir jeden Tag Computer benutzen, müssen wir oft einige häufig verwendete Programme öffnen. Diese Programme zeigen auf unserer Benutzeroberfläche ein bestimmtes Symbol an, damit wir sie schnell identifizieren und finden können. In einigen Fällen möchten wir diese Programmsymbole jedoch möglicherweise ändern, um sie beispielsweise besser an unsere persönlichen Vorlieben oder Themen anzupassen.

In diesem Artikel konzentrieren wir uns darauf, wie man Golang und einige Systembibliotheken verwendet, um das Symbol des Programms zu ändern. Wir werden Windows als Demonstrationsumgebung verwenden.

Lassen Sie uns zunächst die grundlegenden Schritte skizzieren, die wir ausführen müssen:

  1. Öffnen Sie die Ressourcendatei des Programms (.exe- oder .dll-Datei) und suchen Sie die Symbolressource.
  2. Fügen Sie der Ressourcendatei des Programms neue Symbolressourcen hinzu.
  3. Ändern Sie die .manifest-Datei des Programms, damit es auf die neue Symbolressource zugreifen kann.

Als nächstes besprechen wir, wie Sie diese Schritte nacheinander ausführen.

Schritt eins: Öffnen Sie die Ressourcendatei und suchen Sie die Symbolressource.

In Golang können wir die Funktion in der Systembibliothek „syscall“ verwenden, um die Datei zu öffnen und zu lesen. Dazu müssen wir einige notwendige Variablen definieren:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

package main

 

import (

    "os"

    "syscall"

    "unsafe"

)

 

var (

    kernel32DLL                             = syscall.MustLoadDLL("kernel32.dll")

    BeginUpdateResourceProc     = kernel32DLL.MustFindProc("BeginUpdateResourceW")

    UpdateResourceProc              = kernel32DLL.MustFindProc("UpdateResourceW")

    EndUpdateResourceProc       = kernel32DLL.MustFindProc("EndUpdateResourceW")

)

Nach dem Login kopieren

Wir verwenden hier mehrere Funktionen in der Windows-API, nämlich „BeginUpdateResourceW“, „UpdateResourceW“ und „EndUpdateResourceW“. Diese Funktionen können uns dabei helfen, die Ressourcen in der Programmressourcendatei zu verwalten.

Als nächstes müssen wir die Ressourcendatei des Programms öffnen, das wir ändern möchten (kann eine EXE- oder DLL-Datei sein) und die Symbolressource finden. Hier verwenden wir eine Funktion namens „findIconIndex“, um die Programmressourcendatei zu durchsuchen und die Indexnummer zu finden, unter der sich die Symbolressource befindet.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

func findIconIndex(exePath string) (int, error) {

    exeFile, err := os.OpenFile(exePath, os.O_RDWR, 0666)

    defer exeFile.Close()

    if err != nil {

        return 0, err

    }

    exeStat, err := exeFile.Stat()

    if err != nil {

        return 0, err

    }

    exeSize := exeStat.Size()

 

    // DOS header

    dosHeader := new(image.DosHeader)

    err = binary.Read(exeFile, binary.LittleEndian, dosHeader)

    if err != nil {

        return 0, err

    }

    exeFile.Seek(int64(dosHeader.Lfanew), 0)

 

    // File header and optional header

    fileHeader := new(image.FileHeader)

    err = binary.Read(exeFile, binary.LittleEndian, fileHeader)

    if err != nil {

        return 0, err

    }

    extHeader := make([]byte, fileHeader.SizeOfOptionalHeader-2)

    exeFile.Read(extHeader)

 

    // Section headers

    sections := make([]image.SectionHeader, fileHeader.NumberOfSections)

    err = binary.Read(exeFile, binary.LittleEndian, sections)

    if err != nil {

        return 0, err

    }

 

    // Find icon resource

    for _, section := range sections {

        if section.Name == ".rsrc" {

            exeFile.Seek(int64(section.Offset), 0)

            resourceHeader := new(resourceHeader)

            err = binary.Read(exeFile, binary.LittleEndian, resourceHeader)

            if err != nil {

                return 0, err

            }

            stack := []resourceDirectoryEntry{resourceDirectoryEntry{uint32(resourceHeader.RootID), int64(resourceHeader.OffsetToDirectory)}}

            for len(stack) > 0 {

                currentEntry := stack[len(stack)-1]

                stack = stack[:len(stack)-1]

                exeFile.Seek(currentEntry.offset, 0)

                directoryHeader := new(resourceDirectoryHeader)

                err = binary.Read(exeFile, binary.LittleEndian, directoryHeader)

                if err != nil {

                    return 0, err

                }

                entries := make([]resourceDirectoryEntry, directoryHeader.NumNamedEntries+directoryHeader.NumIDEntries)

                for i := range entries {

                    err = binary.Read(exeFile, binary.LittleEndian, &entries[i])

                    if err != nil {

                        return 0, err

                    }

                    if entries[i].nameIsString {

                        nameBytes := make([]byte, entries[i].nameOffset&0x7FFFFFFF)

                        exeFile.Read(nameBytes)

                        entries[i].name = syscall.UTF16ToString(nameBytes)

                    }

                }

                for _, entry := range entries {

                    if entry.ID&^0xFFFF == rtIcon {

                        return int(entry.ID & 0xFFFF), nil

                    } else if entry.name == "ICON" {

                        stack = append(stack, resourceDirectoryEntry{entry.ID, int64(entry.offset)})

                    } else if entry.name == "#0" && entry.ID&^0xFFFF == rtGroupIcon {

                        groupIconDirHeader := new(resourceGroupIconDirectoryHeader)

                        exeFile.Seek(int64(entry.offset), 0)

                        err = binary.Read(exeFile, binary.LittleEndian, groupIconDirHeader)

                        if err != nil {

                            return 0, err

                        }

                        var largestIcon resourceGroupIconDirectoryEntry

                        for i := 0; i < int(groupIconDirHeader.Count); i++ {

                            groupIconDirEntry := new(resourceGroupIconDirectoryEntry)

                            err = binary.Read(exeFile, binary.LittleEndian, groupIconDirEntry)

                            if err != nil {

                                return 0, err

                            }

                            if groupIconDirEntry.Width > largestIcon.Width || groupIconDirEntry.Height > largestIcon.Height {

                                largestIcon = *groupIconDirEntry

                            }

                        }

                        return int(largestIcon.ID), nil

                    } else if entry.name == "ICONGROUP" {

                        stack = append(stack, resourceDirectoryEntry{entry.ID, int64(entry.offset)})

                    } else if entry.name == "MAINICON" {

                        stack = append(stack, resourceDirectoryEntry{entry.ID, int64(entry.offset)})

                    } else {

                        stack = append(stack, resourceDirectoryEntry{entry.ID, int64(entry.offset)})

                    }

                }

            }

            return 0, fmt.Errorf("Icon not found")

        }

    }

    return 0, fmt.Errorf("Resource not found")

}

Nach dem Login kopieren

Diese Funktion durchläuft jeden Abschnitt (.rsrc) in der Programmressourcendatei und findet den Index der Symbolressource. Normalerweise hängt die Indizierung von der Größe und dem Format der Symbolressource ab. Wir können nach eigenem Ermessen entscheiden, welchen Index die Symbolressource in der Ressourcendatei ändern soll.

Schritt 2: Fügen Sie die neue Symbolressource zur Ressourcendatei hinzu

Um die neue Symbolressource zur Programmressourcendatei hinzuzufügen, müssen wir sie zuerst im ICO-Dateiformat speichern. Wir können die Bildbibliothek in Golang verwenden, um ICO-Dateien zu erstellen.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

package main

 

import (

    "image"

    "image/draw"

    "image/png"

    "os"

)

 

func writeIcoFile(icon image.Image, filename string) error {

    file, err := os.Create(filename)

    if err != nil {

        return err

    }

    defer file.Close()

 

    // Create icon file header

    iconSize := icon.Bounds().Size()

    fileHeader := new(resourceIconFileHeader)

    fileHeader.Reserved = 0

    fileHeader.Type = 1

    fileHeader.Count = 1

 

    // Create icon directory entry

    dirEntry := new(resourceIconDirectoryEntry)

    dirEntry.Width = uint8(iconSize.X)

    dirEntry.Height = uint8(iconSize.Y)

    dirEntry.Colors = 0

    dirEntry.Reserved = 0

    dirEntry.Plane = 1

    dirEntry.BitCount = 32

    dirEntry.SizeInBytes = uint32(40 + 4*iconSize.X*iconSize.Y)

    dirEntry.Offset = 22

 

    // Create bitmap info header and color mask for bitmap graphics

    colorMask := [12]byte{0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00}

    infoHeader := new(bitmapInfoHeader)

    infoHeader.Size = 40

    infoHeader.Width = int32(iconSize.X)

    infoHeader.Height = int32(2 * iconSize.Y)

    infoHeader.Planes = 1

    infoHeader.BitCount = 32

    infoHeader.Compression = 0

    infoHeader.SizeImage = uint32(4 * iconSize.X * iconSize.Y)

    infoHeader.XPelsPerMeter = 0

    infoHeader.YPelsPerMeter = 0

    infoHeader.ClrUsed = 0

    infoHeader.ClrImportant = 0

 

    // Write icon file header, directory entry, bitmap info header and color mask

    binary.Write(file, binary.LittleEndian, fileHeader)

    binary.Write(file, binary.LittleEndian, dirEntry)

    binary.Write(file, binary.LittleEndian, infoHeader)

    binary.Write(file, binary.LittleEndian, colorMask)

 

    // Write bitmap graphics

    rgba := image.NewRGBA(image.Rect(0, 0, iconSize.X, 2*iconSize.Y))

    draw.Draw(rgba, rgba.Bounds(), image.Black, image.ZP, draw.Src)

    draw.Draw(rgba, image.Rect(0, 0, iconSize.X, iconSize.Y), icon, image.ZP, draw.Over)

    draw.Draw(rgba, image.Rect(0, iconSize.Y, iconSize.X, 2*iconSize.Y), image.Transparent, image.ZP, draw.Src)

    err = png.Encode(file, rgba)

    if err != nil {

        return err

    }

 

    return nil

}

Nach dem Login kopieren

Diese Funktion erstellt einen ICO-Dateiheader und hängt die Symbolressource daran an. Der Header der ICO-Datei enthält notwendige Informationen zu den Symbolressourcen in der ICO-Datei.

Als nächstes schreiben wir sie in Ressourcendateien. Dazu müssen wir die Funktionen „BeginUpdateResource“, „UpdateResource“ und „EndUpdateResource“ in der Windows-API verwenden.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

func updateIcon(exePath, icoPath string, iconIndex int) error {

    exeFile, err := os.OpenFile(exePath, os.O_RDWR, 0666)

    defer exeFile.Close()

    if err != nil {

        return err

    }

 

    icoFile, err := os.Open(icoPath)

    defer icoFile.Close()

    if err != nil {

        return err

    }

 

    // Read ICO file and prepare icon directory entry

    icoData, err := ioutil.ReadAll(icoFile)

    if err != nil {

        return err

    }

    dirEntry := new(resourceIconDirectoryEntry)

    dirEntry.Width = 0

    dirEntry.Height = 0

    dirEntry.Colors = 0

    dirEntry.Reserved = 0

    dirEntry.Plane = 1

    dirEntry.BitCount = 0

    dirEntry.SizeInBytes = uint32(len(icoData))

    dirEntry.Offset = 22

 

    // Find update handle

    exeHandle, err := syscall.CreateFile(syscall.StringToUTF16Ptr(exePath), syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)

    if err != nil {

        return err

    }

    defer syscall.CloseHandle(exeHandle)

    updateHandle, _, err := BeginUpdateResourceProc.Call(uintptr(exeHandle), 0)

    defer syscall.CloseHandle(syscall.Handle(updateHandle))

    if updateHandle == 0 {

        return fmt.Errorf("BeginUpdateResourceW failed")

    }

 

    // Write resource to update handle

    success, _, err := UpdateResourceProc.Call(uintptr(updateHandle), uintptr(rtIcon), uintptr(iconIndex), 0, uintptr(unsafe.Pointer(&icoData[0])), uintptr(len(icoData)))

    if success == 0 {

        return fmt.Errorf("UpdateResourceW failed")

    }

 

    // Write updated icon directory entry

    success, _, err = UpdateResourceProc.Call(uintptr(updateHandle), uintptr(rtGroupIcon), uintptr(MAKEINTRESOURCE(iconIndex)), 0, uintptr(unsafe.Pointer(dirEntry)), uintptr(unsafe.Sizeof(*dirEntry)))

    if success == 0 {

        return fmt.Errorf("UpdateResourceW failed")

    }

 

    // Commit update handle

    success, _, err = EndUpdateResourceProc.Call(updateHandle, 0)

    if success == 0 {

        return fmt.Errorf("EndUpdateResourceW failed")

    }

 

    return nil

}

Nach dem Login kopieren

Schritt 3: Ändern Sie die .manifest-Datei des Programms

Wir müssen die .manifest-Datei des Programms ändern, damit es auf die neue Symbolressource zugreifen kann. Dazu müssen wir der .manifest-Datei Folgendes hinzufügen:

1

2

3

4

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

  <assemblyIdentity type="win32" name="MyApplication" version="1.0.0.0" processorArchitecture="x86" />

  <icon type="group">MyIconResourceIndex</icon>

</assembly>

Nach dem Login kopieren

Dadurch wird dem Programm eine Symbolressourcen-Indexnummer zugewiesen, damit es die neue Symbolressource verwenden kann. Wir können die OS-Bibliothek in Golang verwenden, um die .manifest-Datei zu ändern.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

func updateManifest(manifestPath string, iconIndex int) error {

    manifestData, err := ioutil.ReadFile(manifestPath)

    if err != nil {

        return err

    }

 

    updatedManifest := strings.Replace(string(manifestData), "</assembly>", "  <icon type="group">"+strconv.Itoa(iconIndex)+"</icon>

</assembly>", 1)

 

    err = ioutil.WriteFile(manifestPath, []byte(updatedManifest), 0666)

    if err != nil {

        return err

    }

 

    return nil

}

Nach dem Login kopieren

Jetzt wissen wir, wie man das Symbol des Programms mithilfe von Golang- und Systembibliotheken ändert. Wenn wir diese Schritte zusammenfügen, erstellen wir eine vollständige Funktion. Hier ist ein Beispielcode:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

package main

 

import (

    "encoding/binary"

    "encoding/hex"

    "fmt"

    "image"

    "image/png"

    "io/ioutil"

    "os"

    "strconv"

    "strings"

    "syscall"

    "unsafe"

)

 

const (

    rtIcon        = 14

    rtGroupIcon   = rtIcon + 11

    LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020

)

 

// Resource header

type resourceHeader struct {

    RootID        uint16

    RootType      uint16

    RootName      [16]uint16

    RootDataSize  uint32

    RootDataVer   uint32

    RootDate      uint32

    RootRMLow     uint16

    RootRMHigh    uint16

    RootLangID    uint16

    RootDataVerOS uint32

}

 

// Resource directory header

type resourceDirectoryHeader struct {

    Characteristics uint32

    TimeDateStamp   uint32

    VersionMajor    uint16

    VersionMinor    uint16

    NumNamedEntries uint16

    NumIDEntries    uint16

}

 

// Resource directory entry

type resourceDirectoryEntry struct {

    nameIsString bool

    ID           uint32

    offset       uint32

    nameOffset   uint32

    name         string

}

 

// Resource icon file header

type resourceIconFileHeader struct {

    Reserved uint16

    Type     uint16

    Count    uint16

}

 

// Resource icon directory entry

type resourceIconDirectoryEntry struct {

    Width       uint8

    Height      uint8

    Colors      uint8

    Reserved    uint8

    Plane       uint16

    BitCount    uint16

    SizeInBytes uint32

    Offset      uint32

}

 

// Resource group icon directory header

type resourceGroupIconDirectoryHeader struct {

    Width    uint16

    Height   uint16

    ColorCount uint16

    Reserved uint16

    Planes   uint16

    BitCount uint16

    Count    uint32

}

 

// Resource group icon directory entry

type resourceGroupIconDirectoryEntry struct {

    Width      uint8

    Height     uint8

    ColorCount uint8

    Reserved   uint8

    Planes     uint16

    BitCount   uint16

    BytesInRes uint32

    ID         uint16

}

 

// Bitmap header

type bitmapInfoHeader struct {

    Size          uint32

    Width         int32

    Height        int32

    Planes        uint16

    BitCount      uint16

    Compression   uint32

    SizeImage     uint32

    XPelsPerMeter int32

    YPelsPerMeter int32

    ClrUsed       uint32

    ClrImportant  uint32

}

 

var (

    kernel32DLL                = syscall.MustLoadDLL("kernel32.dll")

    user32DLL                  = syscall.MustLoadDLL("user32.dll")

    autoDetectEncodingProc     = kernel32DLL.MustFindProc("AutoDetectEncoding")

    BeginUpdateResourceProc    = kernel32DLL.MustFindProc("BeginUpdateResourceW")

    LoadImageProc              = user32DLL.MustFindProc("LoadImageW")

    ResourceNotFound         = fmt.Errorf("Resource not found")

    NoIconFound             = fmt.Errorf("Icon not found")

)

 

func main() {

    exePath := "path/to/program.exe"

    icoPath := "path/to/newicon.png"

    manifestPath := "path/to/program.exe.manifest"

    iconIndex, err := findIconIndex(exePath)

Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonÄnderung des Golang-Programmsymbols. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage