I'm getting error code 998 (ERROR_NOACCESS) when using ReadProcessMemory to read the memory of a 64bit process (Minesweeper). I'm using python 3.5 64bit on windows 7 64bit.
The strange thing is, this error only happens with addresses that are higher up, like for example 0x 0000 0000 FF3E 0000. Lower addresses, like 0x 0000 0000 0012 AE40 don't throw an error and return correct Minesweeper data.
When I write the same program using nearly identical code in C#.NET and look at the same addresses, it works and I don't get an error!
I know the address I'm looking at is correct because I can see it with Cheat Engine and VMMap. I don't know if it's relevant, but the higher address I'm looking at is the base module address of the MineSweeper.exe module in Minesweeper.
Why is the python code not working?
Python code (throws error for higher addresses but works for lower):
import ctypes, struct
pid = 3484 # Minesweeper
processHandle = ctypes.windll.kernel32.OpenProcess(0x10, False, pid)
addr = 0x00000000FF3E0000 # Minesweeper.exe module base address
buffer = (ctypes.c_byte * 8)()
bytesRead = ctypes.c_ulonglong(0)
result = ctypes.windll.kernel32.ReadProcessMemory(processHandle, addr, buffer, len(buffer), ctypes.byref(bytesRead))
e = ctypes.windll.kernel32.GetLastError()
print('result: ' + str(result) + ', err code: ' + str(e))
print('data: ' + str(struct.unpack('Q', buffer)[0]))
ctypes.windll.kernel32.CloseHandle(processHandle)
# Output:
# result: 0, err code: 998
# data: 0
C#.NET code (64bit project, no errors):
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr hObject);
static void Main(string[] args)
{
var pid = 3484; // Minesweeper
var processHandle = OpenProcess(0x10, false, pid);
var addr = 0x00000000FF3E0000; // Minesweeper.exe module base address
var buffer = new byte[8];
IntPtr bytesRead;
var result = ReadProcessMemory(processHandle, new IntPtr(addr), buffer, (uint)buffer.Length, out bytesRead);
Console.WriteLine("result: " + result);
Console.WriteLine("data: " + BitConverter.ToInt64(buffer, 0).ToString());
CloseHandle(processHandle);
Console.ReadLine();
}
// Output:
// result: 1
// data: 12894362189
It's good to be explicit when using ctypes. Setting argtypes and restype appropriately will help check number and type of arguments, just like the DllImport statements in C#.
Here's a pedantic example:
import ctypes as c
from ctypes import wintypes as w
pid = 4568 # Minesweeper
k32 = c.WinDLL('kernel32', use_last_error=True)
OpenProcess = k32.OpenProcess
OpenProcess.argtypes = w.DWORD,w.BOOL,w.DWORD
OpenProcess.restype = w.HANDLE
ReadProcessMemory = k32.ReadProcessMemory
ReadProcessMemory.argtypes = w.HANDLE,w.LPCVOID,w.LPVOID,c.c_size_t,c.POINTER(c.c_size_t)
ReadProcessMemory.restype = w.BOOL
CloseHandle = k32.CloseHandle
CloseHandle.argtypes = [w.HANDLE]
CloseHandle.restype = w.BOOL
processHandle = OpenProcess(0x10, False, pid)
addr = 0x00000000FF900000 # Minesweeper.exe module base address
data = c.c_ulonglong()
bytesRead = c.c_ulonglong()
result = ReadProcessMemory(processHandle, addr, c.byref(data), c.sizeof(data), c.byref(bytesRead))
e = c.get_last_error()
print('result: {}, err code: {}, bytesRead: {}'.format(result,e,bytesRead.value))
print('data: {:016X}h'.format(data.value))
CloseHandle(processHandle)
Output:
result: 1, err code: 0, bytesRead: 8
data: 0000000300905A4Dh
Also note that you can pass the address of a data variable instead of creating a buffer and unpacking it with the struct module.
See eryksun's comment, it fixed my problem! Changed 'addr' to 'ctypes.c_void_p(addr)' in the ReadProcessMemory call.
Related
How to pass a string as argument from Python to a Go Dll using ctypes:
Go-code:
package main
import "C"
import "fmt"
//export GetInt
func GetInt() int32 {
return 42
}
//export GetString
func GetString() {
fmt.Println("Foo")
}
//export PrintHello
func PrintHello(name string) {
// if name == "hello" { ... }
fmt.Printf("From DLL: Hello, %s!", name)
}
func main() {
// Need a main function to make CGO compile package as C shared library
}
Compiled on MacOs using: GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -buildmode=c-shared -o ./dist/perf_nlp.dll
Python code:
import ctypes
def getString():
nlp = ctypes.windll.LoadLibrary("H:/perf_nlp.dll")
dllFunc = nlp.GetString
dllFunc.restype = ctypes.c_char_p
return dllFunc()
def getInt():
nlp = ctypes.windll.LoadLibrary("H:/perf_nlp.dll")
dllFunc = nlp.GetInt
dllFunc.restype = int
return dllFunc()
def readString():
nlp = ctypes.windll.LoadLibrary("H:/perf_nlp.dll")
dllFunc = nlp.ReadString
dllFunc.argtypes = [ctypes.c_char_p]
dllFunc.restype = ctypes.c_char_p
return dllFunc(b'Foo')
print(getInt())
print(getString())
print(readString()). # Fails
Out:
42
Foo
None
unexpected fault address 0x871000
fatal error: fault
[signal 0xc0000005 code=0x0 addr=0x871000 pc=0x623e501f]
goroutine 17 [running, locked to thread]:
runtime.throw(0x6245b592, 0x5)
/Users/foobar/.goenv/versions/1.14.15/src/runtime/panic.go:1116 +0x64 fp=0x1242fda4 sp=0x1242fd90 pc=0x623be404
runtime.sigpanic()
/Users/foobar/.goenv/versions/1.14.15/src/runtime/signal_windows.go:249 +0x1ed fp=0x1242fdb8 sp=0x1242fda4 pc=0x623ceb8d
runtime.memmove(0x12500011, 0x800588, 0x32efe4)
/Users/foobar/.goenv/versions/1.14.15/src/runtime/memmove_386.s:89 +0x7f fp=0x1242fdbc sp=0x1242fdb8 pc=0x623e501f
fmt.(*buffer).writeString(...)
/Users/foobar/.goenv/versions/1.14.15/src/fmt/print.go:82
fmt.(*fmt).padString(0x124a60b0, 0x800588, 0x32efe4)
/Users/foobar/.goenv/versions/1.14.15/src/fmt/format.go:110 +0x6c fp=0x1242fdfc sp=0x1242fdbc pc=0x6241576c
fmt.(*fmt).fmtS(0x124a60b0, 0x800588, 0x32efe4)
/Users/foobar/.goenv/versions/1.14.15/src/fmt/format.go:359 +0x4d fp=0x1242fe14 sp=0x1242fdfc pc=0x6241664d
fmt.(*pp).fmtString(0x124a6090, 0x800588, 0x32efe4, 0x73)
/Users/foobar/.goenv/versions/1.14.15/src/fmt/print.go:450 +0x188 fp=0x1242fe38 sp=0x1242fe14 pc=0x62418f58
fmt.(*pp).printArg(0x124a6090, 0x62447c80, 0x1248c110, 0x73)
/Users/foobar/.goenv/versions/1.14.15/src/fmt/print.go:698 +0x776 fp=0x1242fe80 sp=0x1242fe38 pc=0x6241ad56
fmt.(*pp).doPrintf(0x124a6090, 0x6245e0a5, 0x14, 0x1242ff48, 0x1, 0x1)
/Users/foobar/.goenv/versions/1.14.15/src/fmt/print.go:1030 +0x12b fp=0x1242fef0 sp=0x1242fe80 pc=0x6241d81b
fmt.Fprintf(0x62476550, 0x1248c0d8, 0x6245e0a5, 0x14, 0x1242ff48, 0x1, 0x1, 0x623e2fe7, 0x0, 0x12488030)
/Users/foobar/.goenv/versions/1.14.15/src/fmt/print.go:204 +0x52 fp=0x1242ff20 sp=0x1242fef0 pc=0x62417bd2
fmt.Printf(...)
/Users/foobar/.goenv/versions/1.14.15/src/fmt/print.go:213
main.ReadString(...)
/Users/foobar/__projects__/heine/db_dll/perf_nlp.go:19
main._cgoexpwrap_c3579cea1e16_ReadString(0x800588, 0x32efe4)
_cgo_gotypes.go:71 +0x8d fp=0x1242ff54 sp=0x1242ff20 pc=0x6241e9bd
runtime.call16(0x0, 0x32ef1c, 0x32ef68, 0x8, 0x0)
/Users/foobar/.goenv/versions/1.14.15/src/runtime/asm_386.s:565 +0x30 fp=0x1242ff68 sp=0x1242ff54 pc=0x623e3020
runtime.cgocallbackg1(0x0)
/Users/foobar/.goenv/versions/1.14.15/src/runtime/cgocall.go:332 +0x149 fp=0x1242ffb0 sp=0x1242ff68 pc=0x62393f59
runtime.cgocallbackg(0x0)
/Users/foobar/.goenv/versions/1.14.15/src/runtime/cgocall.go:207 +0xb5 fp=0x1242ffe0 sp=0x1242ffb0 pc=0x62393d85
runtime.cgocallback_gofunc(0x0, 0x0, 0x0, 0x0)
/Users/foobar/.goenv/versions/1.14.15/src/runtime/asm_386.s:806 +0x7e fp=0x1242fff0 sp=0x1242ffe0 pc=0x623e419e
runtime.goexit()
/Users/foobar/.goenv/versions/1.14.15/src/runtime/asm_386.s:1337 +0x1 fp=0x1242fff4 sp=0x1242fff0 pc=0x623e4651
Working solution:
//export ReadString
func ReadString(name *C.char) *C.char {
res := "";
goName := C.GoString(name);
if goName == "Foo" {
res = "From DLL: Hello, Foo"
}else{
res = "From DLL: Hello!"
}
return C.CString(res)
}
Python:
def readString():
nlp = ctypes.windll.LoadLibrary("H:/perf_nlp.dll")
dllFunc = nlp.ReadString
dllFunc.argtypes = [ctypes.c_char_p]
dllFunc.restype = ctypes.c_char_p
return dllFunc(b'cFoo')
A Go string and a C string are entirely unrelated (except in that both are called strings, which is a lie for at least one of them).
Here Python is sending a C string because you've told it to, but Go expects a Go string, which has a completely diffrent layout so it blows up. And if it didn't blow up at the callsite it'd probably blow up when the GC tries to handle the string, which it can't, because it's not a Go string.
You want to look at the magical "C" pseudo-package: you need to take in a *C.char and copy that to a Go string using C.GoString before you can pass it to anything expecting a go String. Or something along those lines, my experience with cgo (especially calling into it) is limited to avoiding this as a bad idea.
Regardless you probably want to at the very least read the cgo documentation in full, FFI is tricky at the best of time, and FFI between two managed languages much more so.
I have a DLL with a function
EXPORT long Util_funct( char *intext, char *outtext, int *outlen )
Looks like it expects char *intext, char *outtext, int *outlen.
I wass trying to define differnt data types in python so i can pass an argument, but no success so far.
from ctypes import *
string1 = "testrr"
#b_string1 = string1.encode('utf-8')
dll = WinDLL('util.dll')
funct = dll.Util_funct
funct.argtypes = [c_wchar_p,c_char_p, POINTER(c_int)]
funct.restype = c_char_p
p = c_int()
buf = create_string_buffer(1024)
retval = funct(string1, buf, byref(p))
print(retval)
The output is None, but I see some changes in p.
Could you please help me to define proper data types for the function.
This should work:
from ctypes import *
string1 = b'testrr' # byte string for char*
dll = CDLL('util.dll') # CDLL unless function declared __stdcall
funct = dll.Util_funct
funct.argtypes = c_char_p,c_char_p,POINTER(c_int) # c_char_p for char*
funct.restype = c_long # return value is long
p = c_int()
buf = create_string_buffer(1024) # assume this is big enough???
retval = funct(string1, buf, byref(p))
print(retval)
Thanks for all your answers!
I think i figured it out. Using not the smartest way but just trying/experimenting with different data types.
As this is not a common library and i had no information for it, maybe the sulution wont be very useful for others , but anyway.
Looks like the function process only one character at a time, because if i pass a word it returns only one encoded character.
So here it is :
from ctypes import *
buf = create_unicode_buffer(1024)
string1 = "a"
c_s = c_wchar_p(string1)
dll = CDLL('util.dll')
enc = dll.Util_funct
enc.argtypes = c_wchar_p, c_wchar_p, POINTER(c_int)
enc.restype = c_long # i don't think this type matters at all
p = c_int()
enc(c_s, buf, byref(p))
print(p.value)
print(buf.value)
the output is 1 and the simbol ^
Thanks again
I was trying to reproduce the example from a previous SO post on a kernel above 4 (4.1):
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
/* Protocol family, consistent in both kernel prog and user prog. */
#define MYPROTO NETLINK_USERSOCK
/* Multicast group, consistent in both kernel prog and user prog. */
#define MYGRP 31
static struct sock *nl_sk = NULL;
static void send_to_user(void)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char *msg = "Hello from kernel";
int msg_size = strlen(msg) + 1;
int res;
pr_info("Creating skb.\n");
skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_KERNEL);
if (!skb) {
pr_err("Allocation failure.\n");
return;
}
nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
strcpy(nlmsg_data(nlh), msg);
pr_info("Sending skb.\n");
res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_KERNEL);
if (res < 0)
pr_info("nlmsg_multicast() error: %d\n", res);
else
pr_info("Success.\n");
}
static int __init hello_init(void)
{
pr_info("Inserting hello module.\n");
nl_sk = netlink_kernel_create(&init_net, MYPROTO, NULL);
if (!nl_sk) {
pr_err("Error creating socket.\n");
return -10;
}
send_to_user();
netlink_kernel_release(nl_sk);
return 0;
}
static void __exit hello_exit(void)
{
pr_info("Exiting hello module.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
However, compilation works fine, but when I insert the module, it returns:
nlmsg_multicast() error: -3
I dont even know, where I can lookup the error codes to learn, what -3 means in this context (I searched here, but was unable to find anything useful, regarding the error code).
Just to be sure, I post the userland code (Python) also:
EDITED due to a comment: (but still not working)
#!/usr/bin/env python
import socket
import os
import time
sock = socket.socket(socket.AF_NETLINK, socket.SOCK_DGRAM, socket.NETLINK_USERSOCK)
# 270 is SOL_NETLINK and 1 is NETLINK_ADD_MEMBERSHIP
sock.setsockopt(270, 1, 31)
while 1:
try:
print sock.recvfrom(1024)
except socket.error, e:
print 'Exception'
You forgot to bind the socket. :-)
I'm not very fluent with Python, so use this only as a starting point (between the socket and the setsockopt):
sock.bind((0, 0))
That prints me a bunch of garbage, among which I can see
Hello from kernel
By the way: When nlmsg_multicast() throws ESRCH, it's usually (or maybe always) because there were no clients listening.
First open the client, then try to send the message from the kernel.
Otherwise you can always ignore that error code it that makes sense for your use case.
I'd like to transmit a few bytes of data though a pipe to plot it from python.
I started with some snippets I found here but I cant get them working.
I've created the pipe like this:
int main(void){
HANDLE hPipe;
char buffer[24];
DWORD dwRead;
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_WAIT,
1,
24 * 16,
24 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
if (ConnectNamedPipe(hPipe, NULL) != FALSE) // wait for someone to connect to the pipe
{
while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
{
/* add terminating zero */
buffer[dwRead] = '\0';
/* do something with data in buffer */
printf("%s", buffer);
}
}
DisconnectNamedPipe(hPipe);
}
return 0;}
If I execute the following code it writes but the read part blocks:
import time
import struct
f = open(r'\\.\\pipe\\Pipe', 'r+b', 0)
i = 1
sss='ccccc'
while True:
s = sss.format(i)
i += 1
f.write(struct.pack('I', len(s)) + s) # Write str length and str
f.seek(0) # EDIT: This is also necessary
print 'Wrote:', s
n = struct.unpack('I', f.read(4))[0] # Read str length
s = f.read(n) # Read str
f.seek(0) # Important!!!
print 'Read:', s
time.sleep(2)
I tried commenting the ReadFile part in the C code but It did not work. Is there any other way to achieve this? I want to write from C and read from python. I tried writing into the pipe with CreateFile (from C) and it worked as expected. I only need the read part with python.
On most systems pipe is one-directional and you use two pipes to get two-directional (bidirectional) connection.
In your Python code you can open two connections
and then you don't need seek
import time
import struct
wf = open(r'Pipe', 'wb', 0)
rf = open(r'Pipe', 'rb', 0)
i = 0
template = 'Hello World {}'
while True:
i += 1
text = template.format(i)
# write text length and text
wf.write(struct.pack('I', len(text)))
wf.write(text)
print 'Wrote:', text
# read text length and text
n = struct.unpack('I', rf.read(4))[0]
read = rf.read(n)
print 'Read:', read
time.sleep(2)
EDIT: tested on Linux Mint 17, Python 3.4 & 2.7
I've solved it with PyWin32(http://sourceforge.net/projects/pywin32/files/) which seems to be the right tool for windows. I would rather use something more cross-plataform oriented but it has solved the problem.
I have the following named pipe created in Windows Powershell.
# .NET 3.5 is required to use the System.IO.Pipes namespace
[reflection.Assembly]::LoadWithPartialName("system.core") | Out-Null
$pipeName = "pipename"
$pipeDir = [System.IO.Pipes.PipeDirection]::InOut
$pipe = New-Object system.IO.Pipes.NamedPipeServerStream( $pipeName, $pipeDir )
Now, what i need is some Python code snippet to read from the above named pipe created. Can Python do that ?
Thanks in advance !
Courtesy :http://jonathonreinhart.blogspot.com/2012/12/named-pipes-between-c-and-python.html
Here's the C# Code
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
class PipeServer
{
static void Main()
{
var server = new NamedPipeServerStream("NPtest");
Console.WriteLine("Waiting for connection...");
server.WaitForConnection();
Console.WriteLine("Connected.");
var br = new BinaryReader(server);
var bw = new BinaryWriter(server);
while (true)
{
try
{
var len = (int)br.ReadUInt32(); // Read string length
var str = new string(br.ReadChars(len)); // Read string
Console.WriteLine("Read: \"{0}\"", str);
//str = new string(str.Reverse().ToArray()); // Aravind's edit: since Reverse() is not working, might require some import. Felt it as irrelevant
var buf = Encoding.ASCII.GetBytes(str); // Get ASCII byte array
bw.Write((uint)buf.Length); // Write string length
bw.Write(buf); // Write string
Console.WriteLine("Wrote: \"{0}\"", str);
}
catch (EndOfStreamException)
{
break; // When client disconnects
}
}
}
}
And here's the Python code:
import time
import struct
f = open(r'\\.\pipe\NPtest', 'r+b', 0)
i = 1
while True:
s = 'Message[{0}]'.format(i)
i += 1
f.write(struct.pack('I', len(s)) + s) # Write str length and str
f.seek(0) # EDIT: This is also necessary
print 'Wrote:', s
n = struct.unpack('I', f.read(4))[0] # Read str length
s = f.read(n) # Read str
f.seek(0) # Important!!!
print 'Read:', s
time.sleep(2)
Convert the C# code into a .ps1 file.