idb 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +65 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/idb +5 -0
- data/idb.gemspec +41 -0
- data/lib/LICENSE +20 -0
- data/lib/README.md +54 -0
- data/lib/config/.dummy +0 -0
- data/lib/config/settings.yml +8 -0
- data/lib/gui/app_binary_tab_widget.rb +45 -0
- data/lib/gui/app_details_group_box.rb +213 -0
- data/lib/gui/app_list_dialog.rb +67 -0
- data/lib/gui/app_list_widget_item.rb +9 -0
- data/lib/gui/binary_strings_widget.rb +33 -0
- data/lib/gui/browse_filesystem_widget.rb +4 -0
- data/lib/gui/ca_manager_dialog.rb +137 -0
- data/lib/gui/cache_db_widget.rb +61 -0
- data/lib/gui/certificate_item.rb +5 -0
- data/lib/gui/console_widget.rb +163 -0
- data/lib/gui/cycript_console_widget.rb +68 -0
- data/lib/gui/cycript_thread.rb +81 -0
- data/lib/gui/device_info_group_box.rb +55 -0
- data/lib/gui/device_status_dialog.rb +351 -0
- data/lib/gui/file_system_events_widget.rb +4 -0
- data/lib/gui/fs_viewer_tab_widget.rb +245 -0
- data/lib/gui/i_device_syslog_thread.rb +47 -0
- data/lib/gui/images/check.png +0 -0
- data/lib/gui/images/folder.ico +0 -0
- data/lib/gui/images/iphone.ico +0 -0
- data/lib/gui/images/screenshot.png +0 -0
- data/lib/gui/key_chain_widget.rb +86 -0
- data/lib/gui/local_storage_tab_widget.rb +37 -0
- data/lib/gui/log_plain_text_edit.rb +18 -0
- data/lib/gui/log_widget.rb +71 -0
- data/lib/gui/main_tab_widget.rb +179 -0
- data/lib/gui/pasteboard_monitor_widget.rb +116 -0
- data/lib/gui/path_list_widget_item.rb +5 -0
- data/lib/gui/pb_watcher_thread.rb +63 -0
- data/lib/gui/plist_file_widget.rb +66 -0
- data/lib/gui/qt_ruby_variant.rb +16 -0
- data/lib/gui/screenshot_wizard.rb +169 -0
- data/lib/gui/settings_dialog.rb +69 -0
- data/lib/gui/settings_tab_widget.rb +149 -0
- data/lib/gui/shared_libraries_widget.rb +47 -0
- data/lib/gui/snoop_it_fs_events_widget.rb +150 -0
- data/lib/gui/snoop_it_keychain_widget.rb +172 -0
- data/lib/gui/snoop_it_sensitive_api_widget.rb +128 -0
- data/lib/gui/snoop_it_tab_widget.rb +27 -0
- data/lib/gui/snoop_it_update_thread.rb +48 -0
- data/lib/gui/sqlite_widget.rb +73 -0
- data/lib/gui/ssh_port_forward_tab_widget.rb +209 -0
- data/lib/gui/tool_widget.rb +94 -0
- data/lib/gui/url_handler_widget.rb +26 -0
- data/lib/gui/url_scheme_fuzz_widget.rb +103 -0
- data/lib/gui/url_scheme_widget.rb +60 -0
- data/lib/gui/weak_class_dump_widget.rb +89 -0
- data/lib/helper/ssh_port_forwarder.rb +72 -0
- data/lib/idb.rb +295 -0
- data/lib/idb/version.rb +3 -0
- data/lib/lib/CgBI.rb +153 -0
- data/lib/lib/abstract_device.rb +31 -0
- data/lib/lib/app.rb +286 -0
- data/lib/lib/app_binary.rb +57 -0
- data/lib/lib/ca_interface.rb +151 -0
- data/lib/lib/configuration.rb +0 -0
- data/lib/lib/console_launcher.rb +24 -0
- data/lib/lib/device.rb +438 -0
- data/lib/lib/device_ca_interface.rb +36 -0
- data/lib/lib/host_file_wrapper.rb +27 -0
- data/lib/lib/i_device_diagnostics_wrapper.rb +90 -0
- data/lib/lib/keychain_plist_parser.rb +15 -0
- data/lib/lib/local_operations.rb +67 -0
- data/lib/lib/otool_wrapper.rb +116 -0
- data/lib/lib/plist_util.rb +72 -0
- data/lib/lib/qt_thread_fix.rb +29 -0
- data/lib/lib/rsync_git_manager.rb +81 -0
- data/lib/lib/screen_shot_util.rb +59 -0
- data/lib/lib/settings.rb +67 -0
- data/lib/lib/simulator.rb +60 -0
- data/lib/lib/simulator_ca_interface.rb +16 -0
- data/lib/lib/snoop_it_wrapper.rb +80 -0
- data/lib/lib/ssh_operations.rb +136 -0
- data/lib/lib/ssh_port_forwarder.rb +43 -0
- data/lib/lib/tools.rb +11 -0
- data/lib/lib/url_scheme_fuzzer.rb +98 -0
- data/lib/lib/usb_muxd_wrapper.rb +32 -0
- data/lib/lib/weak_class_dump_wrapper.rb +62 -0
- data/lib/utils/dumpdecrypted/README +4 -0
- data/lib/utils/dumpdecrypted/dumpdecrypted_armv6.dylib +0 -0
- data/lib/utils/dumpdecrypted/dumpdecrypted_armv7.dylib +0 -0
- data/lib/utils/ios-ssl-kill-switch/com.isecpartners.nabla.sslkillswitch_v0.5-iOS_6.1.deb +0 -0
- data/lib/utils/keychain_dump/README +2 -0
- data/lib/utils/keychain_dump/keychain_dump +0 -0
- data/lib/utils/pbwatcher/pbwatcher +0 -0
- data/lib/utils/pcviewer/protectionclassviewer +0 -0
- data/lib/utils/weak_class_dump/README +5 -0
- data/lib/utils/weak_class_dump/weak_classdump.cy +726 -0
- metadata +412 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
require 'log4r'
|
3
|
+
|
4
|
+
|
5
|
+
module Idb
|
6
|
+
class SSHPortForwarder
|
7
|
+
|
8
|
+
def initialize username, password, hostname, port
|
9
|
+
# initialize log
|
10
|
+
@log = Log4r::Logger.new 'port_forward'
|
11
|
+
outputter = Log4r::Outputter.stdout
|
12
|
+
outputter.formatter = Log4r::PatternFormatter.new(:pattern => "[%l] %d :: %c :: %m")
|
13
|
+
|
14
|
+
@log.outputters = [ outputter ]
|
15
|
+
|
16
|
+
@log.info 'Establishing SSH port forwarding...'
|
17
|
+
@ssh = Net::SSH.start hostname, username, :password => password, :port => port
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_local_forward local_port, remote_host, remote_port
|
21
|
+
@log.info " - Forwarding local:#{local_port} -> #{remote_host}:#{remote_port}"
|
22
|
+
@ssh.forward.local local_port, remote_host, remote_port
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_remote_forward remote_port, local_host, local_port
|
26
|
+
@log.info " - Forwarding remote:#{remote_port} -> #{local_host}:#{local_port}"
|
27
|
+
@ssh.forward.remote_to local_port, local_host, remote_port
|
28
|
+
end
|
29
|
+
|
30
|
+
def start
|
31
|
+
@ssh.loop {
|
32
|
+
true
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop
|
37
|
+
$log.info "Closing SSH connection."
|
38
|
+
@ssh.close
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/lib/lib/tools.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# source: https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
|
2
|
+
def which(cmd)
|
3
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
4
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
5
|
+
exts.each { |ext|
|
6
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
7
|
+
return exe if File.executable? exe
|
8
|
+
}
|
9
|
+
end
|
10
|
+
return nil
|
11
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Idb
|
4
|
+
class URLSchemeFuzzer
|
5
|
+
def initialize
|
6
|
+
@crash_report_folder = "/var/mobile/Library/Logs/CrashReporter"
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def default_fuzz_strings
|
12
|
+
fuzz_inputs = [
|
13
|
+
"A" * 10,
|
14
|
+
"A" * 101,
|
15
|
+
"A" * 1001,
|
16
|
+
"\x0",
|
17
|
+
"'",
|
18
|
+
"%",
|
19
|
+
"%n",
|
20
|
+
"%@" * 20,
|
21
|
+
"%n%d" * 20,
|
22
|
+
"%s%p%x%d",
|
23
|
+
"%x%x%x%x",
|
24
|
+
"%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%",
|
25
|
+
# "100",
|
26
|
+
# "1000",
|
27
|
+
# "3fffffff",
|
28
|
+
# "7ffffffe",
|
29
|
+
# "7fffffff",
|
30
|
+
# "80000000",
|
31
|
+
# "fffffffe",
|
32
|
+
# "ffffffff",
|
33
|
+
# "10000",
|
34
|
+
# "100000",
|
35
|
+
"0",
|
36
|
+
"-1",
|
37
|
+
"1",
|
38
|
+
]
|
39
|
+
fuzz_inputs
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete_old_reports
|
43
|
+
#remove old crash reports
|
44
|
+
crashes = $device.ops.dir_glob @crash_report_folder, "*"
|
45
|
+
crashes.each { |x|
|
46
|
+
if x.include? $selected_app.binary_name
|
47
|
+
$log.info "Deleting old log #{x}"
|
48
|
+
$device.ops.execute ("rm -f '#{x}' ")
|
49
|
+
end
|
50
|
+
}
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def generate_inputs url, fuzz_inputs
|
56
|
+
inputs = Array.new
|
57
|
+
|
58
|
+
# count fuzz locations
|
59
|
+
locs = url.scan(/\$@\$/)
|
60
|
+
|
61
|
+
# generate input combinations
|
62
|
+
combs = fuzz_inputs.combination(locs.size).to_a
|
63
|
+
|
64
|
+
# generate test instance for each combination
|
65
|
+
for c in combs do
|
66
|
+
inputs << url.dup.gsub!(/\$@\$/) { |x|
|
67
|
+
x = URI::encode(c.pop) }
|
68
|
+
end
|
69
|
+
|
70
|
+
return inputs
|
71
|
+
end
|
72
|
+
|
73
|
+
def execute url
|
74
|
+
$log.info "Fuzzing: #{url}"
|
75
|
+
$device.open_url url
|
76
|
+
sleep 2
|
77
|
+
|
78
|
+
$log.info "Killing processes names #{$selected_app.binary_name}"
|
79
|
+
$device.kill_by_name $selected_app.binary_name
|
80
|
+
|
81
|
+
crashed?
|
82
|
+
end
|
83
|
+
|
84
|
+
def crashed?
|
85
|
+
crashes = $device.ops.dir_glob @crash_report_folder, "*"
|
86
|
+
crashed = false
|
87
|
+
crashes.each { |x|
|
88
|
+
if x.include? $selected_app.binary_name
|
89
|
+
crashed = true
|
90
|
+
end
|
91
|
+
}
|
92
|
+
crashed
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'awesome_print'
|
3
|
+
|
4
|
+
module Idb
|
5
|
+
class USBMuxdWrapper
|
6
|
+
def initialize
|
7
|
+
@proxy_pids = Array.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def find_available_port
|
11
|
+
x = TCPServer.new("127.0.0.1",0)
|
12
|
+
@port= x.addr[1]
|
13
|
+
x.close
|
14
|
+
@port
|
15
|
+
end
|
16
|
+
|
17
|
+
def proxy local_port, remote_port
|
18
|
+
$log.info "Launching SSH proxy on port #{local_port}"
|
19
|
+
@proxy_pids << Process.spawn("iproxy #{local_port} #{remote_port}")
|
20
|
+
@proxy_pids.last
|
21
|
+
end
|
22
|
+
|
23
|
+
def stop_all
|
24
|
+
@proxy_pids.each { |pid|
|
25
|
+
$log.info "Terminating proxy with pid #{pid}"
|
26
|
+
Process.kill("INT", pid)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Idb
|
2
|
+
class WeakClassDumpWrapper
|
3
|
+
|
4
|
+
def initialize local_header_dir
|
5
|
+
|
6
|
+
@remote_header_dir_base = "/tmp/weak_class_dump_"
|
7
|
+
@remote_header_dir = @remote_header_dir_base + $selected_app.uuid
|
8
|
+
|
9
|
+
@local_header_dir = local_header_dir
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute_cycript
|
14
|
+
unless $device.cycript_installed?
|
15
|
+
$log.error "Cycript not found, aborting."
|
16
|
+
return
|
17
|
+
end
|
18
|
+
|
19
|
+
# ensure cycript script is installed.
|
20
|
+
# originally from: https://github.com/limneos/weak_classdump
|
21
|
+
|
22
|
+
wc_file = "/var/root/weak_classdump.cy"
|
23
|
+
unless $device.ops.file_exists? wc_file
|
24
|
+
$log.info "weak_classdump not found, Installing onto device."
|
25
|
+
$device.ops.upload("utils/weak_class_dump/weak_classdump.cy", wc_file)
|
26
|
+
end
|
27
|
+
|
28
|
+
local_instructions_file = "#{$tmp_path}/weak_classdump_instructions.cy"
|
29
|
+
remote_instructions_file = "/var/root/weak_classdump_instructions.cy"
|
30
|
+
File.open(local_instructions_file,"w") { |x|
|
31
|
+
x.puts("weak_classdump_bundle([NSBundle mainBundle],\"#{@remote_header_dir}\")")
|
32
|
+
}
|
33
|
+
|
34
|
+
$device.ops.upload local_instructions_file, remote_instructions_file
|
35
|
+
|
36
|
+
$log.info "Launching app..."
|
37
|
+
$selected_app.launch
|
38
|
+
|
39
|
+
cmd = "cycript -p '#{$selected_app.binary_name}' #{wc_file}"
|
40
|
+
$log.info "Injecting: #{cmd}"
|
41
|
+
$device.ops.execute cmd
|
42
|
+
|
43
|
+
$log.info "Running cycript using weak_classdump."
|
44
|
+
cmd = "cycript -p '#{$selected_app.binary_name}' #{remote_instructions_file}"
|
45
|
+
$log.info "Running: #{cmd}"
|
46
|
+
$device.ops.execute cmd
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_header_files
|
51
|
+
Dir.entries(@local_header_dir).reject{|entry| entry == "." || entry == ".."}
|
52
|
+
end
|
53
|
+
|
54
|
+
def pull_header_files
|
55
|
+
$log.info "Downloading header files from #{@remote_header_dir} to #{@local_header_dir}"
|
56
|
+
$device.ops.download_recursive(@remote_header_dir, @local_header_dir)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,726 @@
|
|
1
|
+
|
2
|
+
function commonTypes(type){
|
3
|
+
|
4
|
+
isPointer=NO;
|
5
|
+
if ([type containsSubstring:@"^"]){
|
6
|
+
isPointer=YES;
|
7
|
+
type=[type stringByReplacingOccurrencesOfString:@"^" withString:""];
|
8
|
+
}
|
9
|
+
|
10
|
+
switch (type.toString()){
|
11
|
+
|
12
|
+
case "d": type = "double"; break;
|
13
|
+
case "i": type = "int"; break;
|
14
|
+
case "f": type = "float"; break;
|
15
|
+
case "c": type = "BOOL"; break;
|
16
|
+
case "s": type = "short"; break;
|
17
|
+
case "I": type = "unsigned"; break;
|
18
|
+
case "l": type = "long"; break;
|
19
|
+
case "q": type = "long long"; break;
|
20
|
+
case "L": type = "unsigned long"; break;
|
21
|
+
case "C": type = "unsigned char"; break;
|
22
|
+
case "S": type = "unsigned short"; break;
|
23
|
+
case "Q": type = "unsigned long long"; break;
|
24
|
+
case "B": type = "_Bool"; break;
|
25
|
+
case "v": type = "void"; break;
|
26
|
+
case "*": type = "char*"; break;
|
27
|
+
case ":": type = "SEL"; break;
|
28
|
+
case "#": type = "Class"; break;
|
29
|
+
case "@": type = "id"; break;
|
30
|
+
case "@?": type = "id"; break;
|
31
|
+
case "Vv": type = "void"; break;
|
32
|
+
case "rv": type = "const void*"; break;
|
33
|
+
default: type = type;
|
34
|
+
|
35
|
+
}
|
36
|
+
|
37
|
+
return isPointer ? type.toString()+"*" : type.toString();
|
38
|
+
|
39
|
+
}
|
40
|
+
|
41
|
+
function getProtocolLines(protocol){
|
42
|
+
|
43
|
+
var protocolsMethodsString="";
|
44
|
+
currentProtocol=protocol;
|
45
|
+
|
46
|
+
protocolName=protocol_getName(currentProtocol);
|
47
|
+
protocolsMethodsString=protocolsMethodsString.toString()+"\n@protocol "+protocolName.toString()+"\n";
|
48
|
+
|
49
|
+
protPropertiesString="";
|
50
|
+
protPropertiesCount=new int;
|
51
|
+
protPropertyList=protocol_copyPropertyList(currentProtocol,protPropertiesCount);
|
52
|
+
for (xi=0; xi<*protPropertiesCount; xi++){
|
53
|
+
|
54
|
+
propname=property_getName(protPropertyList[xi]);
|
55
|
+
attrs=property_getAttributes(protPropertyList[xi]);
|
56
|
+
newString=propertyLineGenerator(attrs,propname).toString();
|
57
|
+
if (![protPropertiesString containsSubstring:newString]){
|
58
|
+
protPropertiesString=protPropertiesString.toString()+newString.toString();
|
59
|
+
}
|
60
|
+
}
|
61
|
+
protocolsMethodsString=protocolsMethodsString.toString()+protPropertiesString;
|
62
|
+
free(protPropertyList);
|
63
|
+
|
64
|
+
for (acase=0; acase<5; acase++){
|
65
|
+
|
66
|
+
protocolMethodsCount=new int;
|
67
|
+
isRequiredMethod=acase<2 ? NO : YES;
|
68
|
+
isInstanceMethod=(acase==0 || acase==2) ? NO : YES;
|
69
|
+
|
70
|
+
protMeths=protocol_copyMethodDescriptionList(currentProtocol, isRequiredMethod, isInstanceMethod, protocolMethodsCount);
|
71
|
+
for (gg=0; gg<*protocolMethodsCount; gg++){
|
72
|
+
if (acase<2 && ![[NSString stringWithString:protocolsMethodsString] containsSubstring:@"@optional"]){
|
73
|
+
protocolsMethodsString=protocolsMethodsString.toString()+"@optional\n";
|
74
|
+
}
|
75
|
+
if (acase>1 && ![[NSString stringWithString:protocolsMethodsString] containsSubstring:@"@required"]){
|
76
|
+
protocolsMethodsString=protocolsMethodsString.toString()+"@required\n";
|
77
|
+
}
|
78
|
+
startSign=isInstanceMethod==NO ? "+" : "-";
|
79
|
+
protSelector=protMeths[gg][0].toString();
|
80
|
+
protTypes=protMeths[gg][1];
|
81
|
+
protTypes=[protTypes stringByRemovingCharactersFromSet: [NSCharacterSet decimalDigitCharacterSet ]];
|
82
|
+
protTypes=[[NSString stringWithString:protTypes] stringByReplacingOccurrencesOfString:@"@:" withString:""];
|
83
|
+
returnType=[protTypes substringToIndex: 1];
|
84
|
+
returnType=commonTypes(returnType);
|
85
|
+
finString="";
|
86
|
+
if ([protTypes length]>1){
|
87
|
+
selectorsArray=[[NSString stringWithString:protSelector] componentsSeparatedByString:@":"];
|
88
|
+
typesArray=[NSMutableArray array];
|
89
|
+
for (typ=0; typ<[selectorsArray count]-1; typ++){
|
90
|
+
newobject=[NSString stringWithString:commonTypes([protTypes substringWithRange: [typ+1,1]])];
|
91
|
+
[typesArray addObject:newobject];
|
92
|
+
}
|
93
|
+
for (ad=0;ad<[typesArray count]; ad++){
|
94
|
+
argCount=ad+1;
|
95
|
+
finString=finString.toString()+selectorsArray[ad].toString()+"("+typesArray[ad].toString()+")"+":arg"+argCount.toString()+" ";
|
96
|
+
}
|
97
|
+
}
|
98
|
+
else{
|
99
|
+
finString=protSelector.toString();
|
100
|
+
|
101
|
+
}
|
102
|
+
|
103
|
+
finString=finString.toString()+";";
|
104
|
+
protocolsMethodsString=protocolsMethodsString.toString()+startSign.toString()+"("+returnType.toString()+")"+finString.toString()+"\n";
|
105
|
+
}
|
106
|
+
}
|
107
|
+
return protocolsMethodsString.toString()+"@end\n";
|
108
|
+
|
109
|
+
}
|
110
|
+
|
111
|
+
function constructTypeAndName(aType,IvarName,isIvar){
|
112
|
+
|
113
|
+
NSNotFound=2147483647;
|
114
|
+
|
115
|
+
compareString1=[NSString stringWithString:aType];
|
116
|
+
compareString2=[[[NSString stringWithString:aType] stringByReplacingOccurrencesOfString:"^" withString:""] stringByAppendingString:@"*"];
|
117
|
+
|
118
|
+
if (![[NSString stringWithString:commonTypes(aType)] isEqual:compareString1] && ![[NSString stringWithString:commonTypes(aType)] isEqual:compareString2]){
|
119
|
+
|
120
|
+
return commonTypes(aType).toString()+" "+IvarName.toString();
|
121
|
+
}
|
122
|
+
|
123
|
+
charSet=[NSCharacterSet characterSetWithCharactersInString:"@^\"{}="];
|
124
|
+
structCharSet=[NSCharacterSet characterSetWithCharactersInString:"?:{}="];
|
125
|
+
|
126
|
+
if ([aType rangeOfString:"]"].location!=NSNotFound && [aType rangeOfString:"^{"].location==NSNotFound){
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
aType=[aType stringByRemovingCharactersFromSet: [NSCharacterSet punctuationCharacterSet ]];
|
132
|
+
arrayCount=[[aType copy] stringByRemovingCharactersFromSet: [NSCharacterSet letterCharacterSet ]];
|
133
|
+
arrayType=[aType stringByRemovingCharactersFromSet: [NSCharacterSet decimalDigitCharacterSet ]];
|
134
|
+
return commonTypes(arrayType).toString()+"["+arrayCount.toString()+"]"+" "+IvarName.toString();
|
135
|
+
|
136
|
+
}
|
137
|
+
|
138
|
+
if ([aType rangeOfString:"{?"].length>0 && isIvar){
|
139
|
+
|
140
|
+
aType=[aType stringByRemovingCharactersFromSet:structCharSet];
|
141
|
+
structValues=[aType componentsSeparatedByString:@"\""];
|
142
|
+
structValues =[NSMutableArray arrayWithArray:structValues ];
|
143
|
+
firstEntry=[structValues removeObjectAtIndex:0];
|
144
|
+
[structValues removeObject:firstEntry];
|
145
|
+
newString=[NSString stringWithString:"struct {\n"];
|
146
|
+
namesArray=[NSMutableArray array];
|
147
|
+
typesArray=[NSMutableArray array];
|
148
|
+
|
149
|
+
for (d=0; d<[structValues count] ; d++){
|
150
|
+
|
151
|
+
if ((d % 2)==0){
|
152
|
+
[namesArray addObject:structValues[d]];
|
153
|
+
}
|
154
|
+
else{
|
155
|
+
[typesArray addObject:structValues[d]];
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
for (e=0; e<[typesArray count]; e++){
|
160
|
+
newString=newString.toString()+"\t\t"+constructTypeAndName(typesArray[e],namesArray[e],0).toString()+";\n";
|
161
|
+
}
|
162
|
+
return newString.toString()+"\t} "+IvarName.toString();
|
163
|
+
|
164
|
+
}
|
165
|
+
|
166
|
+
if ([aType rangeOfString:"{"].length>0){
|
167
|
+
|
168
|
+
returnValue="struct ";
|
169
|
+
range=[aType rangeOfString:@"="];
|
170
|
+
|
171
|
+
if ([aType containsSubstring:@"^{?="]){
|
172
|
+
|
173
|
+
aStruct=aType;
|
174
|
+
structString="";
|
175
|
+
someType="";
|
176
|
+
aStruct=[NSString stringWithString:aStruct];
|
177
|
+
aStruct=[aStruct stringByReplacingOccurrencesOfString:@"^{?=" withString:""];
|
178
|
+
aStruct=[aStruct stringByReplacingOccurrencesOfString:@"}" withString:""];
|
179
|
+
|
180
|
+
for (var f=0; f<[aStruct length]; f++){
|
181
|
+
currentLetter=[aStruct substringWithRange:[f,1]];
|
182
|
+
someType=constructTypeAndName(currentLetter,"",0);
|
183
|
+
someType=[someType stringByRemovingWhitespace];
|
184
|
+
structString=structString.toString()+"\t"+someType.toString()+" value"+(f+1).toString()+";\n";
|
185
|
+
}
|
186
|
+
|
187
|
+
structName="WCStruct_"+aStruct.toString();
|
188
|
+
|
189
|
+
if (![structsString containsSubstring:structName]){
|
190
|
+
structString="typedef struct{\n"+structString.toString();
|
191
|
+
structString=structString.toString()+"} "+structName.toString()+";\n\n";
|
192
|
+
structsString=structsString.toString()+structString.toString();
|
193
|
+
}
|
194
|
+
|
195
|
+
structName=structName.toString()+"*";
|
196
|
+
|
197
|
+
return structName+" "+IvarName.toString();
|
198
|
+
}
|
199
|
+
aType=[aType stringByReplacingCharactersInRange:[range.location,aType.length-range.location] withString:"" ];
|
200
|
+
returnValue=returnValue.toString()+[aType stringByRemovingCharactersFromSet:structCharSet].toString();
|
201
|
+
if ([returnValue containsSubstring:@"GSEvent"] || [returnValue containsSubstring:@"CTCall"]){
|
202
|
+
returnValue=[returnValue stringByReplacingOccurrencesOfString:"__" withString:""];
|
203
|
+
returnValue=[returnValue stringByReplacingOccurrencesOfString:"struct " withString:""];
|
204
|
+
returnValue=[returnValue stringByReplacingOccurrencesOfString:"^" withString:""];
|
205
|
+
returnValue=[returnValue stringByAppendingString:@"Ref"];
|
206
|
+
|
207
|
+
}
|
208
|
+
if ([returnValue containsSubstring:@"NSZone"]){
|
209
|
+
returnValue="NSZone*";
|
210
|
+
}
|
211
|
+
|
212
|
+
if ([returnValue containsSubstring:@"CGPoint"] || [returnValue containsSubstring:@"CGRect"] || [returnValue containsSubstring:@"CGSize"] ){
|
213
|
+
returnValue=[returnValue stringByReplacingOccurrencesOfString:@"struct " withString:@""];
|
214
|
+
}
|
215
|
+
return commonTypes(returnValue).toString()+" "+IvarName.toString();
|
216
|
+
}
|
217
|
+
|
218
|
+
|
219
|
+
if ([aType rangeOfString:@"^"].length>0){
|
220
|
+
|
221
|
+
range=[aType rangeOfString:"^" options: NULL range: [2,aType.length-2]];
|
222
|
+
if (range.length>0){
|
223
|
+
aType=[aType stringByReplacingCharactersInRange:[range.location-1,aType.length-range.location+1] withString:"" ];
|
224
|
+
}
|
225
|
+
aType=[aType stringByRemovingCharactersFromSet:charSet];
|
226
|
+
//aType=[aType stringByReplacingOccurrencesOfString:@"__" withString:""];
|
227
|
+
return aType.toString()+"* "+IvarName.toString();
|
228
|
+
|
229
|
+
}
|
230
|
+
|
231
|
+
|
232
|
+
|
233
|
+
if ([aType rangeOfString:@"@\""].length>0){
|
234
|
+
if ([aType rangeOfString:"<"].location==2){
|
235
|
+
aType="id"+aType.toString();
|
236
|
+
return [aType stringByRemovingCharactersFromSet:charSet].toString()+" "+IvarName.toString();
|
237
|
+
}
|
238
|
+
|
239
|
+
strippedString=[aType stringByRemovingCharactersFromSet:charSet];
|
240
|
+
return strippedString.toString()+ "* "+IvarName.toString();
|
241
|
+
|
242
|
+
}
|
243
|
+
|
244
|
+
if ([aType rangeOfString:@"b"].length>0 && [aType rangeOfString:":{"].length<1){
|
245
|
+
string=[aType stringByReplacingOccurrencesOfString:@"b" withString:""];
|
246
|
+
return "unsigned int "+IvarName.toString()+":"+string.toString();
|
247
|
+
}
|
248
|
+
|
249
|
+
return aType.toString() + " " + IvarName.toString();
|
250
|
+
|
251
|
+
}
|
252
|
+
|
253
|
+
|
254
|
+
|
255
|
+
function propertyLineGenerator(attributes,name){
|
256
|
+
|
257
|
+
parSet=[NSCharacterSet characterSetWithCharactersInString:@"()"];
|
258
|
+
attributes=[attributes stringByRemovingCharactersFromSet:parSet];
|
259
|
+
attrArr=[attributes componentsSeparatedByString:@","];
|
260
|
+
|
261
|
+
type=attrArr[0];
|
262
|
+
type=[type stringByReplacingCharactersInRange:[0,1] withString:""];
|
263
|
+
type=constructTypeAndName(type,"",0);
|
264
|
+
type=[type stringByRemovingWhitespace];
|
265
|
+
attrArr=[NSMutableArray arrayWithArray:attrArr];
|
266
|
+
[attrArr removeObjectAtIndex:0];
|
267
|
+
|
268
|
+
propertyString="@property ";
|
269
|
+
|
270
|
+
newPropsArray=[NSMutableArray array];
|
271
|
+
synthesize=[NSString stringWithString:""];
|
272
|
+
for each (attr in attrArr){
|
273
|
+
|
274
|
+
vToClear=nil;
|
275
|
+
|
276
|
+
if ([attr rangeOfString:@"V_"].location==0){
|
277
|
+
vToClear=attr;
|
278
|
+
attr=[attr stringByReplacingCharactersInRange:[0,2] withString:""];
|
279
|
+
synthesize="\t\t\t\t//@synthesize "+attr.toString()+"=_"+attr.toString()+" - In the implementation block";
|
280
|
+
}
|
281
|
+
|
282
|
+
if ([attr length]==1){
|
283
|
+
|
284
|
+
switch (attr.toString()){
|
285
|
+
case "R" : translatedProperty = "readonly";
|
286
|
+
case "C" : translatedProperty = "copy"; break;
|
287
|
+
case "&" : translatedProperty = "retain"; break;
|
288
|
+
case "N" : translatedProperty = "nonatomic"; break;
|
289
|
+
case "D" : translatedProperty = "@dynamic"; break;
|
290
|
+
case "W" : translatedProperty = "__weak"; break;
|
291
|
+
case "P" : translatedProperty = "t<encoding>"; break;
|
292
|
+
default: translatedProperty = attr;
|
293
|
+
}
|
294
|
+
|
295
|
+
[newPropsArray addObject:translatedProperty];
|
296
|
+
}
|
297
|
+
|
298
|
+
if ([attr rangeOfString:@"G"].location==0){
|
299
|
+
attr=[attr stringByReplacingCharactersInRange:[0,1] withString:""];
|
300
|
+
attr="getter="+attr.toString();
|
301
|
+
[newPropsArray addObject:attr];
|
302
|
+
}
|
303
|
+
|
304
|
+
if ([attr rangeOfString:@"S"].location==0){
|
305
|
+
attr=[attr stringByReplacingCharactersInRange:[0,1] withString:""];
|
306
|
+
attr="setter="+attr.toString();
|
307
|
+
[newPropsArray addObject:attr];
|
308
|
+
}
|
309
|
+
|
310
|
+
}
|
311
|
+
|
312
|
+
if ([newPropsArray containsObject:@"nonatomic"] && ![newPropsArray containsObject:@"assign"] && ![newPropsArray containsObject:@"readonly"] && ![newPropsArray containsObject:@"copy"] && ![newPropsArray containsObject:@"retain"]){
|
313
|
+
[newPropsArray addObject:@"assign"];
|
314
|
+
}
|
315
|
+
|
316
|
+
newPropsArray=[newPropsArray reversedArray];
|
317
|
+
|
318
|
+
rebuiltString=[newPropsArray componentsJoinedByString:","];
|
319
|
+
attrString=newPropsArray.length>0 ? "("+rebuiltString.toString()+")" : "(assign)";
|
320
|
+
|
321
|
+
propertyString=propertyString.toString()+attrString.toString()+" "+type.toString()+" "+name.toString()+"; "+synthesize.toString()+"\n";
|
322
|
+
return propertyString;
|
323
|
+
|
324
|
+
}
|
325
|
+
|
326
|
+
function methodLinesGenerator(methodList,methodsCount,isClassMethod){
|
327
|
+
methodLines="";
|
328
|
+
for (n=0; n<*methodsCount;n++){
|
329
|
+
method=methodList[n];
|
330
|
+
methodName=_method_getName(method);
|
331
|
+
returnType=_method_copyReturnType(method);
|
332
|
+
returnType=[constructTypeAndName([NSString stringWithString:returnType],[NSString stringWithString:""],0) stringByRemovingWhitespace];
|
333
|
+
argNum=_method_getNumberOfArguments(method);
|
334
|
+
methodBrokenDown=[methodName componentsSeparatedByString:@":"];
|
335
|
+
methodString=[NSString stringWithString:""];
|
336
|
+
if ([methodBrokenDown count]>1){
|
337
|
+
for (x=0; x<[methodBrokenDown count]-1; x++){
|
338
|
+
anIndex=x+2;
|
339
|
+
argumentType=_method_copyArgumentType(method,anIndex);
|
340
|
+
if (!argumentType){
|
341
|
+
argumentType="id";
|
342
|
+
}
|
343
|
+
typeName=constructTypeAndName([NSString stringWithString:argumentType],[NSString stringWithString:""],0);
|
344
|
+
typeName=[typeName stringByTrimmingLastCharacter];
|
345
|
+
|
346
|
+
methodString=methodString.toString()+methodBrokenDown[x].toString()+":("+typeName.toString()+")arg"+(x+1)+" ";
|
347
|
+
|
348
|
+
}
|
349
|
+
methodString=[methodString stringByTrimmingLastCharacter];
|
350
|
+
}
|
351
|
+
else{
|
352
|
+
methodString=methodName;
|
353
|
+
}
|
354
|
+
|
355
|
+
symbol=isClassMethod ? "+" : "-"; symbol=[NSString stringWithString:symbol];
|
356
|
+
newMethod=symbol.toString()+"("+returnType.toString()+")"+methodString.toString()+";\n";
|
357
|
+
cappedMethod=[methodName capitalizedString];
|
358
|
+
setterMethod="set"+cappedMethod.toString();
|
359
|
+
if (![methodsArray containsObject:newMethod] && ![propertiesString containsSubstring:methodName] && ![methodsString containsSubstring:setterMethod]){
|
360
|
+
[methodsArray addObject:newMethod];
|
361
|
+
methodLines=methodLines.toString()+newMethod.toString();
|
362
|
+
}
|
363
|
+
|
364
|
+
}
|
365
|
+
return methodLines;
|
366
|
+
|
367
|
+
}
|
368
|
+
|
369
|
+
function weak_classdump(classname,alsoDumpSuperclasses,outputdir){
|
370
|
+
|
371
|
+
//NSLog(@"weak_classdump: Dumping class %@",classname);
|
372
|
+
if (!classname){
|
373
|
+
return "Cannot find class";
|
374
|
+
}
|
375
|
+
|
376
|
+
if (typeof(alsoDumpSuperclasses) == 'undefined' || !alsoDumpSuperclasses){
|
377
|
+
alsoDumpSuperclasses=0;
|
378
|
+
}
|
379
|
+
|
380
|
+
|
381
|
+
|
382
|
+
structsString="";
|
383
|
+
interfaceString="";
|
384
|
+
version = [NSProcessInfo processInfo ].operatingSystemVersionString;
|
385
|
+
loc=[NSLocale localeWithLocaleIdentifier: "en-us"];
|
386
|
+
date=[NSDate.date descriptionWithLocale: loc];
|
387
|
+
classString = "/*\n * This header is generated by weak_classdump 0.2\n * on "+date.toString()+"\n * Operating System: "+version.toString()+"\n * weak_classdump is Freeware by Elias Limneos.\n *\n */\n\n";
|
388
|
+
if ( [[classname description] containsSubstring:@"<Protocol:"]){
|
389
|
+
|
390
|
+
classString=classString.toString()+getProtocolLines(classname).toString();
|
391
|
+
|
392
|
+
if (typeof(outputdir) == 'undefined'){
|
393
|
+
outputdir = "/tmp";
|
394
|
+
}
|
395
|
+
|
396
|
+
if (typeof(alsoDumpSuperclasses) == 'string'){
|
397
|
+
outputdir=alsoDumpSuperclasses;
|
398
|
+
}
|
399
|
+
|
400
|
+
|
401
|
+
outputdir=outputdir.toString()+"/";
|
402
|
+
|
403
|
+
if (![NSFileManager.defaultManager fileExistsAtPath:outputdir]){
|
404
|
+
try{
|
405
|
+
[NSFileManager.defaultManager createDirectoryAtPath:outputdir withIntermediateDirectories:YES attributes:nil error:nil];
|
406
|
+
}catch(e){}
|
407
|
+
}
|
408
|
+
|
409
|
+
classString = [NSString stringWithString:classString ];
|
410
|
+
if ([classString writeToFile:outputdir.toString()+classname.toString()+".h" atomically:YES]){
|
411
|
+
return "Wrote /PROTOCOL/ header file to "+outputdir.toString()+protocol_getName(classname).toString()+".h";
|
412
|
+
}
|
413
|
+
else {
|
414
|
+
NSSearchPathForDirectoriesInDomains=new Functor(dlsym(RTLD_DEFAULT,"NSSearchPathForDirectoriesInDomains"),"@ccc");
|
415
|
+
writeableDir=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
416
|
+
writeableDir=writeableDir[0];
|
417
|
+
return "Failed to write to "+outputdir.toString()+protocol_getName(classname).toString()+".h - Check file path and permissions? Suggested writeable directory: "+writeableDir.toString();
|
418
|
+
}
|
419
|
+
|
420
|
+
}
|
421
|
+
_class_copyIvarList = new Functor(dlsym(RTLD_DEFAULT,"class_copyIvarList"),"^^{objc_ivar=}#^I");
|
422
|
+
_class_copyProtocolList=new Functor(dlsym(RTLD_DEFAULT,"class_copyProtocolList"),"^@#^I");
|
423
|
+
_class_conformsToProtocol=new Functor(dlsym(RTLD_DEFAULT,"class_conformsToProtocol"),"B#@");
|
424
|
+
_class_copyMethodList=new Functor(dlsym(RTLD_DEFAULT,"class_copyMethodList"),"^^{objc_method=}#^I");
|
425
|
+
_class_copyPropertyList=new Functor(dlsym(RTLD_DEFAULT,"class_copyPropertyList"),"^^{objc_property=}#^I");
|
426
|
+
_method_getName=new Functor(dlsym(RTLD_DEFAULT,"method_getName"),"*^{objc_method=}");
|
427
|
+
_method_getNumberOfArguments=new Functor(dlsym(RTLD_DEFAULT,"method_getNumberOfArguments"),"I^{objc_method=}");
|
428
|
+
_method_copyReturnType=new Functor(dlsym(RTLD_DEFAULT,"method_copyReturnType"),"*^{objc_method=}");
|
429
|
+
_method_copyArgumentType=new Functor(dlsym(RTLD_DEFAULT,"method_copyArgumentType"),"*^{objc_method=}I");
|
430
|
+
_property_getAttributes=new Functor(dlsym(RTLD_DEFAULT,"property_getAttributes"),"*^{objc_property=}");
|
431
|
+
_property_getName=new Functor(dlsym(RTLD_DEFAULT,"property_getName"),"*^{objc_property=}");
|
432
|
+
_ivar_getName = new Functor(dlsym(RTLD_DEFAULT,"ivar_getName"),"*^?");
|
433
|
+
_ivar_getTypeEncoding = new Functor(dlsym(RTLD_DEFAULT,"ivar_getTypeEncoding"),"*^{objc_ivar=}");
|
434
|
+
_protocol_getName=new Functor(dlsym(RTLD_DEFAULT,"protocol_getName"),"*@");
|
435
|
+
_objc_getClassList=new Functor(dlsym(RTLD_DEFAULT,"objc_getClassList"),"i^#");
|
436
|
+
methodsArray=[NSMutableArray array];
|
437
|
+
propertiesString=@"";
|
438
|
+
methodsString=@"";
|
439
|
+
ivarsString=@"";
|
440
|
+
classMethodsString=@"";
|
441
|
+
|
442
|
+
startingClassname=classname;
|
443
|
+
superclass=classname.superclass;
|
444
|
+
|
445
|
+
protocolsCount=new int;
|
446
|
+
protocolArray=_class_copyProtocolList(classname,protocolsCount);
|
447
|
+
|
448
|
+
var protocolsMethodsString=classString;
|
449
|
+
var protocolName;
|
450
|
+
allProtocols="";
|
451
|
+
if (*protocolsCount>0){
|
452
|
+
for (iter=0; iter<*protocolsCount; iter++){
|
453
|
+
if (_class_conformsToProtocol(classname,protocolArray[iter])){
|
454
|
+
protocolName=protocol_getName(protocolArray[iter]);
|
455
|
+
protocolsMethodsString=protocolsMethodsString.toString()+getProtocolLines(protocolArray[iter]).toString();
|
456
|
+
}
|
457
|
+
|
458
|
+
protocolsMethodsString = [NSString stringWithString:protocolsMethodsString ];
|
459
|
+
|
460
|
+
classString=classString.toString()+"#import <"+protocolName.toString()+".h>\n";
|
461
|
+
|
462
|
+
if (typeof(outputdir)=="undefined" || outputdir==null){
|
463
|
+
outputdir="/tmp";
|
464
|
+
}
|
465
|
+
outputdir=outputdir+"/";
|
466
|
+
allProtocols=allProtocols.toString()+", "+outputdir.toString()+protocolName.toString()+".h";
|
467
|
+
if ([protocolsMethodsString writeToFile:outputdir.toString()+protocolName.toString()+".h" atomically:YES]){
|
468
|
+
//NSLog(@"Found Protocol %@, wrote to %@%@.h",protocolName,outputdir,protocolName);
|
469
|
+
}
|
470
|
+
}
|
471
|
+
}
|
472
|
+
|
473
|
+
|
474
|
+
protocolsString="";
|
475
|
+
if (*protocolsCount>0){
|
476
|
+
protocolsString=@" <".toString();
|
477
|
+
for (i=0; i<*protocolsCount; i++){
|
478
|
+
if (_class_conformsToProtocol(classname,protocolArray[i])){
|
479
|
+
comma=@"".toString();
|
480
|
+
if (i<*protocolsCount-1){
|
481
|
+
comma=@", ".toString();
|
482
|
+
}
|
483
|
+
protocolsString=protocolsString.toString()+_protocol_getName(protocolArray[i]).toString()+comma;
|
484
|
+
}
|
485
|
+
}
|
486
|
+
protocolsString=protocolsString+@">".toString();
|
487
|
+
}
|
488
|
+
|
489
|
+
if (classname.superclass!=nil && classname.superclass!="nil"){
|
490
|
+
interfaceString = [NSString stringWithString:@"\n@interface "+classname.toString()+" : "+classname.superclass.toString()].toString() + protocolsString.toString();
|
491
|
+
}
|
492
|
+
else{
|
493
|
+
interfaceString = [NSString stringWithString:@"\n@interface "+classname.toString()].toString() + protocolsString.toString();
|
494
|
+
}
|
495
|
+
|
496
|
+
|
497
|
+
while (classname!=NSObject && (classname.superclass!="nil" && classname.superclass!=NSObject) ) {
|
498
|
+
|
499
|
+
|
500
|
+
// Get Ivars
|
501
|
+
classIvarCount=new int;
|
502
|
+
superclassIvarCount=new int;
|
503
|
+
list=_class_copyIvarList(classname,classIvarCount);
|
504
|
+
superlist=_class_copyIvarList(superclass,superclassIvarCount);
|
505
|
+
superClassIvars=[NSMutableArray array];
|
506
|
+
for (i=0; i<*superclassIvarCount;i++){
|
507
|
+
if (_ivar_getName(superlist[i])){
|
508
|
+
[superClassIvars addObject:_ivar_getName(superlist[i])];
|
509
|
+
}
|
510
|
+
|
511
|
+
}
|
512
|
+
free(superlist);
|
513
|
+
|
514
|
+
for (i=0; i<*classIvarCount;i++){
|
515
|
+
classIvar=_ivar_getName(list[i]);
|
516
|
+
appendString="";
|
517
|
+
if (classIvar && ![superClassIvars containsObject:classIvar]){
|
518
|
+
ivarType=ivar_getTypeEncoding(list[i]).toString();
|
519
|
+
ivar=constructTypeAndName([NSString stringWithString:ivarType],[NSString stringWithString:_ivar_getName(list[i])],1);
|
520
|
+
newString="\n\t"+ivar.toString()+"; ";
|
521
|
+
if (![ivarsString containsSubstring:newString]){
|
522
|
+
ivarsString=ivarsString.toString()+newString.toString();
|
523
|
+
}
|
524
|
+
}
|
525
|
+
|
526
|
+
}
|
527
|
+
free(list);
|
528
|
+
|
529
|
+
// Get Properties
|
530
|
+
propertiesCount=new int;
|
531
|
+
propertyList=_class_copyPropertyList(classname,propertiesCount);
|
532
|
+
for (i=0; i<*propertiesCount; i++){
|
533
|
+
|
534
|
+
propname=_property_getName(propertyList[i]);
|
535
|
+
attrs=_property_getAttributes(propertyList[i]);
|
536
|
+
newString=propertyLineGenerator(attrs,propname).toString();
|
537
|
+
if (![propertiesString containsSubstring:newString]){
|
538
|
+
propertiesString=propertiesString.toString()+newString.toString();
|
539
|
+
}
|
540
|
+
}
|
541
|
+
free(propertyList);
|
542
|
+
|
543
|
+
// Get Methods
|
544
|
+
|
545
|
+
methodsCount=new int;
|
546
|
+
classMethodsCount=new int;
|
547
|
+
classMethodList=_class_copyMethodList(object_getClass(classname),classMethodsCount);
|
548
|
+
methodList=_class_copyMethodList(classname,methodsCount);
|
549
|
+
classMethodsString=classMethodsString.toString()+methodLinesGenerator(classMethodList,classMethodsCount,1).toString();
|
550
|
+
methodsString=methodsString.toString()+methodLinesGenerator(methodList,methodsCount,0).toString();
|
551
|
+
free(methodList);
|
552
|
+
free(classMethodList);
|
553
|
+
|
554
|
+
if (!alsoDumpSuperclasses)
|
555
|
+
break;
|
556
|
+
classname=classname.superclass ? classname.superclass : NSObject;
|
557
|
+
|
558
|
+
}
|
559
|
+
|
560
|
+
classString= classString.toString()+structsString.toString()+interfaceString.toString();
|
561
|
+
classString = classString.toString()+" {"+ivarsString.toString()+"\n}\n"+propertiesString.toString()+classMethodsString.toString()+methodsString.toString();
|
562
|
+
classString = classString.toString()+"@end";
|
563
|
+
|
564
|
+
|
565
|
+
if (typeof(outputdir) == 'undefined'){
|
566
|
+
outputdir = "/tmp";
|
567
|
+
}
|
568
|
+
|
569
|
+
if (typeof(alsoDumpSuperclasses) == 'string'){
|
570
|
+
outputdir=alsoDumpSuperclasses;
|
571
|
+
}
|
572
|
+
|
573
|
+
isDir= new boolean;
|
574
|
+
dirExists=[[NSFileManager defaultManager ] fileExistsAtPath:outputdir isDirectory: isDir] ;
|
575
|
+
if (!dirExists || !isDir){
|
576
|
+
createDirSucceeded = [[NSFileManager defaultManager ] createDirectoryAtPath:outputdir attributes: nil];
|
577
|
+
}
|
578
|
+
|
579
|
+
outputdir=outputdir.toString()+"/";
|
580
|
+
|
581
|
+
if (![NSFileManager.defaultManager fileExistsAtPath:outputdir]){
|
582
|
+
try{
|
583
|
+
[NSFileManager.defaultManager createDirectoryAtPath:outputdir withIntermediateDirectories:YES attributes:nil error:nil];
|
584
|
+
}catch(e){}
|
585
|
+
}
|
586
|
+
|
587
|
+
classString = [NSString stringWithString:classString ];
|
588
|
+
if ([classString writeToFile:outputdir.toString()+startingClassname.toString()+".h" atomically:YES]){
|
589
|
+
return "Wrote file to "+outputdir.toString()+startingClassname.toString()+".h"+allProtocols.toString();
|
590
|
+
}
|
591
|
+
else {
|
592
|
+
NSSearchPathForDirectoriesInDomains=new Functor(dlsym(RTLD_DEFAULT,"NSSearchPathForDirectoriesInDomains"),"@ccc");
|
593
|
+
writeableDir=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
594
|
+
writeableDir=writeableDir[0];
|
595
|
+
return "Failed to write to "+outputdir.toString()+startingClassname.toString()+".h - Check file path and permissions? Suggested writeable directory: "+writeableDir.toString();
|
596
|
+
}
|
597
|
+
}
|
598
|
+
|
599
|
+
|
600
|
+
function writeToSylogFromBgThread(string){
|
601
|
+
//NSLog(string);
|
602
|
+
}
|
603
|
+
|
604
|
+
function mweak_loadwdc_class(){
|
605
|
+
|
606
|
+
@implementation WCDBundleDumper : NSObject {}
|
607
|
+
+(id)dumpBundle:(id)infoDictionary{
|
608
|
+
var bundle=[infoDictionary objectForKey:@"bundle"];
|
609
|
+
var outputdir=[infoDictionary objectForKey:@"outputdir"];
|
610
|
+
writeToSylogFromBgThread(@"weak_classdump: Gathering all classes...please wait...");
|
611
|
+
var permittedNames = [ObjectiveC.classes allKeys].filter( function (name) { if ([name rangeOfString:"LA"].location!=0){ return [[NSBundle bundleForClass:objc_getClass(name.toString())] isEqual:bundle]; } else{ return NO; } } );
|
612
|
+
writeToSylogFromBgThread(@"weak_classdump: Found " + [permittedNames count].toString() +" classes matching your bundle. Starting dump...");
|
613
|
+
var results = [];
|
614
|
+
for (var i = 0; i < permittedNames.length; i++) {
|
615
|
+
try {
|
616
|
+
results.push(weak_classdump(objc_getClass(objc_getClass([[permittedNames[i] description] UTF8String])), false, outputdir));
|
617
|
+
} catch (e) {
|
618
|
+
}
|
619
|
+
}
|
620
|
+
|
621
|
+
[UIDevice.currentDevice _playSystemSound:1100]; // comment out to not produce any sound on finish
|
622
|
+
writeToSylogFromBgThread([NSString stringWithFormat:@"weak_classdump: Finished dumping bundle %@. Check output dir %@",bundle,outputdir]);
|
623
|
+
|
624
|
+
}
|
625
|
+
@end
|
626
|
+
|
627
|
+
}
|
628
|
+
|
629
|
+
function weak_classdump_bundle(bundle, outputdir) {
|
630
|
+
|
631
|
+
if (typeof(bundle)=="undefined"){
|
632
|
+
bundle=[NSBundle mainBundle];
|
633
|
+
}
|
634
|
+
if (![bundle isLoaded]){
|
635
|
+
//NSLog(@"weak_classdump: Bundle %@ is not loaded,attempting to load it",bundle);
|
636
|
+
[bundle load];
|
637
|
+
}
|
638
|
+
if (typeof(outputdir)=="undefined"){
|
639
|
+
outputdir="/tmp/";
|
640
|
+
}
|
641
|
+
|
642
|
+
|
643
|
+
var infoDict=[NSMutableDictionary dictionary];
|
644
|
+
[ infoDict setObject:bundle forKey:@"bundle"];
|
645
|
+
[ infoDict setObject:outputdir forKey:@"outputdir"];
|
646
|
+
|
647
|
+
try {
|
648
|
+
[WCDBundleDumper class];
|
649
|
+
} catch (e){
|
650
|
+
mweak_loadwdc_class();
|
651
|
+
}
|
652
|
+
|
653
|
+
[objc_getClass("WCDBundleDumper") performSelectorInBackground:@selector(dumpBundle:) withObject:infoDict ];
|
654
|
+
return "Dumping bundle... Check syslog. Will play lock sound when done."
|
655
|
+
|
656
|
+
}
|
657
|
+
|
658
|
+
|
659
|
+
if ( ! [NSString instancesRespondToSelector:@selector(stringByRemovingCharactersFromSet:)] ){
|
660
|
+
|
661
|
+
|
662
|
+
|
663
|
+
|
664
|
+
@implementation NSString (weakclassdump_compatibility)
|
665
|
+
- (void)removeCharactersInSet:(id)set{
|
666
|
+
|
667
|
+
length = [this length];
|
668
|
+
matchRange = [this rangeOfCharacterFromSet:set options:2 range:[0, length]];
|
669
|
+
while(matchRange.length > 0){
|
670
|
+
replaceRange = matchRange;
|
671
|
+
searchRange=[0,0];
|
672
|
+
searchRange.location = replaceRange.location + replaceRange.length;
|
673
|
+
searchRange.length = length - searchRange.location;
|
674
|
+
for(;;){
|
675
|
+
matchRange = [this rangeOfCharacterFromSet:set options:2 range:searchRange];
|
676
|
+
if((matchRange.length == 0) || (matchRange.location != searchRange.location))
|
677
|
+
break;
|
678
|
+
replaceRange.length += matchRange.length;
|
679
|
+
searchRange.length -= matchRange.length;
|
680
|
+
searchRange.location += matchRange.length;
|
681
|
+
}
|
682
|
+
[this deleteCharactersInRange:replaceRange];
|
683
|
+
matchRange.location -= replaceRange.length;
|
684
|
+
length -= replaceRange.length;
|
685
|
+
}
|
686
|
+
}
|
687
|
+
|
688
|
+
|
689
|
+
- (id)stringByRemovingCharactersFromSet:(id)set{
|
690
|
+
|
691
|
+
if([this rangeOfCharacterFromSet:set options:2].length == 0)
|
692
|
+
return this;
|
693
|
+
temp = [[this mutableCopyWithZone:[this zone]] autorelease];
|
694
|
+
[temp removeCharactersInSet:set];
|
695
|
+
temp=[temp stringByReplacingOccurrencesOfString: @"\"" withString: @""];
|
696
|
+
return temp;
|
697
|
+
}
|
698
|
+
|
699
|
+
@end
|
700
|
+
|
701
|
+
}
|
702
|
+
|
703
|
+
if ( ! [NSString instancesRespondToSelector:@selector(stringByRemovingWhitespace)] ){
|
704
|
+
|
705
|
+
@implementation NSString (weakclassdump_compatibility)
|
706
|
+
-(id)stringByRemovingWhitespace{
|
707
|
+
return [this stringByRemovingCharactersFromSet:[NSCharacterSet whitespaceCharacterSet]];
|
708
|
+
}
|
709
|
+
@end
|
710
|
+
}
|
711
|
+
|
712
|
+
//NSLog_ = dlsym(RTLD_DEFAULT, "NSLog")
|
713
|
+
//NSLog = function() { var types = 'v', args = [], count = arguments.length; for (var i = 0; i != count; ++i) { types += '@'; args.push(arguments[i]); } new Functor(NSLog_, types).apply(null, args); }
|
714
|
+
|
715
|
+
|
716
|
+
// Usage example : weak_classdump(SBAwayController);
|
717
|
+
// (will write to default path "/tmp/SBAwayController.h"
|
718
|
+
// example 2: weak_classdump(UIApplication,"/var/mobile/");
|
719
|
+
// will write to "/var/mobile/UIApplication.h"
|
720
|
+
// example 3: weak_classdump_bundle([NSBundle bundleWithPath:"/System/Library/Frameworks/iAd.framework"]);
|
721
|
+
// will dump all classes in the defined bundle to default dir "/tmp"
|
722
|
+
// example 4: weak_classdump_bundle([NSBundle bundleWithPath:"/System/Library/Frameworks/iAd.framework"],"/tmp/iAD.framework/Headers/");
|
723
|
+
// will dump all classes in the defined bundle to "/tmp/iAD.framework/"
|
724
|
+
|
725
|
+
|
726
|
+
"Added weak_classdump to \""+NSProcessInfo.processInfo .processName.toString()+"\" ("+NSProcessInfo.processInfo .processIdentifier.toString()+")";
|