idb 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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()+")";