#include "kextfind_main.h"
#include "kextfind_report.h"
#include "kextfind_query.h"
#include "kextfind_commands.h"
#include "kext_tools_util.h"
#include <IOKit/kext/OSKext.h>
#include <IOKit/kext/OSKextPrivate.h>
#include <IOKit/kext/fat_util.h>
#include <IOKit/kext/macho_util.h>
Boolean reportParseProperty(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
uint32_t index = 1;
QEQueryElementSetPredicate(element, CFSTR(kPredNameProperty));
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
result = true;
finish:
*num_used += index;
return result;
}
Boolean reportParseShorthand(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
CFStringRef predicate = QEQueryElementGetPredicate(element);
uint32_t index = 1;
if (CFEqual(predicate, CFSTR(kPredNameBundleID))) {
QEQueryElementAppendArgument(element, kCFBundleIdentifierKey);
} else if (CFEqual(predicate, CFSTR(kPredNameBundleName))) {
QEQueryElementAppendArgument(element, kCFBundleNameKey);
} else if (CFEqual(predicate, CFSTR(kPredNameVersion))) {
QEQueryElementAppendArgument(element, kCFBundleVersionKey);
} else {
goto finish;
}
QEQueryElementSetPredicate(element, CFSTR(kPredNameProperty));
result = true;
finish:
*num_used += index;
return result;
}
char * cStringForCFValue(CFTypeRef value)
{
CFTypeID valueType;
CFIndex count;
char buffer[80];
if (!value) {
return strdup("<null>");
}
valueType = CFGetTypeID(value);
if (CFStringGetTypeID() == valueType) {
return createUTF8CStringForCFString(value);
} else if (CFBooleanGetTypeID() == valueType) {
return CFBooleanGetValue(value) ? strdup(kWordTrue) : strdup(kWordFalse);
} else if (CFNumberGetTypeID() == valueType) {
} else if (CFArrayGetTypeID() == valueType) {
count = CFArrayGetCount(value);
snprintf(buffer, (sizeof(buffer)/sizeof(char)), "<array of %ld>", count);
return strdup(buffer);
} else if (CFDictionaryGetTypeID() == valueType) {
count = CFDictionaryGetCount(value);
snprintf(buffer, (sizeof(buffer)/sizeof(char)), "<dict of %ld>", count);
return strdup(buffer);
} else if (CFDataGetTypeID() == valueType) {
count = CFDataGetLength(value);
snprintf(buffer, (sizeof(buffer)/sizeof(char)), "<data of %ld>", count);
return strdup(buffer);
} else {
return strdup("<unknown CF type>");
}
return NULL;
}
Boolean reportEvalProperty(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
QueryContext * context = (QueryContext *)user_data;
CFStringRef propKey = NULL; CFTypeRef propVal = NULL; char * cString = NULL;
propKey = QEQueryElementGetArgumentAtIndex(element, 0);
if (!propKey) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
if (!context->reportStarted) {
cString = createUTF8CStringForCFString(propKey);
if (!cString) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "",
cString);
} else {
propVal = OSKextGetValueForInfoDictionaryKey(theKext, propKey);
cString = cStringForCFValue(propVal);
if (!cString) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "",
cString);
}
context->reportRowStarted = true;
result = true;
finish:
if (cString) free(cString);
return result;
}
Boolean reportParseFlag(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
CFStringRef flag = QEQueryElementGetPredicate(element);
QueryContext * context = (QueryContext *)user_data;
uint32_t index = 1;
QEQueryElementSetPredicate(element, CFSTR(kPredNameFlag));
CFDictionarySetValue(element, CFSTR(kKeywordFlag), flag);
if (CFEqual(flag, CFSTR(kPredNameLoaded))) {
context->checkLoaded = true;
} else if (CFEqual(flag, CFSTR(kPredNameIntegrity))) {
context->checkIntegrity = true;
}
result = true;
*num_used += index;
return result;
}
Boolean reportEvalFlag(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
CFStringRef flag = CFDictionaryGetValue(element, CFSTR(kKeywordFlag));
QueryContext * context = (QueryContext *)user_data;
char * cString = NULL; Boolean print = true;
if (!context->reportStarted) {
if (CFEqual(flag, CFSTR(kPredNameLoaded))) {
cString = "Loaded";
} else if (CFEqual(flag, CFSTR(kPredNameValid))) {
cString = "Valid";
} else if (CFEqual(flag, CFSTR(kPredNameAuthentic))) {
cString = "Authentic";
} else if (CFEqual(flag, CFSTR(kPredNameDependenciesMet))) {
cString = "Dependencies Met";
} else if (CFEqual(flag, CFSTR(kPredNameLoadable))) {
cString = "Loadable";
} else if (CFEqual(flag, CFSTR(kPredNameWarnings))) {
cString = "Warnings";
} else if (CFEqual(flag, CFSTR(kPredNameIsLibrary))) {
cString = "Library";
} else if (CFEqual(flag, CFSTR(kPredNameHasPlugins))) {
cString = "Plugins";
} else if (CFEqual(flag, CFSTR(kPredNameIsPlugin))) {
cString = "Is Plugin";
} else if (CFEqual(flag, CFSTR(kPredNameHasDebugProperties))) {
cString = "Debug";
} else if (CFEqual(flag, CFSTR(kPredNameIsKernelResource))) {
cString = "Kernel Resource";
} else if (CFEqual(flag, CFSTR(kPredNameIntegrity))) {
cString = "Integrity";
} else if (CFEqual(flag, CFSTR(kPredNameExecutable))) {
cString = "Has Executable";
} else {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "", cString);
} else {
if (CFEqual(flag, CFSTR(kPredNameLoaded))) {
cString = OSKextIsLoaded(theKext) ? kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameValid))) {
cString = OSKextIsValid(theKext) ? kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameAuthentic))) {
cString = OSKextIsAuthentic(theKext) ? kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameDependenciesMet))) {
cString = OSKextResolveDependencies(theKext) ? kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameLoadable))) {
cString = OSKextIsLoadable(theKext) ?
kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameWarnings))) {
CFDictionaryRef warnings = OSKextCopyDiagnostics(theKext,
kOSKextDiagnosticsFlagWarnings);
cString = (warnings && CFDictionaryGetCount(warnings)) ?
kWordYes : kWordNo;
SAFE_RELEASE(warnings);
} else if (CFEqual(flag, CFSTR(kPredNameIsLibrary))) {
cString = (OSKextGetCompatibleVersion(theKext) > 0) ?
kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameHasPlugins))) {
CFArrayRef plugins = OSKextCopyPlugins(theKext);
cString = (plugins && CFArrayGetCount(plugins)) ?
kWordYes : kWordNo;
SAFE_RELEASE(plugins);
} else if (CFEqual(flag, CFSTR(kPredNameIsPlugin))) {
cString = OSKextIsPlugin(theKext) ? kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameHasDebugProperties))) {
cString = OSKextHasLogOrDebugFlags(theKext) ? kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameIsKernelResource))) {
cString = OSKextIsKernelComponent(theKext) ? kWordYes : kWordNo;
} else if (CFEqual(flag, CFSTR(kPredNameIntegrity))) {
printf("%s%s", context->reportRowStarted ? "\t" : "",
"n/a");
print = false;
} else if (CFEqual(flag, CFSTR(kPredNameExecutable))) {
cString = OSKextDeclaresExecutable(theKext) ? kWordYes : kWordNo;
}
if (print) {
if (!cString) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "",
cString);
}
}
context->reportRowStarted = true;
result = true;
finish:
return result;
}
Boolean reportParseArch(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
if (!argv[(*num_used) + 1]) {
goto finish;
}
CFDictionarySetValue(element, CFSTR("label"),
CFStringCreateWithCString(kCFAllocatorDefault,
argv[(*num_used) + 1], kCFStringEncodingUTF8));
result = parseArch(element, argc, argv, num_used, user_data, error);
if (!result) {
goto finish;
}
result = true;
finish:
return result;
}
Boolean reportEvalArch(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
CFStringRef string = NULL; char * cString = NULL;
if (!context->reportStarted) {
string = CFDictionaryGetValue(element, CFSTR("label"));
if (!string) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
cString = createUTF8CStringForCFString(string);
if (!cString) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "",
cString);
} else {
Boolean match = evalArch(element, object, user_data, error);
if (*error != kQEQueryErrorNone) {
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "",
match ? kWordYes : kWordNo);
}
context->reportRowStarted = true;
result = true;
finish:
if (cString) free(cString);
return result;
}
Boolean reportEvalArchExact(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
CFStringRef string = NULL; char * cString = NULL;
if (!context->reportStarted) {
string = CFDictionaryGetValue(element, CFSTR("label"));
if (!string) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
cString = createUTF8CStringForCFString(string);
if (!cString) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
printf("%s%s (only)", context->reportRowStarted ? "\t" : "",
cString);
} else {
Boolean match = evalArchExact(element, object, user_data, error);
if (*error != kQEQueryErrorNone) {
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "",
match ? kWordYes : kWordNo);
}
context->reportRowStarted = true;
result = true;
finish:
if (cString) free(cString);
return result;
}
Boolean reportParseDefinesOrReferencesSymbol(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
return parseDefinesOrReferencesSymbol(element, argc, argv, num_used,
user_data, error);
}
Boolean reportEvalDefinesOrReferencesSymbol(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
OSKextRef theKext = (OSKextRef)object;
QueryContext * context = (QueryContext *)user_data;
CFStringRef symbol = QEQueryElementGetArgumentAtIndex(element, 0);
char * cSymbol = NULL; const char * value = ""; fat_iterator fiter = NULL; struct mach_header * farch = NULL;
void * farch_end = NULL;
uint8_t nlist_type;
if (!symbol) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
cSymbol = createUTF8CStringForCFString(symbol);
if (!cSymbol) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
if (!context->reportStarted) {
printf("%ssymbol %s", context->reportRowStarted ? "\t" : "",
cSymbol);
} else {
fiter = createFatIteratorForKext(theKext);
if (!fiter) {
goto finish;
}
while ((farch = fat_iterator_next_arch(fiter, &farch_end))) {
macho_seek_result seek_result = macho_find_symbol(
farch, farch_end, cSymbol, &nlist_type, NULL);
if (seek_result == macho_seek_result_found_no_value ||
seek_result == macho_seek_result_found) {
if ((N_TYPE & nlist_type) == N_UNDF) {
value = OSKextIsKernelComponent(theKext) ?
"defines" : "references";
} else {
value = "defines";
}
result = true;
break;
}
}
}
printf("%s%s", context->reportRowStarted ? "\t" : "", value);
context->reportRowStarted = true;
result = true;
finish:
if (cSymbol) free(cSymbol);
return result;
}
Boolean reportParseCommand(
CFMutableDictionaryRef element,
int argc,
char * const argv[],
uint32_t * num_used,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
QueryContext * context = (QueryContext *)user_data;
CFStringRef command = QEQueryElementGetPredicate(element);
uint32_t index = 1;
if (CFEqual(command, CFSTR(kPredNamePrintProperty))) {
QEQueryElementSetPredicate(element, CFSTR(kPredNameProperty));
if (!parseArgument(element, &argv[index], &index, user_data, error)) {
goto finish;
}
} else if (CFEqual(command, CFSTR(kPredNamePrintIntegrity))) {
context->checkIntegrity = true;
}
CFDictionarySetValue(element, CFSTR(kKeywordCommand), command);
QEQueryElementSetPredicate(element, CFSTR(kPredNameCommand));
result = true;
finish:
*num_used += index;
return result;
}
Boolean reportEvalCommand(
CFDictionaryRef element,
void * object,
void * user_data,
QEQueryError * error)
{
Boolean result = false;
CFStringRef command = CFDictionaryGetValue(element, CFSTR(kKeywordCommand));
OSKextRef theKext = (OSKextRef)object;
QueryContext * context = (QueryContext *)user_data;
CFStringRef scratchString = NULL; char * cString = NULL;
Boolean print = true;
CFArrayRef dependencies = NULL; CFArrayRef dependents = NULL; CFArrayRef plugins = NULL; CFIndex count;
char buffer[80];
if (!context->reportStarted) {
if (CFEqual(command, CFSTR(kPredNamePrint)) ||
CFEqual(command, CFSTR(kPredNameBundleName))) {
cString = strdup("Bundle");
} else if (CFEqual(command, CFSTR(kPredNamePrintProperty))) {
result = reportEvalProperty(element, object, user_data, error);
goto finish;
} else if (CFEqual(command, CFSTR(kPredNamePrintArches))) {
cString = strdup("Arches");
} else if (CFEqual(command, CFSTR(kPredNamePrintDependencies))) {
cString = strdup("# Dependencies");
} else if (CFEqual(command, CFSTR(kPredNamePrintDependents))) {
cString = strdup("# Dependents");
} else if (CFEqual(command, CFSTR(kPredNamePrintPlugins))) {
cString = strdup("# Plugins");
} else if (CFEqual(command, CFSTR(kPredNamePrintIntegrity))) {
cString = strdup("Integrity");
} else if (CFEqual(command, CFSTR(kPredNamePrintInfoDictionary))) {
cString = strdup("Info Dictionary");
} else if (CFEqual(command, CFSTR(kPredNamePrintExecutable))) {
cString = strdup("Executable");
} else {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "", cString);
} else {
if (CFEqual(command, CFSTR(kPredNamePrint))) {
scratchString = copyPathForKext(theKext, context->pathSpec);
if (!scratchString) {
OSKextLogMemError();
}
cString = createUTF8CStringForCFString(scratchString);
} else if (CFEqual(command, CFSTR(kPredNameBundleName))) {
scratchString = copyPathForKext(theKext, kPathsNone);
if (!scratchString) {
OSKextLogMemError();
}
cString = createUTF8CStringForCFString(scratchString);
} else if (CFEqual(command, CFSTR(kPredNamePrintProperty))) {
result = reportEvalProperty(element, object, user_data, error);
goto finish;
} else if (CFEqual(command, CFSTR(kPredNamePrintArches))) {
printf("%s", context->reportRowStarted ? "\t" : "");
printKextArches(theKext, 0, false );
print = false;
} else if (CFEqual(command, CFSTR(kPredNamePrintDependencies))) {
dependencies = OSKextCopyAllDependencies(theKext,
false);
count = dependencies ? CFArrayGetCount(dependencies) : 0;
snprintf(buffer, (sizeof(buffer)/sizeof(char)), "%ld", count);
cString = strdup(buffer);
} else if (CFEqual(command, CFSTR(kPredNamePrintDependents))) {
dependencies = OSKextCopyDependents(theKext, false);
count = dependencies ? CFArrayGetCount(dependencies) : 0;
snprintf(buffer, (sizeof(buffer)/sizeof(char)), "%ld", count);
cString = strdup(buffer);
} else if (CFEqual(command, CFSTR(kPredNamePrintPlugins))) {
plugins = OSKextCopyPlugins(theKext);
count = plugins ? CFArrayGetCount(plugins) : 0;
snprintf(buffer, (sizeof(buffer)/sizeof(char)), "%ld", count);
cString = strdup(buffer);
SAFE_RELEASE(plugins);
} else if (CFEqual(command, CFSTR(kPredNamePrintIntegrity))) {
printf("%s%s", context->reportRowStarted ? "\t" : "",
"n/a");
print = false;
} else if (CFEqual(command, CFSTR(kPredNamePrintInfoDictionary))) {
scratchString = copyKextInfoDictionaryPath(theKext, context->pathSpec);
if (!scratchString) {
OSKextLogMemError();
}
cString = createUTF8CStringForCFString(scratchString);
} else if (CFEqual(command, CFSTR(kPredNamePrintExecutable))) {
scratchString = copyKextExecutablePath(theKext, context->pathSpec);
if (!scratchString) {
OSKextLogMemError();
}
cString = createUTF8CStringForCFString(scratchString);
} else {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
if (print) {
if (!cString) {
*error = kQEQueryErrorEvaluationCallbackFailed;
goto finish;
}
printf("%s%s", context->reportRowStarted ? "\t" : "",
cString);
}
}
context->reportRowStarted = true;
result = true;
finish:
SAFE_RELEASE(scratchString);
SAFE_FREE(cString);
SAFE_RELEASE(dependencies);
SAFE_RELEASE(dependents);
return result;
}