2 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // File: AppController.m
6 // Created: Wed Aug 13 2003
8 // Copyright: 2003 Chaz McGarvey. All rights reserved.
9 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 #import "AppController.h"
13 #include <mach/vm_map.h>
14 #include <mach/mach_traps.h>
18 #define PID_SELECTED [[[processList objectAtIndex:[processPopup indexOfSelectedItem]] objectForKey:@"NSApplicationProcessIdentifier"] intValue]
19 #define TYPE_SELECTED [typePopup indexOfSelectedItem]
20 #define SIZE_SELECTED [sizePopup indexOfSelectedItem]
23 @implementation AppController
27 if ( self = [super init
] )
37 NSNotificationCenter
*nc
= [[NSWorkspace sharedWorkspace
] notificationCenter
];
39 [self rebuildProcessList
];
40 [self updateProcessPopup
];
41 [self updateTypePopup
];
42 [self updateSizePopup
];
43 [self updateChangeButton
];
44 [self updateStatusText
];
46 [nc addObserver
:self selector
:@selector(processListChanged
:) name
:@
"NSWorkspaceDidLaunchApplicationNotification" object
:nil];
47 [nc addObserver
:self selector
:@selector(processListChanged
:) name
:@
"NSWorkspaceDidTerminateApplicationNotification" object
:nil];
59 [addressList release
], addressList
= nil;
61 // update the interface
62 [typePopup setEnabled
:YES
];
63 [sizePopup setEnabled
:YES
];
64 [searchTextField setStringValue
:@
""];
65 [changeTextField setStringValue
:@
""];
66 [addressTable reloadData
];
71 - (void)firstSearch
:(id)nothing
73 NSAutoreleasePool
*pool
= [[NSAutoreleasePool alloc
] init
];
75 pid_t pid
= (pid_t
)PID_SELECTED
;
80 vm_address_t address
= 0x0;
82 vm_region_basic_info_data_t info
;
83 mach_msg_type_number_t infoCnt
= 8;
84 mach_port_t object_name
= 0;
89 char unsigned *string8bit
= (char unsigned *)[[searchTextField stringValue
] lossyCString
];
90 long unsigned stringSize
= strlen( string8bit
);
91 char integer8bit
= (char)[searchTextField intValue
];
92 short integer16bit
= (short)[searchTextField intValue
];
93 long integer32bit
= (long)[searchTextField intValue
];
94 long long integer64bit
= (long long)[searchTextField intValue
];
95 float float32bit
= (float)[searchTextField floatValue
];
96 double float64bit
= (double)[searchTextField doubleValue
];
100 if ( (result
= task_for_pid( current_task(), pid
, &task
)) != KERN_SUCCESS
)
102 NSLog( @
"task_for_pid returned error: %i", result
);
106 addressList
= [[NSMutableArray alloc
] init
];
110 if ( (result
= vm_region( task
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
)) != KERN_SUCCESS
)
112 if ( result
!= KERN_INVALID_ADDRESS
)
114 NSLog( @
"vm_region returned error: %i", result
);
120 //NSLog( @"address: %X, size: %i", address, size );
122 if ( (info.protection
& VM_PROT_READ
) && ((info.protection
& VM_PROT_WRITE
) >> 1) )
124 data
= (char unsigned *)malloc( size
);
127 if ( (result
= vm_read_overwrite( task
, address
, size
, (vm_address_t
)data
, &dataCnt
)) != KERN_SUCCESS
&& result
!= KERN_PROTECTION_FAILURE
)
129 NSLog( @
"vm_read_overwrite returned error: %i", result
);
134 if ( result
== KERN_SUCCESS
)
136 long unsigned i
, max
= (long unsigned)dataCnt
;
138 //NSLog( @"data: %X, size: %i", (vm_address_t)data, dataCnt );
140 switch ( TYPE_SELECTED
)
143 switch ( SIZE_SELECTED
)
147 long unsigned maxString
= max
- stringSize
;
149 for ( i
= 0; i
< maxString
; i
+= sizeof(char unsigned) )
151 if ( strncmp( string8bit
, data
+i
, stringSize
) == 0 )
153 [addressList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
162 switch ( SIZE_SELECTED
)
166 for ( i
= 0; i
< max
; i
+= sizeof(char) )
168 if ( integer8bit
== *((char *)(data
+i
)) )
170 [addressList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
178 for ( i
= 0; i
< max
; i
+= sizeof(short) )
180 if ( integer16bit
== *((short *)(data
+i
)) )
182 [addressList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
190 for ( i
= 0; i
< max
; i
+= sizeof(long) )
192 if ( integer32bit
== *((long *)(data
+i
)) )
194 [addressList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
202 for ( i
= 0; i
< max
; i
+= sizeof(long long) )
204 if ( integer64bit
== *((long long *)(data
+i
)) )
206 [addressList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
215 switch ( SIZE_SELECTED
+2 )
219 for ( i
= 0; i
< max
; i
+= sizeof(float) )
221 if ( float32bit
== *((float *)(data
+i
)) )
223 [addressList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
231 for ( i
= 0; i
< max
; i
+= sizeof(double) )
233 if ( float64bit
== *((double *)(data
+i
)) )
235 [addressList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
253 // update the interface
254 [statusBar stopAnimation
:self];
255 [self updateProcessPopup
];
256 [self updateSearchButton
];
257 [self updateTypePopup
];
258 [self updateSizePopup
];
259 [self updateChangeButton
];
260 [self updateStatusText
];
261 [addressTable reloadData
];
266 - (void)search
:(id)nothing
268 NSAutoreleasePool
*pool
= [[NSAutoreleasePool alloc
] init
];
270 pid_t pid
= (pid_t
)PID_SELECTED
;
273 kern_return_t result
;
275 vm_address_t address
= 0x0;
277 vm_region_basic_info_data_t info
;
278 mach_msg_type_number_t infoCnt
= 8;
279 mach_port_t object_name
= 0;
284 char unsigned *string8bit
= (char unsigned *)[[searchTextField stringValue
] lossyCString
];
285 long unsigned stringSize
= strlen( string8bit
);
286 char integer8bit
= (char)[searchTextField intValue
];
287 short integer16bit
= (short)[searchTextField intValue
];
288 long integer32bit
= (long)[searchTextField intValue
];
289 long long integer64bit
= (long long)[searchTextField intValue
];
290 float float32bit
= (float)[searchTextField floatValue
];
291 double float64bit
= (double)[searchTextField doubleValue
];
293 long unsigned j
, max
= [addressList count
];
295 NSMutableArray
*newList
= [[NSMutableArray alloc
] init
];
297 if ( (result
= task_for_pid( current_task(), pid
, &task
)) != KERN_SUCCESS
)
299 NSLog( @
"task_for_pid returned error: %i", result
);
303 for ( j
= 0; j
< max
; j
++ )
305 long unsigned item
= [[addressList objectAtIndex
:j
] unsignedLongValue
];
307 address
= (vm_address_t
)item
;
309 if ( (result
= vm_region( task
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
)) != KERN_SUCCESS
)
311 if ( result
!= KERN_INVALID_ADDRESS
)
313 NSLog( @
"vm_region returned error: %i", result
);
319 //NSLog( @"address: %X, size: %i", address, size );
321 if ( (info.protection
& VM_PROT_READ
) && ((info.protection
& VM_PROT_WRITE
) >> 1) )
323 data
= (char unsigned *)malloc( size
);
326 if ( (result
= vm_read_overwrite( task
, address
, size
, (vm_address_t
)data
, &dataCnt
)) != KERN_SUCCESS
&& result
!= KERN_PROTECTION_FAILURE
)
328 NSLog( @
"vm_read_overwrite returned error: %i", result
);
333 if ( result
== KERN_SUCCESS
)
335 long unsigned i
= item
- (long unsigned)address
;
337 if ( i
< (long unsigned)dataCnt
)
339 //NSLog( @"data: %X, size: %i", (vm_address_t)data, dataCnt );
341 switch ( TYPE_SELECTED
)
344 switch ( SIZE_SELECTED
)
348 if ( strncmp( string8bit
, data
+i
, stringSize
) == 0 )
350 [newList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
358 switch ( SIZE_SELECTED
)
362 if ( integer8bit
== *((char *)(data
+i
)) )
364 [newList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
371 if ( integer16bit
== *((short *)(data
+i
)) )
373 [newList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
380 if ( integer32bit
== *((long *)(data
+i
)) )
382 [newList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
389 if ( integer64bit
== *((long long *)(data
+i
)) )
391 [newList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
399 switch ( SIZE_SELECTED
+2 )
403 if ( float32bit
== *((float *)(data
+i
)) )
405 [newList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
412 if ( float64bit
== *((double *)(data
+i
)) )
414 [newList addObject
:[NSNumber numberWithUnsignedLong
:(long unsigned)address
+ i
]];
428 [addressList release
];
429 addressList
= newList
;
433 // update the interface
434 [statusBar stopAnimation
:self];
435 [self updateProcessPopup
];
436 [self updateSearchButton
];
437 [self updateTypePopup
];
438 [self updateSizePopup
];
439 [self updateChangeButton
];
440 [self updateStatusText
];
441 [addressTable reloadData
];
449 pid_t pid
= (pid_t
)PID_SELECTED
;
452 kern_return_t result
;
454 char unsigned *string8bit
= (char unsigned *)[[changeTextField stringValue
] lossyCString
];
455 long unsigned stringSize
= strlen( string8bit
);
456 char integer8bit
= (char)[changeTextField intValue
];
457 short integer16bit
= (short)[changeTextField intValue
];
458 long integer32bit
= (long)[changeTextField intValue
];
459 long long integer64bit
= (long long)[changeTextField intValue
];
460 float float32bit
= (float)[changeTextField floatValue
];
461 double float64bit
= (double)[changeTextField doubleValue
];
463 NSEnumerator
*enumerator
= [addressTable selectedRowEnumerator
];
466 if ( (result
= task_for_pid( current_task(), pid
, &task
)) != KERN_SUCCESS
)
468 NSLog( @
"task_for_pid returned error: %i", result
);
472 while ( row
= [enumerator nextObject
] )
474 long unsigned item
= [[addressList objectAtIndex
:[row intValue
]] unsignedLongValue
];
476 //NSLog( @"address: %X", item );
478 switch ( TYPE_SELECTED
)
481 switch ( SIZE_SELECTED
)
485 result
= vm_write( task
, (vm_address_t
)item
, (vm_offset_t
)string8bit
, (mach_msg_type_number_t
)stringSize
);
492 switch ( SIZE_SELECTED
)
496 result
= vm_write( task
, (vm_address_t
)item
, (vm_offset_t
)(&integer8bit
), sizeof(char) );
502 result
= vm_write( task
, (vm_address_t
)item
, (vm_offset_t
)(&integer16bit
), sizeof(short) );
508 result
= vm_write( task
, (vm_address_t
)item
, (vm_offset_t
)(&integer32bit
), sizeof(long) );
514 result
= vm_write( task
, (vm_address_t
)item
, (vm_offset_t
)(&integer64bit
), sizeof(long long) );
521 switch ( SIZE_SELECTED
+2 )
525 result
= vm_write( task
, (vm_address_t
)item
, (vm_offset_t
)(&float32bit
), sizeof(float) );
531 result
= vm_write( task
, (vm_address_t
)item
, (vm_offset_t
)(&float64bit
), sizeof(double) );
541 - (void)updateProcessPopup
545 [processPopup setEnabled
:NO
];
549 [processPopup setEnabled
:YES
];
553 - (void)updateTypePopup
555 if ( cheating || searching
)
557 [typePopup setEnabled
:NO
];
561 int selected
= [typePopup indexOfSelectedItem
];
563 [typePopup setEnabled
:YES
];
565 [typePopup removeAllItems
];
567 [typePopup addItemWithTitle
:@
"String"];
568 [typePopup addItemWithTitle
:@
"Integer"];
569 [typePopup addItemWithTitle
:@
"Float"];
571 [typePopup selectItemAtIndex
:selected
];
575 - (void)updateSizePopup
577 if ( cheating || searching
)
579 [sizePopup setEnabled
:NO
];
583 [sizePopup setEnabled
:YES
];
585 [sizePopup removeAllItems
];
587 switch ( TYPE_SELECTED
)
590 [sizePopup addItemWithTitle
:@
" 8-bit"];
594 [sizePopup addItemWithTitle
:@
" 8-bit"];
595 [sizePopup addItemWithTitle
:@
"16-bit"];
596 [sizePopup addItemWithTitle
:@
"32-bit"];
597 [sizePopup addItemWithTitle
:@
"64-bit"];
601 [sizePopup addItemWithTitle
:@
"32-bit"];
602 [sizePopup addItemWithTitle
:@
"64-bit"];
608 - (void)updateSearchButton
612 [searchTextField setEnabled
:NO
];
613 [searchButton setEnabled
:NO
];
617 [searchTextField setEnabled
:YES
];
618 [searchButton setEnabled
:YES
];
622 - (void)updateChangeButton
624 if ( [addressTable selectedRow
] == -1 || searching
)
626 [changeTextField setEnabled
:NO
];
627 [changeButton setEnabled
:NO
];
631 [changeTextField setEnabled
:YES
];
632 [changeButton setEnabled
:YES
];
636 - (void)updateStatusText
640 [statusText setStringValue
:@
"Searching..."];
642 else if ( !cheating
)
644 [statusText setStringValue
:[NSString stringWithFormat
:@
"PID: %i", PID_SELECTED
]];
648 [statusText setStringValue
:[NSString stringWithFormat
:@
"Found: %i", [addressList count
]]];
651 [statusText display
];
655 - (void)processListChanged
:(NSNotification
*)note
657 if ( cheating
&& [[note name
] isEqualToString
:@
"NSWorkspaceDidTerminateApplicationNotification"] )
659 int pid
= PID_SELECTED
;
660 int other
= [[[note userInfo
] objectForKey
:@
"NSApplicationProcessIdentifier"] intValue
];
662 // check to make sure the program we were cheating wasn't the one that quit
665 // it was, so let's take care of it
666 NSBeginAlertSheet( @
"", @
"OK", nil, nil, window
, nil, nil, nil, 0, @
"The application that was being cheated has quit." );
672 [self rebuildProcessList
];
673 [self updateProcessPopup
];
674 [self updateStatusText
];
678 - (void)rebuildProcessList
680 NSString
*selected
= [[processPopup titleOfSelectedItem
] retain
];
683 [processList release
];
684 processList
= [[[NSWorkspace sharedWorkspace
] launchedApplications
] retain
];
686 max
= [processList count
];
688 [processPopup setImagePosition
:NSImageOverlaps
];
690 [processPopup removeAllItems
];
692 for ( i
= 0; i
< max
; i
++ )
694 NSString
*name
= [[processList objectAtIndex
:i
] objectForKey
:@
"NSApplicationName"];
695 NSString
*path
= [[processList objectAtIndex
:i
] objectForKey
:@
"NSApplicationPath"];
697 NSImage
*image
= [[NSWorkspace sharedWorkspace
] iconForFile
:path
];
699 [processPopup addItemWithTitle
:name
];
701 [image setScalesWhenResized
:YES
];
702 [image setSize
:NSMakeSize( 16.0, 16.0 )];
704 [[processPopup itemAtIndex
:i
] setImage
:image
];
706 if ( [selected isEqualToString
:[processPopup itemTitleAtIndex
:i
]] )
708 [processPopup selectItemAtIndex
:i
];
720 [[[NSWorkspace sharedWorkspace
] notificationCenter
] removeObserver
:self];
722 [processList release
];
728 - (IBAction
)processPopup
:(id)sender
732 [self updateStatusText
];
735 - (IBAction
)typePopup
:(id)sender
737 [self updateSizePopup
];
740 - (IBAction
)searchButton
:(id)sender
742 if ( [[searchTextField stringValue
] isEqualToString
:@
""] )
750 // update the interface
751 [statusBar startAnimation
:self];
752 [self updateProcessPopup
];
753 [self updateSearchButton
];
754 [self updateTypePopup
];
755 [self updateSizePopup
];
756 [self updateChangeButton
];
757 [self updateStatusText
];
763 [NSThread detachNewThreadSelector
:@selector(firstSearch
:) toTarget
:self withObject
:nil];
767 [NSThread detachNewThreadSelector
:@selector(search
:) toTarget
:self withObject
:nil];
771 pid_t pid = (pid_t)PID_SELECTED;
774 kern_return_t result;
777 addressList = [[NSMutableArray alloc] init];
779 result = task_for_pid( current_task(), pid, &task );
781 if ( result == KERN_SUCCESS )
782 NSLog( @"KERN_SUCCESS" );
783 else if ( result == KERN_INVALID_ADDRESS )
784 NSLog( @"KERN_INVALID_ADDRESS" );
785 else if ( result == KERN_INVALID_ARGUMENT )
786 NSLog( @"KERN_INVALID_ARGUMENT" );
787 else if ( result == KERN_PROTECTION_FAILURE )
788 NSLog( @"KERN_PROTECTION_FAILURE" );
789 else if ( result == KERN_NO_SPACE )
790 NSLog( @"KERN_NO_SPACE" );
792 if ( ptrace( PT_ATTACH, pid, 0, 0 ) != -1 )
794 if ( waitpid( pid, &waitStatus, WUNTRACED ) == pid )
796 if ( WIFSTOPPED(waitStatus) )
798 NSLog( @"process stopped" );
802 NSLog( @"process didn't stop" );
806 vm_address_t address = 0x1b000;
808 vm_region_basic_info_data_t info;
809 mach_msg_type_number_t infoCnt = 8;
810 mach_port_t object_name = 0;
812 BOOL canRead, canWrite, canExecute;
817 NSLog( @"pid: %i, task: %i", pid, task );
819 result = vm_region( task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)(&info), &infoCnt, &object_name );
821 NSLog( @"info count: %i", (int)infoCnt );
823 if ( result == KERN_SUCCESS )
824 NSLog( @"KERN_SUCCESS" );
825 else if ( result == KERN_INVALID_ADDRESS )
826 NSLog( @"KERN_INVALID_ADDRESS" );
827 else if ( result == KERN_INVALID_ARGUMENT )
828 NSLog( @"KERN_INVALID_ARGUMENT" );
829 else if ( result == KERN_PROTECTION_FAILURE )
830 NSLog( @"KERN_PROTECTION_FAILURE" );
831 else if ( result == KERN_NO_SPACE )
832 NSLog( @"KERN_NO_SPACE" );
834 NSLog( @"address: %X, size: %i", address, size );
836 canRead = info.protection & VM_PROT_READ;
837 canWrite = (info.protection & VM_PROT_WRITE) >> 1;
838 canExecute = (info.protection & VM_PROT_EXECUTE) >> 2;
841 NSLog( @"can read" );
843 NSLog( @"can write" );
845 NSLog( @"can execute" );
847 data = (char unsigned *)malloc( size );
850 result = vm_read_overwrite( task, address, size, (vm_address_t)data, &dataCnt );
852 if ( result == KERN_SUCCESS )
853 NSLog( @"KERN_SUCCESS" );
854 else if ( result == KERN_INVALID_ADDRESS )
855 NSLog( @"KERN_INVALID_ADDRESS" );
856 else if ( result == KERN_INVALID_ARGUMENT )
857 NSLog( @"KERN_INVALID_ARGUMENT" );
858 else if ( result == KERN_PROTECTION_FAILURE )
859 NSLog( @"KERN_PROTECTION_FAILURE" );
860 else if ( result == KERN_NO_SPACE )
861 NSLog( @"KERN_NO_SPACE" );
863 NSLog( @"data: %X, size: %i", (vm_address_t)data, dataCnt );
870 NSLog( @"waitpid() failed" );
873 ptrace( PT_DETACH, pid, 0, 0 );
877 NSLog( @"ptrace() failed" );
882 - (IBAction
)changeButton
:(id)sender
888 - (int)numberOfRowsInTableView
:(NSTableView
*)table
890 if ( cheating
&& !searching
)
891 return [addressList count
];
896 - (id)tableView
:(NSTableView
*)table objectValueForTableColumn
:(NSTableColumn
*)column row
:(int)row
898 return [NSString stringWithFormat
:@
"%X", [[addressList objectAtIndex
:row
] unsignedLongValue
]];
901 - (void)tableView
:(NSTableView
*) setObjectValue
:(id)object forTableColumn
:(NSTableColumn
*)column row
:(int)row
906 - (void)tableViewSelectionDidChange
:(NSNotification
*)note
908 [self updateChangeButton
];