myph.git


myph

~ shellcode loader for your evasion needs
git clone https://github.com/matro7sh/myph.git
log | files | refs | archive | README | LICENSE

fromJson.go (8992B)

      1 package rc
      2 
      3 /*
      4    Copied from :
      5    https://github.com/tc-hib/go-winres/blob/main/resdir.go
      6 
      7    and took just what we need. I left the data types as-is
      8    if we want to expand usage later.
      9 
     10    it would be really cool if this was just in the library,
     11    but it might be actually, id have to check this out.
     12 */
     13 
     14 import (
     15 	"encoding/json"
     16 	"errors"
     17 	"image"
     18 	"os"
     19 	"path/filepath"
     20 	"sort"
     21 	"strconv"
     22 	"strings"
     23 
     24 	"github.com/tc-hib/winres"
     25 	"github.com/tc-hib/winres/version"
     26 )
     27 
     28 const (
     29 	errInvalidSet    = "invalid resource set definition"
     30 	errInvalidCursor = "invalid cursor definition"
     31 	errInvalidIcon   = "invalid icon definition"
     32 )
     33 
     34 type jsonDef map[string]map[string]map[string]interface{}
     35 
     36 var typeIDToString = map[winres.ID]string{
     37 	winres.RT_CURSOR:       "RT_CURSOR",
     38 	winres.RT_BITMAP:       "RT_BITMAP",
     39 	winres.RT_ICON:         "RT_ICON",
     40 	winres.RT_MENU:         "RT_MENU",
     41 	winres.RT_DIALOG:       "RT_DIALOG",
     42 	winres.RT_STRING:       "RT_STRING",
     43 	winres.RT_FONTDIR:      "RT_FONTDIR",
     44 	winres.RT_FONT:         "RT_FONT",
     45 	winres.RT_ACCELERATOR:  "RT_ACCELERATOR",
     46 	winres.RT_RCDATA:       "RT_RCDATA",
     47 	winres.RT_MESSAGETABLE: "RT_MESSAGETABLE",
     48 	winres.RT_GROUP_CURSOR: "RT_GROUP_CURSOR",
     49 	winres.RT_GROUP_ICON:   "RT_GROUP_ICON",
     50 	winres.RT_VERSION:      "RT_VERSION",
     51 	winres.RT_PLUGPLAY:     "RT_PLUGPLAY",
     52 	winres.RT_VXD:          "RT_VXD",
     53 	winres.RT_ANICURSOR:    "RT_ANICURSOR",
     54 	winres.RT_ANIICON:      "RT_ANIICON",
     55 	winres.RT_HTML:         "RT_HTML",
     56 	winres.RT_MANIFEST:     "RT_MANIFEST",
     57 }
     58 
     59 var typeIDFromString = map[string]winres.ID{
     60 	"RT_CURSOR":       winres.RT_CURSOR,
     61 	"RT_BITMAP":       winres.RT_BITMAP,
     62 	"RT_ICON":         winres.RT_ICON,
     63 	"RT_MENU":         winres.RT_MENU,
     64 	"RT_DIALOG":       winres.RT_DIALOG,
     65 	"RT_STRING":       winres.RT_STRING,
     66 	"RT_FONTDIR":      winres.RT_FONTDIR,
     67 	"RT_FONT":         winres.RT_FONT,
     68 	"RT_ACCELERATOR":  winres.RT_ACCELERATOR,
     69 	"RT_RCDATA":       winres.RT_RCDATA,
     70 	"RT_MESSAGETABLE": winres.RT_MESSAGETABLE,
     71 	"RT_GROUP_CURSOR": winres.RT_GROUP_CURSOR,
     72 	"RT_GROUP_ICON":   winres.RT_GROUP_ICON,
     73 	"RT_VERSION":      winres.RT_VERSION,
     74 	"RT_PLUGPLAY":     winres.RT_PLUGPLAY,
     75 	"RT_VXD":          winres.RT_VXD,
     76 	"RT_ANICURSOR":    winres.RT_ANICURSOR,
     77 	"RT_ANIICON":      winres.RT_ANIICON,
     78 	"RT_HTML":         winres.RT_HTML,
     79 	"RT_MANIFEST":     winres.RT_MANIFEST,
     80 }
     81 
     82 func idsFromStrings(t, r, l string) (winres.Identifier, winres.Identifier, uint16, error) {
     83 	var (
     84 		typeID winres.Identifier
     85 		resID  winres.Identifier
     86 		langID uint16
     87 	)
     88 
     89 	if id, ok := typeIDFromString[t]; ok {
     90 		typeID = id
     91 	} else {
     92 		typeID = stringToIdentifier(t)
     93 	}
     94 	if typeID == nil {
     95 		return nil, nil, 0, errors.New("invalid type identifier")
     96 	}
     97 
     98 	resID = stringToIdentifier(r)
     99 	if resID == nil {
    100 		return nil, nil, 0, errors.New("invalid resource identifier")
    101 	}
    102 
    103 	n, err := strconv.ParseUint(l, 16, 16)
    104 	if err != nil {
    105 		return nil, nil, 0, errors.New("invalid language identifier")
    106 	}
    107 	langID = uint16(n)
    108 
    109 	return typeID, resID, langID, nil
    110 }
    111 
    112 func stringToIdentifier(s string) winres.Identifier {
    113 	if s == "" {
    114 		return nil
    115 	}
    116 	if s[0] == '#' {
    117 		n, err := strconv.ParseInt(s[1:], 10, 16)
    118 		if err == nil {
    119 			return winres.ID(n)
    120 		}
    121 	}
    122 	return winres.Name(s)
    123 }
    124 
    125 func LoadResourcesFromJson(rs *winres.ResourceSet, jsonName string) error {
    126 	dir := filepath.Dir(jsonName)
    127 	b, err := os.ReadFile(jsonName)
    128 
    129 	if err != nil {
    130 		return err
    131 	}
    132 	res := jsonDef{}
    133 	err = json.Unmarshal(b, &res)
    134 	if err != nil {
    135 		return err
    136 	}
    137 
    138 	for tid, t := range res {
    139 		for _, r := range sortedRes(t) {
    140 			for _, l := range sortedLang(r.langs) {
    141 				typeID, resID, langID, err := idsFromStrings(tid, r.id, l.id)
    142 				if err != nil {
    143 					return err
    144 				}
    145 				switch typeID {
    146 				case winres.RT_ICON:
    147 					return errors.New("cannot import RT_ICON resources directly, use RT_GROUP_ICON instead")
    148 				case winres.RT_CURSOR:
    149 					return errors.New("cannot import RT_CURSOR resources directly, use RT_GROUP_CURSOR instead")
    150 				case winres.RT_GROUP_CURSOR:
    151 					cursor, err := loadCursor(dir, l.data)
    152 					if err != nil {
    153 						return err
    154 					}
    155 					err = rs.SetCursorTranslation(resID, langID, cursor)
    156 					if err != nil {
    157 						return err
    158 					}
    159 				case winres.RT_GROUP_ICON:
    160 					icon, err := loadIcon(dir, l.data)
    161 					if err != nil {
    162 						return err
    163 					}
    164 					err = rs.SetIconTranslation(resID, langID, icon)
    165 					if err != nil {
    166 						return err
    167 					}
    168 				case winres.RT_VERSION:
    169 					vi := version.Info{}
    170 					j, _ := json.Marshal(l.data)
    171 					err = json.Unmarshal(j, &vi)
    172 					if err != nil {
    173 						return err
    174 					}
    175 					rs.SetVersionInfo(vi)
    176 				case winres.RT_BITMAP:
    177 					filename, ok := l.data.(string)
    178 					if !ok {
    179 						return errors.New(errInvalidSet)
    180 					}
    181 					dib, err := loadBMP(filepath.Join(dir, filename))
    182 					if err != nil {
    183 						return err
    184 					}
    185 					err = rs.Set(winres.RT_BITMAP, resID, langID, dib)
    186 					if err != nil {
    187 						return err
    188 					}
    189 				case winres.RT_MANIFEST:
    190 					switch val := l.data.(type) {
    191 					case string:
    192 						data, err := os.ReadFile(filepath.Join(dir, val))
    193 						if err != nil {
    194 							return err
    195 						}
    196 						err = rs.Set(typeID, resID, langID, data)
    197 						if err != nil {
    198 							return err
    199 						}
    200 					default:
    201 						j, _ := json.Marshal(val)
    202 						m := winres.AppManifest{}
    203 						err = json.Unmarshal(j, &m)
    204 						if err != nil {
    205 							return err
    206 						}
    207 						rs.SetManifest(m)
    208 					}
    209 				default:
    210 					filename, ok := l.data.(string)
    211 					if !ok {
    212 						return errors.New(errInvalidSet)
    213 					}
    214 					data, err := os.ReadFile(filepath.Join(dir, filename))
    215 					if err != nil {
    216 						return err
    217 					}
    218 					err = rs.Set(typeID, resID, langID, data)
    219 					if err != nil {
    220 						return err
    221 					}
    222 				}
    223 			}
    224 		}
    225 	}
    226 
    227 	return nil
    228 }
    229 
    230 type resource struct {
    231 	id    string
    232 	langs map[string]interface{}
    233 }
    234 
    235 type lang struct {
    236 	id   string
    237 	data interface{}
    238 }
    239 
    240 func sortedRes(m map[string]map[string]interface{}) []resource {
    241 	var res []resource
    242 	for id, langs := range m {
    243 		res = append(res, resource{id, langs})
    244 	}
    245 	sort.Slice(res, func(i, j int) bool {
    246 		return res[i].id < res[j].id
    247 	})
    248 	return res
    249 }
    250 
    251 func sortedLang(m map[string]interface{}) []lang {
    252 	var l []lang
    253 	for id, data := range m {
    254 		l = append(l, lang{id, data})
    255 	}
    256 	sort.Slice(l, func(i, j int) bool {
    257 		return l[i].id < l[j].id
    258 	})
    259 	return l
    260 }
    261 
    262 func loadCursor(dir string, c interface{}) (*winres.Cursor, error) {
    263 	switch c := c.(type) {
    264 	case string:
    265 		return loadCUR(filepath.Join(dir, c))
    266 
    267 	case []interface{}:
    268 		var images []winres.CursorImage
    269 		for i := range c {
    270 			o, ok := c[i].(map[string]interface{})
    271 			if !ok {
    272 				return nil, errors.New(errInvalidCursor)
    273 			}
    274 			curImg, err := loadCursorImage(dir, o)
    275 			if err != nil {
    276 				return nil, err
    277 			}
    278 			images = append(images, curImg)
    279 		}
    280 		return winres.NewCursorFromImages(images)
    281 
    282 	case map[string]interface{}:
    283 		curImg, err := loadCursorImage(dir, c)
    284 		if err != nil {
    285 			return nil, err
    286 		}
    287 		return winres.NewCursorFromImages([]winres.CursorImage{curImg})
    288 	}
    289 
    290 	return nil, errors.New(errInvalidCursor)
    291 }
    292 
    293 func loadCursorImage(dir string, c map[string]interface{}) (winres.CursorImage, error) {
    294 	x, xOK := c["x"].(float64)
    295 	y, yOK := c["y"].(float64)
    296 	f, fOK := c["image"].(string)
    297 	if !fOK || !xOK || !yOK {
    298 		return winres.CursorImage{}, errors.New(errInvalidCursor)
    299 	}
    300 
    301 	img, err := loadImage(filepath.Join(dir, f))
    302 	if err != nil {
    303 		return winres.CursorImage{}, err
    304 	}
    305 
    306 	return winres.CursorImage{
    307 		Image:   img,
    308 		HotSpot: winres.HotSpot{X: uint16(x), Y: uint16(y)},
    309 	}, nil
    310 }
    311 
    312 func loadIcon(dir string, x interface{}) (*winres.Icon, error) {
    313 	switch x := x.(type) {
    314 	case string:
    315 		if strings.ToLower(filepath.Ext(x)) == ".ico" {
    316 			return loadICO(filepath.Join(dir, x))
    317 		}
    318 		img, err := loadImage(filepath.Join(dir, x))
    319 		if err != nil {
    320 			return nil, err
    321 		}
    322 		return winres.NewIconFromResizedImage(img, nil)
    323 	case []interface{}:
    324 		var images []image.Image
    325 		for i := range x {
    326 			f, ok := x[i].(string)
    327 			if !ok {
    328 				return nil, errors.New(errInvalidIcon)
    329 			}
    330 			img, err := loadImage(filepath.Join(dir, f))
    331 			if err != nil {
    332 				return nil, err
    333 			}
    334 			images = append(images, img)
    335 		}
    336 		return winres.NewIconFromImages(images)
    337 	}
    338 	return nil, errors.New(errInvalidIcon)
    339 }
    340 
    341 func loadImage(name string) (image.Image, error) {
    342 	f, err := os.Open(name)
    343 	if err != nil {
    344 		return nil, err
    345 	}
    346 	defer f.Close()
    347 
    348 	img, _, err := image.Decode(f)
    349 	return img, err
    350 }
    351 
    352 func loadCUR(name string) (*winres.Cursor, error) {
    353 	f, err := os.Open(name)
    354 	if err != nil {
    355 		return nil, err
    356 	}
    357 	defer f.Close()
    358 
    359 	return winres.LoadCUR(f)
    360 }
    361 
    362 func loadICO(name string) (*winres.Icon, error) {
    363 	f, err := os.Open(name)
    364 	if err != nil {
    365 		return nil, err
    366 	}
    367 	defer f.Close()
    368 
    369 	return winres.LoadICO(f)
    370 }
    371 
    372 func loadBMP(name string) ([]byte, error) {
    373 	b, err := os.ReadFile(name)
    374 	if err != nil {
    375 		return nil, err
    376 	}
    377 
    378 	if len(b) > 14 && b[0] == 'B' && b[1] == 'M' && int(b[5])<<24|int(b[4])<<16|int(b[3])<<8|int(b[2]) == len(b) {
    379 		return b[14:], nil
    380 	}
    381 
    382 	return b, nil
    383 }