idb 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +19 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +65 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +2 -0
  9. data/bin/idb +5 -0
  10. data/idb.gemspec +41 -0
  11. data/lib/LICENSE +20 -0
  12. data/lib/README.md +54 -0
  13. data/lib/config/.dummy +0 -0
  14. data/lib/config/settings.yml +8 -0
  15. data/lib/gui/app_binary_tab_widget.rb +45 -0
  16. data/lib/gui/app_details_group_box.rb +213 -0
  17. data/lib/gui/app_list_dialog.rb +67 -0
  18. data/lib/gui/app_list_widget_item.rb +9 -0
  19. data/lib/gui/binary_strings_widget.rb +33 -0
  20. data/lib/gui/browse_filesystem_widget.rb +4 -0
  21. data/lib/gui/ca_manager_dialog.rb +137 -0
  22. data/lib/gui/cache_db_widget.rb +61 -0
  23. data/lib/gui/certificate_item.rb +5 -0
  24. data/lib/gui/console_widget.rb +163 -0
  25. data/lib/gui/cycript_console_widget.rb +68 -0
  26. data/lib/gui/cycript_thread.rb +81 -0
  27. data/lib/gui/device_info_group_box.rb +55 -0
  28. data/lib/gui/device_status_dialog.rb +351 -0
  29. data/lib/gui/file_system_events_widget.rb +4 -0
  30. data/lib/gui/fs_viewer_tab_widget.rb +245 -0
  31. data/lib/gui/i_device_syslog_thread.rb +47 -0
  32. data/lib/gui/images/check.png +0 -0
  33. data/lib/gui/images/folder.ico +0 -0
  34. data/lib/gui/images/iphone.ico +0 -0
  35. data/lib/gui/images/screenshot.png +0 -0
  36. data/lib/gui/key_chain_widget.rb +86 -0
  37. data/lib/gui/local_storage_tab_widget.rb +37 -0
  38. data/lib/gui/log_plain_text_edit.rb +18 -0
  39. data/lib/gui/log_widget.rb +71 -0
  40. data/lib/gui/main_tab_widget.rb +179 -0
  41. data/lib/gui/pasteboard_monitor_widget.rb +116 -0
  42. data/lib/gui/path_list_widget_item.rb +5 -0
  43. data/lib/gui/pb_watcher_thread.rb +63 -0
  44. data/lib/gui/plist_file_widget.rb +66 -0
  45. data/lib/gui/qt_ruby_variant.rb +16 -0
  46. data/lib/gui/screenshot_wizard.rb +169 -0
  47. data/lib/gui/settings_dialog.rb +69 -0
  48. data/lib/gui/settings_tab_widget.rb +149 -0
  49. data/lib/gui/shared_libraries_widget.rb +47 -0
  50. data/lib/gui/snoop_it_fs_events_widget.rb +150 -0
  51. data/lib/gui/snoop_it_keychain_widget.rb +172 -0
  52. data/lib/gui/snoop_it_sensitive_api_widget.rb +128 -0
  53. data/lib/gui/snoop_it_tab_widget.rb +27 -0
  54. data/lib/gui/snoop_it_update_thread.rb +48 -0
  55. data/lib/gui/sqlite_widget.rb +73 -0
  56. data/lib/gui/ssh_port_forward_tab_widget.rb +209 -0
  57. data/lib/gui/tool_widget.rb +94 -0
  58. data/lib/gui/url_handler_widget.rb +26 -0
  59. data/lib/gui/url_scheme_fuzz_widget.rb +103 -0
  60. data/lib/gui/url_scheme_widget.rb +60 -0
  61. data/lib/gui/weak_class_dump_widget.rb +89 -0
  62. data/lib/helper/ssh_port_forwarder.rb +72 -0
  63. data/lib/idb.rb +295 -0
  64. data/lib/idb/version.rb +3 -0
  65. data/lib/lib/CgBI.rb +153 -0
  66. data/lib/lib/abstract_device.rb +31 -0
  67. data/lib/lib/app.rb +286 -0
  68. data/lib/lib/app_binary.rb +57 -0
  69. data/lib/lib/ca_interface.rb +151 -0
  70. data/lib/lib/configuration.rb +0 -0
  71. data/lib/lib/console_launcher.rb +24 -0
  72. data/lib/lib/device.rb +438 -0
  73. data/lib/lib/device_ca_interface.rb +36 -0
  74. data/lib/lib/host_file_wrapper.rb +27 -0
  75. data/lib/lib/i_device_diagnostics_wrapper.rb +90 -0
  76. data/lib/lib/keychain_plist_parser.rb +15 -0
  77. data/lib/lib/local_operations.rb +67 -0
  78. data/lib/lib/otool_wrapper.rb +116 -0
  79. data/lib/lib/plist_util.rb +72 -0
  80. data/lib/lib/qt_thread_fix.rb +29 -0
  81. data/lib/lib/rsync_git_manager.rb +81 -0
  82. data/lib/lib/screen_shot_util.rb +59 -0
  83. data/lib/lib/settings.rb +67 -0
  84. data/lib/lib/simulator.rb +60 -0
  85. data/lib/lib/simulator_ca_interface.rb +16 -0
  86. data/lib/lib/snoop_it_wrapper.rb +80 -0
  87. data/lib/lib/ssh_operations.rb +136 -0
  88. data/lib/lib/ssh_port_forwarder.rb +43 -0
  89. data/lib/lib/tools.rb +11 -0
  90. data/lib/lib/url_scheme_fuzzer.rb +98 -0
  91. data/lib/lib/usb_muxd_wrapper.rb +32 -0
  92. data/lib/lib/weak_class_dump_wrapper.rb +62 -0
  93. data/lib/utils/dumpdecrypted/README +4 -0
  94. data/lib/utils/dumpdecrypted/dumpdecrypted_armv6.dylib +0 -0
  95. data/lib/utils/dumpdecrypted/dumpdecrypted_armv7.dylib +0 -0
  96. data/lib/utils/ios-ssl-kill-switch/com.isecpartners.nabla.sslkillswitch_v0.5-iOS_6.1.deb +0 -0
  97. data/lib/utils/keychain_dump/README +2 -0
  98. data/lib/utils/keychain_dump/keychain_dump +0 -0
  99. data/lib/utils/pbwatcher/pbwatcher +0 -0
  100. data/lib/utils/pcviewer/protectionclassviewer +0 -0
  101. data/lib/utils/weak_class_dump/README +5 -0
  102. data/lib/utils/weak_class_dump/weak_classdump.cy +726 -0
  103. 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
@@ -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
@@ -0,0 +1,4 @@
1
+ dumpdecrypted is developed and maintained by Stefan Esser
2
+ https://github.com/stefanesser/dumpdecrypted
3
+
4
+ Used with permission.
@@ -0,0 +1,2 @@
1
+ Tool from iphone-dataprotection
2
+ https://code.google.com/p/iphone-dataprotection/
@@ -0,0 +1,5 @@
1
+ weak_classdump is developed and maintained by Elias Limneos
2
+ https://github.com/limneos/weak_classdump
3
+
4
+ License
5
+ weak_classdump is open source. Feel free to help improving it if you like.
@@ -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()+")";