├── Makefile
├── README.md
├── SConstruct
├── build
├── darwin
│ └── SConscript
├── linux2
│ └── SConscript
└── win32
│ ├── SConscript
│ ├── iconv.dll
│ ├── libxml2.dll
│ ├── pinpy.dll
│ ├── pinpy.dll.manifest
│ ├── pinpy.lib
│ ├── pinvm.dll
│ ├── python27.dll
│ └── zlib1.dll
├── examples
├── sample.c
├── sample.py
├── sample.xml
└── test-program.c
├── libs
└── pinpylibs.py
└── src
├── knowledge
├── callgraph.cpp
├── callgraph.h
└── knowledge.h
├── main.cpp
├── pin
├── pintool.cpp
└── pintool.h
├── pinfunction.cpp
├── pinfunction.h
├── pinfunctionprototype.cpp
├── pinfunctionprototype.h
├── pinpy.cpp
├── pinpy.h
├── pinpyaction.h
├── python
├── pyhelper.cpp
└── pyhelper.h
├── utils.cpp
└── utils.h
/Makefile:
--------------------------------------------------------------------------------
1 | SRCS=src/main.cpp src/pinpy.cpp src/utils.cpp src/pinfunction.cpp src/pinfunctionprototype.cpp
2 | OBJS=$(patsubst %.cpp, %.o, $(SRCS))
3 | EXEC=pinpy-bin
4 | CC=clang++
5 | CFLAGS=-g -Wall -O2 -fno-strict-aliasing -std=c++98 -fPIC
6 | OFLAGS=-lxml2 -lpcrecpp -Wl,-all_load
7 | LFLAGS=-L/opt/local/lib/
8 | INC=-I/opt/local/include/libxml2 -I/opt/local/include -I.
9 |
10 | %.o : %.cpp
11 | $(CC) -c $(CFLAGS) $(INC) $< -o $@
12 |
13 | $(EXEC) : $(OBJS)
14 | $(CC) -o $(EXEC) $(OFLAGS) $(OBJS) $(LFLAGS)
15 |
16 | .PHONY: clean
17 | clean:
18 | @rm -f $(OBJS) $(EXEC) $(ARNAME)
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PinPy - Shake your hooks with some Python!
2 |
3 | Disclaimer: The code is essentially a proof of concept developed by Romain Gaucher ([@rgaucher](https://twitter.com/rgaucher)) and Haris Andrianakis ([@tl0gic](https://twitter.com/tl0gic)) .
4 | It was tested on example programs, and larger. For larger ones, well... it will slow down the execution.
5 | Even if PinPy is not under active development, we decided to release, since the
6 | code might interest few folks out there.
7 |
8 | PinPy essentially allows you to to run Python scripts inside whatever programs, just educate it
9 | using the XML config file, what you want to hook. You'll need to get some information so that
10 | pin can properly install the hooks such as signature, etc. This is done by embedding a Python runtime
11 | in a pin tool.
12 |
13 | Technically, we hook the selected functions using Pin, and redirect the execution flow to the
14 | selected Python function. The XML config allows you to specify when you want to hook the function
15 | call (for instance, before the function, after, etc.).
16 |
17 | # Example
18 | Configuration for Pidgin, we want to intercept log the SSL traffic:
19 |
20 |
21 |
22 | purple_ssl_read
23 |
24 |
25 | gsc
26 | int
27 |
28 |
29 | data
30 | char *
31 |
32 |
33 | len
34 | int
35 |
36 |
37 | int
38 |
39 |
40 |
41 |
42 |
43 | purple_ssl_read -- BeforeCall
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | purple_ssl_read -- AfterCall
53 |
54 |
55 |
56 |
57 |
58 |
59 | In this case, we decide to intercept all calls to `purple_ssl_read_wrapper`, and redirect them
60 | to our logging function `log` implemented in `sample.py`.
61 |
62 | This logging function `log` is called from the Pin tool, and the parameters will be passed to it:
63 |
64 | # ... helpers functions for ctype available in the Python script
65 | # in the example
66 | def log(a_dict):
67 | if a_dict["@callMode"] == "beforeCall":
68 | if a_dict["@funcName"] == "purple_ssl_read":
69 | data = ''
70 | gsc = length = -1
71 | if a_dict.has_key("gsc"):
72 | gsc = readInt(a_dict["gsc"])
73 | if a_dict.has_key("data"):
74 | data = readStr(a_dict["data"])
75 | if a_dict.has_key("len"):
76 | length = readInt(a_dict["len"])
77 | print length, data.size()
78 | # Build & hack on it
79 | Using `scons`, or just tweak the `Makefile`!
80 |
81 | # Links
82 | - [Pin](http://www.pintool.org/), for dynamic instrumentation of binaries
83 |
--------------------------------------------------------------------------------
/SConstruct:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | __normalize_path = lambda x: os.path.abspath(x)
5 |
6 | def good_ext(fext, l=None):
7 | return fext.lower() in l if l else False
8 |
9 | def scandir(directory, files, l_ext, ignore=None):
10 | names = os.listdir(directory)
11 | for name in names:
12 | if ignore and name in ignore:
13 | continue
14 | srcname = __normalize_path(os.path.join(directory, name))
15 | try:
16 | if os.path.isdir(srcname):
17 | scandir(srcname, files, l_ext, ignore)
18 | elif os.path.isfile(srcname) and good_ext(srcname[srcname.rfind('.') + 1:], l_ext):
19 | if srcname not in files:
20 | files.append(srcname)
21 | except IOError, error:
22 | continue
23 |
24 | def SelectBuildDir(build_dir, platform=None):
25 | # if no platform is specified, then default to sys.platform
26 | if not(platform):
27 | platform = sys.platform
28 | print "Looking for build directory for platform '%s'" % platform
29 | # setup where we start looking at first
30 | test_dir = os.path.join(build_dir, platform)
31 | default_dir = os.path.join(build_dir, 'default')
32 |
33 | # we look for a directory named exactly after the
34 | # platform so that very specific builds can be done
35 | if os.path.exists(test_dir):
36 | # make sure it is a directory
37 | target_dir = test_dir
38 | print "Found directory %s, will build there" % target_dir
39 | return target_dir
40 |
41 |
42 | lib_search_path = ['/lib','/usr/lib','/usr/local/lib']
43 | include_search_path = ['/usr/include', '/usr/local/include','#src']
44 |
45 | ## These are our source files
46 | sources = []
47 | ignored_files = []
48 | if sys.platform in ('darwin', 'win32'):
49 | ignored_files = ["pythonprobe.cpp"]
50 |
51 | scandir('./src', sources, ["cpp"], ignored_files)
52 |
53 | # Build info
54 | source_base_dir = 'src'
55 | build_base_dir = 'build'
56 | target_name = 'pinpy'
57 |
58 | # Setup some of our requirements
59 | env = Environment()
60 |
61 | # setup the include paths where boost::python and Pin
62 | env.Append(CPPPATH=include_search_path)
63 | env.Append(LIBS=['boost_python', 'python', 'xml2'])
64 |
65 | # variables the sub build directories need
66 | Export('env', 'sources', 'target_name')
67 |
68 | # start the build
69 | target_dir = '#' + SelectBuildDir(build_base_dir)
70 | SConscript(os.path.join(target_dir,'SConscript'))
71 |
72 | env.VariantDir(target_dir, source_base_dir, duplicate=0)
73 |
--------------------------------------------------------------------------------
/build/darwin/SConscript:
--------------------------------------------------------------------------------
1 | # import these variables from the parent build script
2 | # this is obivously for testing, pin doesn't work on OSX
3 | Import('env', 'sources', 'target_name')
4 |
5 | BUILD_SHARED = False
6 |
7 | env.Replace(CXX='clang++')
8 | env.Replace(CC='clang++')
9 | env.Replace(CPP='clang++')
10 | env.Replace(LINK='clang++')
11 |
12 | env.Replace(LIBPATH=["/opt/local/lib/", "/opt/local/lib", "/opt/local/Library/Frameworks/Python.framework/Versions/Current/lib"])
13 | env.Replace(CPPPATH=["/opt/local/include/libxml2", "/opt/local/include", "/opt/local/Library/Frameworks/Python.framework/Versions/Current/include/python2.7", "#src"])
14 |
15 | env.Replace(CXXFLAGS="-g -Wall -O2 -fno-strict-aliasing -std=c++98 -fPIC")
16 | env.Replace(LINKFLAGS="-g -Wl,-all_load")
17 |
18 | env.Replace(LIBS=["xml2", "boost_python", "python2.7"])
19 |
20 | if not BUILD_SHARED:
21 | env.Program(target=target_name, source=sources)
22 | else:
23 | env.SharedLibrary(target=target_name, source=sources)
--------------------------------------------------------------------------------
/build/linux2/SConscript:
--------------------------------------------------------------------------------
1 | # import these variables from the parent build script
2 | Import('env', 'sources')
3 | # set this to the path where you installed pin
4 | pin_path = "/opt/pin"
5 |
6 | env.Replace(CXX='g++')
7 | env.Replace(CC='g++')
8 | env.Replace(CPP='g++')
9 | env.Replace(LINK='g++')
10 |
11 | env.Replace(LIBPATH=["/usr/lib/",pin_path+"/Lib/",pin_path+"/ExtLib/",pin_path+"/extras/xed2-intel64/lib",pin_path+"/intel64/lib",pin_path+"/intel64/lib-ext"])
12 | env.Replace(CPPPATH=["#src","#src/pin","#src/python","/usr/include","/usr/include/libxml2","/usr/include/python2.7",pin_path+"/Include",pin_path+"/InstLib",pin_path+"/extras/xed2-intel64/include",pin_path+"/extras/components/include",pin_path+"/source/include",pin_path+"/source/include/gen"])
13 |
14 | env.Replace(CXXFLAGS="-g -Wall -O3 -fno-strict-aliasing -std=c++98 -Wno-unknown-pragmas -fomit-frame-pointer -DBIGARRAY_MULTIPLIER=1 -DUSING_XED -fno-stack-protector -DTARGET_IA32E -DHOST_IA32E -fPIC -DTARGET_LINUX")
15 | env.Replace(LINKFLAGS="-Wl,--hash-style=sysv -shared -Wl,-Bsymbolic -Wl,--version-script="+pin_path+"/source/include/pintool.ver")
16 |
17 | env.Replace(LIBS=["-lpin","-lxed","-ldwarf","-lelf","-ldl","-lpython2.7","-lboost_python","-lxml2"])
18 |
19 | env.Program(target="pinpy", source=sources)
20 | env.SharedLibrary(target="pinpy", source=sources)
21 |
22 | Return("env")
23 |
--------------------------------------------------------------------------------
/build/win32/SConscript:
--------------------------------------------------------------------------------
1 | # import these variables from the parent build script
2 | Import('env', 'sources', 'target_name')
3 | import os
4 | BUILD_SHARED = True
5 |
6 | env = Environment(ENV = {'PATH' : os.environ['PATH']})
7 | env['ENV']['TMP'] = os.environ['TMP']
8 | env.Replace(CXX='cl')
9 | env.Replace(CC='cl')
10 | env.Replace(CPP='cl')
11 | env.Replace(LINK='link')
12 |
13 | # Append lib specifics for windows
14 | env.Replace(LIBPATH=['C:\\Program Files\\boost_1_47\lib', 'C:\\src\\libxml2-2.7.8.win32\\lib', 'C:\\src\\iconv-1.9.2.win32\\lib', 'C:\\src\\pin-2.10\\ia32\\lib', 'C:\\src\\pin-2.10\\ia32\\lib-ext', 'C:\\src\\pin-2.10\\intel64\\lib-ext','C:\\src\\pin-2.10\\extras\\xed2-ia32\\lib', 'C:\\src\\pin-2.10\\extras\\xed2-intel65\\lib', 'C:\\Program Files\\Microsoft Visual Studio 9.0\\VC\\lib', 'C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Lib', 'C:\\Python27\\libs'])
15 |
16 | #C:\\Program Files\\Microsoft Visual Studio 9.0\\VC\\lib', 'C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0A\\Lib'
17 |
18 | # Include specifics for windows
19 | env.Replace(CPPPATH=['C:\\Python27\\include', 'C:\\Program Files\\boost_1_47', 'C:\\src\\libxml2-2.7.8.win32\\include', 'C:\\src\\iconv-1.9.2.win32\\include', 'C:\\src\\pin-2.10\\source\\include', 'C:\\src\\pin-2.10\\source\\include\\gen', 'C:\\src\\pin-2.10\\source\\tools\\InstLib', 'C:\\src\\pin-2.10\\extras\\xed2-ia32\\include', 'C:\\src\\pin-2.10\\extras\\components\\include', 'C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Include', 'C:\\Program Files\\Microsoft Visual Studio 9.0\\VC\\include', '#src'])
20 |
21 | env.Replace(CXXFLAGS=["/MT" ,"/EHs-" ,"/EHa-" ,"/wd4530" ,"/DTARGET_WINDOWS" ,"/DBIGARRAY_MULTIPLIER=1" ,"/DUSING_XED" ,"/DBOOST_PYTHON_STATIC_LIB" ,"/D_CRT_SECURE_NO_DEPRECATE" ,"/D_SECURE_SCL=0" ,"/nologo" ,"/Gy" ,"/O2" , "/DTARGET_IA32" ,"/DHOST_IA32"])
22 |
23 | if BUILD_SHARED:
24 | env.Replace(LINKFLAGS="/EXPORT:main /NOLOGO /INCREMENTAL:NO /MACHINE:x86 /ENTRY:Ptrace_DllMainCRTStartup@12 /BASE:0x55000000")
25 | env.Replace(LIBS=["pin","libxed", "libcpmt","libcmt","pinvm", "kernel32", "ntdll-32", "iconv", "libxml2", "python27", "libboost_python-vc90-mt-s-1_47"])
26 | else:
27 | env.Replace(LIBS=["libxml2"])
28 |
29 | if BUILD_SHARED:
30 | env.SharedLibrary(target=target_name, source=sources)
31 | else:
32 | env.Program(target=target_name, source=sources)
33 |
34 |
--------------------------------------------------------------------------------
/build/win32/iconv.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuroo/pinpy/65f17876caf35651b22679591a17373e6ddae52d/build/win32/iconv.dll
--------------------------------------------------------------------------------
/build/win32/libxml2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuroo/pinpy/65f17876caf35651b22679591a17373e6ddae52d/build/win32/libxml2.dll
--------------------------------------------------------------------------------
/build/win32/pinpy.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuroo/pinpy/65f17876caf35651b22679591a17373e6ddae52d/build/win32/pinpy.dll
--------------------------------------------------------------------------------
/build/win32/pinpy.dll.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/build/win32/pinpy.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuroo/pinpy/65f17876caf35651b22679591a17373e6ddae52d/build/win32/pinpy.lib
--------------------------------------------------------------------------------
/build/win32/pinvm.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuroo/pinpy/65f17876caf35651b22679591a17373e6ddae52d/build/win32/pinvm.dll
--------------------------------------------------------------------------------
/build/win32/python27.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuroo/pinpy/65f17876caf35651b22679591a17373e6ddae52d/build/win32/python27.dll
--------------------------------------------------------------------------------
/build/win32/zlib1.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuroo/pinpy/65f17876caf35651b22679591a17373e6ddae52d/build/win32/zlib1.dll
--------------------------------------------------------------------------------
/examples/sample.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | // gcc -g -O2 sample.c -o sample
7 | int main(int argc, char *argv[]) {
8 | char *buffer = NULL;
9 | size_t length = 0;
10 |
11 | srand(time(0));
12 | length = rand() % 4096 + 20;
13 |
14 | printf ("Start of the sample application...\n");
15 | printf ("Allocate %ld\n", length);
16 |
17 | buffer = (char *)malloc(length);
18 | if (buffer) {
19 | strcpy(buffer, "Hello World!\0");
20 |
21 | printf("Buffer contains: %s\n", buffer);
22 |
23 | printf("Free buffer\n");
24 | free(buffer);
25 | buffer = NULL;
26 | }
27 | return 0;
28 | }
--------------------------------------------------------------------------------
/examples/sample.py:
--------------------------------------------------------------------------------
1 | """
2 | PinPy -- Shake your hooks with some Python!
3 | by Romain Gaucher - http://rgaucher.info
4 |
5 | Copyright (c) 2011-2012 Romain Gaucher @rgaucher
6 | Haris Andrianakis @tl0gic
7 |
8 | Licensed under the Apache License, Version 2.0 (the "License");
9 | you may not use this file except in compliance with the License.
10 | You may obtain a copy of the License at
11 |
12 | http://www.apache.org/licenses/LICENSE-2.0
13 |
14 | Unless required by applicable law or agreed to in writing, software
15 | distributed under the License is distributed on an "AS IS" BASIS,
16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | See the License for the specific language governing permissions and
18 | limitations under the License.
19 | """
20 | import os, sys
21 | import ctypes
22 |
23 | def writeInt(address, integer):
24 | ''' Write an "integer" at "address" '''
25 | p = ctypes.c_void_p(address)
26 | i = ctypes.cast(p, ctypes.POINTER(ctypes.c_int))
27 | i[0] = integer
28 |
29 | def writeStr(address, string):
30 | ''' Write the contents of "string" to the buffer at "address" '''
31 | p = ctypes.c_void_p(address)
32 | void_ptr = ctypes.cast(p, ctypes.POINTER(ctypes.c_void_p))
33 | ctypes.memmove(void_ptr.contents.value, string, len(string))
34 |
35 | def replaceStr(address, string):
36 | ''' Replace the char* pointer at "address" with our string's address '''
37 | p = ctypes.c_void_p(address)
38 | char_ptr = ctypes.cast(p, ctypes.POINTER(ctypes.c_char_p))
39 | char_ptr[0] = string
40 |
41 | def readInt(address):
42 | ''' Read an integer from "address" '''
43 | p = ctypes.c_void_p(address)
44 | i = ctypes.cast(p, ctypes.POINTER(ctypes.c_int))
45 | return i.contents.value
46 |
47 | def readStr(address):
48 | ''' Read the "string" at "address" '''
49 | p = ctypes.c_void_p(address)
50 | char_ptr = ctypes.cast(p, ctypes.POINTER(ctypes.c_char_p))
51 | return char_ptr.contents.value
52 |
53 | def simpleHello(a_dict):
54 | # Handlers for beforeCall
55 | if a_dict["@callMode"] == "beforeCall":
56 |
57 | if a_dict["@funcName"] == "purple_ssl_read":
58 | data = 'unknown'
59 | gsc = length = -1
60 |
61 | if a_dict.has_key("gsc"):
62 | gsc = readInt(a_dict["gsc"])
63 |
64 | if a_dict.has_key("data"):
65 | data = readStr(a_dict["data"])
66 |
67 | if a_dict.has_key("len"):
68 | length = readInt(a_dict["len"])
69 |
70 | print "purple_ssl_read(gsc=" + str(hex(gsc)) + ", data=" + data + ", length=" + str(length) + ")"
71 |
72 | # Handler for wpurple_send beforeCall
73 | if a_dict["@funcName"] == "purple_ssl_write":
74 | data = 'unknown'
75 | gsc = length = -1
76 |
77 | if a_dict.has_key("gsc"):
78 | gsc = readInt(a_dict["gsc"])
79 |
80 | if a_dict.has_key("data"):
81 | data = readStr(a_dict["data"])
82 |
83 | if a_dict.has_key("len"):
84 | length = readInt(a_dict["len"])
85 |
86 | print "purple_ssl_write(gsc=" + str(hex(gsc)) + ", data=" + data + ", length=" + str(length) + ")"
87 |
88 | idx = data.find('')
89 | if idx > 0:
90 | part1 = data[:idx+6]
91 | part2 = data[idx+11:]
92 | newdata = part1+"pwned"+part2
93 | replaceStr(a_dict["data"], newdata)
94 | print "modified purple_ssl_write(gsc=" + str(hex(gsc)) + ", data=" + newdata + ", length=" + str(length) + ")"
95 |
96 | # Handler for sleep beforeCall
97 | if a_dict["@funcName"] == "sleep":
98 | if a_dict.has_key("seconds"):
99 | print "sleep("+str(readInt(a_dict["seconds"]))+")",
100 | else:
101 | print 'python script- error called sleep but arg "seconds" is not set in dict'
102 |
103 | # Handler for myfunction2 beforeCall
104 | # Example usage of replaceStr and writeStr.
105 | # Make sure there is enough space in the buffer you are overwritting
106 | # when using writeStr to hold your new string. Also you cannot (obviously) write
107 | # into constant strings :p
108 | if a_dict["@funcName"] == "myfunction2":
109 | if a_dict.has_key("message"):
110 | print 'beforeCall for myfunction2'
111 | print "message is", readStr(a_dict["message"])
112 |
113 | new_message = "this is a new message"
114 | replaceStr(a_dict["message"], new_message)
115 | # writeStr(a_dict["message"], new_message)
116 |
117 | # Handlers for afterCall
118 | elif a_dict["@callMode"] == "afterCall":
119 |
120 | # Handler for wpurple_send afterCall
121 | if a_dict["@funcName"] == "purple_ssl_write":
122 | if a_dict.has_key("ret"):
123 | print "purple_ssl_write- ret:", readInt(a_dict["ret"])
124 | else:
125 | print "- ret: unknown"
126 |
127 | # Handler for sleep afterCall
128 | if a_dict["@funcName"] == "sleep":
129 | if a_dict.has_key("ret"):
130 | print "- retVal:", readInt(a_dict["ret"])
131 | else:
132 | print 'python script- error we are in afterCall and dont have access to the retVal'
133 |
134 |
--------------------------------------------------------------------------------
/examples/sample.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 | purple_ssl_read
10 |
11 |
12 | gsc
13 | int
14 |
15 |
16 | data
17 | char *
18 |
19 |
20 | len
21 | int
22 |
23 |
24 | int
25 |
26 |
27 |
28 |
29 |
30 |
31 | purple_ssl_read -- BeforeCall
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | purple_ssl_read -- AfterCall
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | purple_ssl_write
51 |
52 |
53 | gsc
54 | int
55 |
56 |
57 | data
58 | char *
59 |
60 |
61 | len
62 | int
63 |
64 |
65 | int
66 |
67 |
68 |
69 |
70 |
71 |
72 | purple_ssl_write -- BeforeCall
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | purple_ssl_write -- AfterCall
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/examples/test-program.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int myfunction(int a_int, char a_char, short a_short, long a_long, long long a_long_long)
5 | {
6 | printf("in myfunction\n");
7 | return 1;
8 | }
9 |
10 | void myfunction2(char *message)
11 | {
12 | printf("c program: the address of message in call is %p\n", message);
13 | printf("c program: message = %s\n", message);
14 | }
15 |
16 | int main(int argc, char **argv)
17 | {
18 | char message[100];
19 | memset(message, 0, 100);
20 | strncpy(message, "koko lala one two", 99);
21 |
22 | int ret;
23 | ret = sleep(1);
24 | printf("c program: sleep returned %d\n", ret);
25 | printf("c program: message address before call is %p\n", message);
26 | myfunction2(message);
27 | sleep(2);
28 | printf("c program: sleep returned %d\n", ret);
29 | sleep(3);
30 | printf("c program: sleep returned %d\n", ret);
31 | return 0;
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/libs/pinpylibs.py:
--------------------------------------------------------------------------------
1 | """
2 | PinPy -- Shake your hooks with some Python!
3 | by Romain Gaucher - http://rgaucher.info
4 |
5 | Copyright (c) 2011-2012 Romain Gaucher @rgaucher
6 | Haris Andrianakis @tl0gic
7 |
8 | Licensed under the Apache License, Version 2.0 (the "License");
9 | you may not use this file except in compliance with the License.
10 | You may obtain a copy of the License at
11 |
12 | http://www.apache.org/licenses/LICENSE-2.0
13 |
14 | Unless required by applicable law or agreed to in writing, software
15 | distributed under the License is distributed on an "AS IS" BASIS,
16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | See the License for the specific language governing permissions and
18 | limitations under the License.
19 | """
20 | import os, sys
21 |
22 | isiterable = lambda obj: isinstance(obj, basestring) or getattr(obj, '__iter__', False)
23 | __normalize_argmt = lambda x: ''.join(x.lower().split())
24 | __normalize_paths = lambda x: [os.path.abspath(of) for of in x]
25 | __normalize_path = lambda x: os.path.abspath(x)
26 |
27 | # Define several decorators for fast processing, and arguments checking
28 | class Memoized(object):
29 | def __init__(self, func):
30 | self.func = func
31 | self.memoized = {}
32 | self.method_cache = {}
33 | def __call__(self, *args):
34 | return self.cache_get(self.memoized, args, lambda: self.func(*args))
35 | def __get__(self, obj, objtype):
36 | return self.cache_get(self.method_cache, obj, lambda: self.__class__(functools.partial(self.func, obj)))
37 | def cache_get(self, cache, key, func):
38 | try:
39 | return cache[key]
40 | except KeyError:
41 | cache[key] = func()
42 | return cache[key]
43 |
44 | class NonNullParameters(object):
45 | def __init__(self, func):
46 | self.func = func
47 | def __call__(self, *args):
48 | if isiterable(args):
49 | for e in args:
50 | if e is None:
51 | return None
52 | else:
53 | if args is None:
54 | return None
55 | return self.func(*args)
--------------------------------------------------------------------------------
/src/knowledge/callgraph.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PinPy -- Shake your hooks with some Python!
3 | by Romain Gaucher - http://rgaucher.info
4 |
5 | Copyright (c) 2011-2012 Romain Gaucher @rgaucher
6 | Haris Andrianakis @tl0gic
7 |
8 | Licensed under the Apache License, Version 2.0 (the "License");
9 | you may not use this file except in compliance with the License.
10 | You may obtain a copy of the License at
11 |
12 | http://www.apache.org/licenses/LICENSE-2.0
13 |
14 | Unless required by applicable law or agreed to in writing, software
15 | distributed under the License is distributed on an "AS IS" BASIS,
16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | See the License for the specific language governing permissions and
18 | limitations under the License.
19 | */
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #include "knowledge/callgraph.h"
32 | using namespace boost;
33 | using namespace std;
34 | using namespace knowledge;
35 |
36 | ofstream out("graph-internal.txt");
37 |
38 | CallGraphNodeId CallGraph::addNode(const CallGraphNode& n) {
39 | CallGraphNodeId nId = getNode(n.address);
40 | if (nId == Graph::null_vertex()) {
41 | CallGraphNodeId nId2 = add_vertex(graph);
42 | // vertex_info[reinterpret_cast(nId2)] = n;
43 | //vertexCache[n.address] = nId2;
44 | out << "Add new vertex: " << nId2 << " address =" << n.address << " (V=" << num_vertices(graph) << ")" << endl;
45 | return nId2;
46 | }
47 | else {
48 | out << "Existing vertex for address = " << " id=" << dec << nId << endl;
49 | }
50 | return nId;
51 | }
52 |
53 | CallGraphNodeId CallGraph::getNode(unsigned int address) {
54 | if (vertexCache.size() < 1)
55 | return Graph::null_vertex();
56 |
57 | /*
58 | map::iterator cacheIterator = vertexCache.find(address);
59 | if (cacheIterator != vertexCache.end())
60 | return cacheIterator->second != Graph::null_vertex() ? cacheIterator->second : Graph::null_vertex();
61 | */
62 | return Graph::null_vertex();
63 | }
64 |
65 | bool CallGraph::addEdgeNodeId(const CallGraphNodeId& n1, const CallGraphNodeId& n2) {
66 | if (n1 == Graph::null_vertex() || n2 == Graph::null_vertex())
67 | return false;
68 | pair edgePair = edge(n1, n2, graph);
69 | if (!edgePair.second) {
70 | // Need to add the edge
71 | pair e = add_edge(n1, n2, graph);
72 | out << "new edge- " << e.first << " (E=" << dec << num_edges(graph) << ")" << flush << endl;
73 | if (e.second) {
74 | //graph[e.first].flow = 1;
75 | }
76 | return e.second;
77 | }
78 | else {
79 | //graph[edgePair.first].flow += 1;
80 | out << "existing edge- " << edgePair.first << " (E=" << dec << num_edges(graph) << ")" << endl;
81 | }
82 | return edgePair.second;
83 | }
84 |
85 |
86 | bool CallGraph::addEdge(unsigned int a1, unsigned int a2) {
87 | // Get the nodes by address, then add an edge
88 | CallGraphNodeId n1 = getNode(a1);
89 | CallGraphNodeId n2 = getNode(a2);
90 |
91 | return addEdgeNodeId(n1, n2);
92 | }
93 | /*
94 | void CallGraph::write(const std::string& fname) {
95 | //boost::dynamic_properties dp;
96 | //dp.property("id", get(name, graph));
97 |
98 | ofstream out(fname.c_str());
99 | write_graphviz(out, graph);
100 |
101 | }
102 | */
103 |
104 | CallGraph::~CallGraph() {
105 | out << "destruct the callgraph" << endl << flush;
106 | out << "############################################" << flush;
107 | }
108 |
109 |
--------------------------------------------------------------------------------
/src/knowledge/callgraph.h:
--------------------------------------------------------------------------------
1 | /*
2 | PinPy -- Shake your hooks with some Python!
3 | by Romain Gaucher - http://rgaucher.info
4 |
5 | Copyright (c) 2011-2012 Romain Gaucher @rgaucher
6 | Haris Andrianakis @tl0gic
7 |
8 | Licensed under the Apache License, Version 2.0 (the "License");
9 | you may not use this file except in compliance with the License.
10 | You may obtain a copy of the License at
11 |
12 | http://www.apache.org/licenses/LICENSE-2.0
13 |
14 | Unless required by applicable law or agreed to in writing, software
15 | distributed under the License is distributed on an "AS IS" BASIS,
16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | See the License for the specific language governing permissions and
18 | limitations under the License.
19 | */
20 | #ifndef CALLGRAPH_H
21 | #define CALLGRAPH_H
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | namespace knowledge {
33 |
34 | struct CallGraphNode {
35 | unsigned int address;
36 | std::string name;
37 |
38 | CallGraphNode(unsigned int a=0, const std::string& n="")
39 | : address(a), name(n)
40 | {}
41 | };
42 |
43 | struct CallGraphEdge {
44 | unsigned int flow;
45 | };
46 |
47 | typedef boost::adjacency_list Graph;
48 | //typedef boost::adjacency_matrix Graph;
49 | typedef boost::graph_traits::vertex_descriptor CallGraphNodeId;
50 | typedef boost::graph_traits::edge_descriptor CallGraphEdgeId;
51 | typedef boost::graph_traits::vertex_iterator CallGraphNodeIterator;
52 |
53 | // We assume that the vertex_descriptor is an unsigned int, since it should be
54 | // the address in the linked-list.
55 |
56 | class CallGraph {
57 | std::map vertexCache;
58 | std::map vertex_info;
59 | std::map edge_info;
60 |
61 | Graph graph;
62 |
63 | public:
64 | CallGraph() {};
65 | CallGraph(const CallGraph& c) {
66 | *this = c;
67 | }
68 | CallGraph& operator=(const CallGraph& c) {
69 | vertexCache = c.vertexCache;
70 | vertex_info = c.vertex_info;
71 | edge_info = c.edge_info;
72 | graph = c.graph;
73 | return *this;
74 | }
75 |
76 | CallGraphNodeId getNode(unsigned int address);
77 | CallGraphNodeId addNode(const CallGraphNode& n);
78 |
79 | bool addEdgeNodeId(const CallGraphNodeId&, const CallGraphNodeId&);
80 | bool addEdge(unsigned int, unsigned int);
81 |
82 | unsigned int count_nodes() const {
83 | return num_vertices(graph);
84 | }
85 |
86 | unsigned int count_edges() const {
87 | return num_edges(graph);
88 | }
89 |
90 | //void write(const std::string& fname);
91 |
92 |
93 |
94 | ~CallGraph();
95 | };
96 |
97 |
98 | }
99 |
100 | #endif
101 |
--------------------------------------------------------------------------------
/src/knowledge/knowledge.h:
--------------------------------------------------------------------------------
1 | /*
2 | PinPy -- Shake your hooks with some Python!
3 | by Romain Gaucher - http://rgaucher.info
4 |
5 | Copyright (c) 2011-2012 Romain Gaucher @rgaucher
6 | Haris Andrianakis @tl0gic
7 |
8 | Licensed under the Apache License, Version 2.0 (the "License");
9 | you may not use this file except in compliance with the License.
10 | You may obtain a copy of the License at
11 |
12 | http://www.apache.org/licenses/LICENSE-2.0
13 |
14 | Unless required by applicable law or agreed to in writing, software
15 | distributed under the License is distributed on an "AS IS" BASIS,
16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | See the License for the specific language governing permissions and
18 | limitations under the License.
19 | */
20 | #ifndef KNOWLEDGE_H
21 | #define KNOWLEDGE_H
22 |
23 | #include "knowledge/callgraph.h"
24 |
25 | namespace knowledge {
26 |
27 | struct Knowledge {
28 |
29 | CallGraph callGraph;
30 | //ValueStore valueStore;
31 |
32 | Knowledge(){}
33 | ~Knowledge(){}
34 |
35 | private:
36 | Knowledge(const Knowledge&) {}
37 | Knowledge& operator=(const Knowledge&) {
38 | return *this;
39 | }
40 | };
41 |
42 |
43 | }
44 |
45 | #endif
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | PinPy -- Shake your hooks with some Python!
3 | by Romain Gaucher - http://rgaucher.info
4 |
5 | Copyright (c) 2011-2012 Romain Gaucher @rgaucher
6 | Haris Andrianakis @tl0gic
7 |
8 | Licensed under the Apache License, Version 2.0 (the "License");
9 | you may not use this file except in compliance with the License.
10 | You may obtain a copy of the License at
11 |
12 | http://www.apache.org/licenses/LICENSE-2.0
13 |
14 | Unless required by applicable law or agreed to in writing, software
15 | distributed under the License is distributed on an "AS IS" BASIS,
16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | See the License for the specific language governing permissions and
18 | limitations under the License.
19 | */
20 | #include "Python.h"
21 | #include "pin.H"
22 |
23 | #include
24 | #include
25 | #include
26 | #include