-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1d344a6
commit 8ebb2fa
Showing
12 changed files
with
1,699 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
// Use IntelliSense to learn about possible attributes. | ||
// Hover to view descriptions of existing attributes. | ||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||
"version": "0.2.0", | ||
"configurations": [ | ||
{ | ||
"name": "Launch", | ||
"type": "go", | ||
"request": "launch", | ||
"mode": "auto", | ||
"program": "${fileDirname}", | ||
"env": {}, | ||
"args": ["-sdk", "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\", | ||
// "--printretval", | ||
// "--printanno", | ||
"--minify", | ||
], | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,39 @@ | ||
# winsdk2json | ||
Windows SDK parsed to JSON | ||
# Windows SDK API definition in JSON | ||
|
||
sdk2json is a go package that parses the Windows SDK (prototypes, structures, unions) to JSON format. | ||
|
||
Here is an example: | ||
|
||
```json | ||
{ | ||
"advapi32.dll": { | ||
"ControlService": { | ||
"callconv": "WINAPI", | ||
"name": "ControlService", | ||
"retVal": "BOOL", | ||
"params": [ | ||
{ | ||
"anno": "_In_", | ||
"type": "SC_HANDLE", | ||
"name": "hService" | ||
}, | ||
{ | ||
"anno": "_In_", | ||
"type": "DWORD", | ||
"name": "dwControl" | ||
}, | ||
{ | ||
"anno": "_Out_", | ||
"type": "LPSERVICE_STATUS", | ||
"name": "lpServiceStatus" | ||
} | ||
] | ||
}, | ||
``` | ||
|
||
The malware sandbox hooking module makes use of this to implement a generic hook handler that does not require to implement a handler for each API we need to hook. | ||
|
||
|
||
## Challenges | ||
|
||
- Not a consistent way of defines functions prototypes or structs. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// Copyright 2021 Saferwall. All rights reserved. | ||
// Use of this source code is governed by Apache v2 license | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"log" | ||
|
||
"regexp" | ||
"strings" | ||
) | ||
|
||
const ( | ||
// RegAPIs is a regex that extract API prototypes. | ||
RegAPIs = `(_Success_|HANDLE|INTERNETAPI|WINHTTPAPI|BOOLAPI|BOOL|STDAPI|WINUSERAPI|WINBASEAPI|WINADVAPI|NTSTATUS|_Must_inspect_result_|BOOLEAN|int)[\w\s\)\(,\[\]\!*+=&<>/|]+;` | ||
|
||
// RegProto extracts API information. | ||
RegProto = `(?P<Attr>WINBASEAPI|WINADVAPI|WSAAPI)?( )?(?P<RetValType>[A-Za-z]+) (?P<CallConv>WINAPI|APIENTRY|WSAAPI) (?P<ApiName>[a-zA-Z0-9]+)( )?\((?P<Params>.*)\);` | ||
|
||
// RegAPIParams parses params. | ||
RegAPIParams = `(?P<Anno>_In_|IN|OUT|_In_opt_|_Inout_opt_|_Out_|_Inout_|_Out_opt_|_Outptr_opt_|_Reserved_|_(O|o)ut[\w(),+ *]+|_In[\w()]+|_When[\w() =,!*]+) (?P<Type>[\w *]+) (?P<Name>[*a-zA-Z0-9]+)` | ||
|
||
// RegParam extacts API parameters. | ||
RegParam = `, ` | ||
) | ||
|
||
// APIParam represents a paramter of a Win32 API. | ||
type APIParam struct { | ||
Annotation string `json:"anno"` | ||
Type string `json:"type"` | ||
Name string `json:"name"` | ||
} | ||
|
||
// API represents information about a Win32 API. | ||
type API struct { | ||
Attribute string `json:"-"` // Microsoft-specific attribute. | ||
CallingConvention string `json:"callconv"` // Calling Convention. | ||
Name string `json:"name"` // Name of the API. | ||
ReturnValueType string `json:"retVal"` // Return value type. | ||
Params []APIParam `json:"params"` // API Arguments. | ||
CountParams uint8 `json:"-"` // Count of Params. | ||
} | ||
|
||
func parseAPIParameter(params string) APIParam { | ||
m := regSubMatchToMapString(RegAPIParams, params) | ||
apiParam := APIParam{ | ||
Annotation: m["Anno"], | ||
Name: m["Name"], | ||
Type: m["Type"], | ||
} | ||
|
||
// move the `*` to the type. | ||
if strings.HasPrefix(apiParam.Name, "*") { | ||
apiParam.Name = apiParam.Name[1:] | ||
apiParam.Type += "*" | ||
} | ||
|
||
return apiParam | ||
} | ||
|
||
func parseAPI(apiPrototype string) API { | ||
m := regSubMatchToMapString(RegProto, apiPrototype) | ||
api := API{ | ||
Attribute: m["Attr"], | ||
CallingConvention: m["CallConv"], | ||
Name: m["ApiName"], | ||
ReturnValueType: m["RetValType"], | ||
} | ||
|
||
// Treat the VOID case. | ||
if m["Params"] == " VOID " { | ||
api.CountParams = 0 | ||
return api | ||
} | ||
|
||
if api.Name == "" || api.CallingConvention == "" { | ||
log.Printf("Failed to parse: %s", apiPrototype) | ||
return api | ||
} | ||
|
||
re := regexp.MustCompile(RegParam) | ||
split := re.Split(m["Params"], -1) | ||
for i, v := range split { | ||
// Quick hack: | ||
ss := strings.Split(standardizeSpaces(v), " ") | ||
if len(ss) == 2 { | ||
// Force In for API without annotations. | ||
v = "_In_ " + v | ||
} else { | ||
if i+1 < len(split) { | ||
vv := standardizeSpaces(split[i+1]) | ||
if !strings.HasPrefix(vv, "In") && | ||
!strings.HasPrefix(vv, "Out") && | ||
!strings.HasPrefix(vv, "_In") && | ||
!strings.HasPrefix(vv, "IN") && | ||
!strings.HasPrefix(vv, "OUT") && | ||
!strings.HasPrefix(vv, "_Reserved") && | ||
!strings.HasPrefix(vv, "_When") && | ||
!strings.HasPrefix(vv, "__out") && | ||
!strings.HasPrefix(vv, "_Out") { | ||
v += ", " + split[i+1] | ||
split[i+1] = v | ||
continue | ||
} | ||
} | ||
} | ||
api.Params = append(api.Params, parseAPIParameter("_"+v)) | ||
api.CountParams++ | ||
} | ||
return api | ||
} |
Oops, something went wrong.