////////////////////////////////////////////////////////////////////////// // // class CWinDB // ////////////////////////////////////////////////////////////////////////// WINDB_API CWinDB::CWinDB(LPCTSTR lpszDB/* = NULL*/): m_inst(lpszDB) { Reset(true); JET_ERR err = JetInit(m_inst); if (err != JET_errSuccess){ throw CWinDBErrExp(err); } m_lpSes = m_inst.NewSession(); }
HRESULT DAPI EseBeginSession( __out JET_INSTANCE *pjiInstance, __out JET_SESID *pjsSession, __in_z LPCWSTR pszInstance, __in_z LPCWSTR pszPath ) { HRESULT hr = S_OK; JET_ERR jEr = JET_errSuccess; LPSTR pszAnsiInstance = NULL; LPSTR pszAnsiPath = NULL; hr = DirEnsureExists(pszPath, NULL); ExitOnFailure(hr, "Failed to ensure database directory exists"); // Sigh. JETblue requires Vista and up for the wide character version of this function, so we'll convert to ANSI before calling, // likely breaking everyone with unicode characters in their path. hr = StrAnsiAllocString(&pszAnsiInstance, pszInstance, 0, CP_ACP); ExitOnFailure(hr, "Failed converting instance name to ansi"); hr = StrAnsiAllocString(&pszAnsiPath, pszPath, 0, CP_ACP); ExitOnFailure(hr, "Failed converting session path name to ansi"); jEr = JetCreateInstanceA(pjiInstance, pszAnsiInstance); ExitOnJetFailure(jEr, hr, "Failed to create instance"); jEr = JetSetSystemParameter(pjiInstance, NULL, JET_paramSystemPath, NULL, pszAnsiPath); ExitOnJetFailure1(jEr, hr, "Failed to set jet system path to: %s", pszAnsiPath); // This makes sure log files that are created are created next to the database, not next to our EXE (note they last after execution) jEr = JetSetSystemParameter(pjiInstance, NULL, JET_paramLogFilePath, NULL, pszAnsiPath); ExitOnJetFailure1(jEr, hr, "Failed to set jet log file path to: %s", pszAnsiPath); jEr = JetSetSystemParameter(pjiInstance, NULL, JET_paramMaxOpenTables, 10, NULL); ExitOnJetFailure(jEr, hr, "Failed to set jet max open tables parameter"); // TODO: Use callback hooks so that Jet Engine uses our memory allocation methods, etc.? (search docs for "JET_PFNREALLOC" - there are other callbacks too) jEr = JetInit(pjiInstance); ExitOnJetFailure(jEr, hr, "Failed to initialize jet engine instance"); jEr = JetBeginSession(*pjiInstance, pjsSession, NULL, NULL); ExitOnJetFailure(jEr, hr, "Failed to begin jet session"); LExit: ReleaseStr(pszAnsiInstance); ReleaseStr(pszAnsiPath); return hr; }
/* * Intialize JET engine for NTDS files * (page_size=8192, no recovery) */ BOOL NTDS_ParserInit(s_parser *parser) { RtlZeroMemory(parser,sizeof(s_parser)); if(JetSetSystemParameter(&parser->instance,JET_sesidNil,JET_paramDatabasePageSize,8192,NULL)!=JET_errSuccess) return FALSE; if(JetCreateInstance(&parser->instance,APP_JET_INSTANCE_STR)!=JET_errSuccess) return FALSE; if(JetSetSystemParameter(&parser->instance,JET_sesidNil,JET_paramRecovery,NULL,"Off")!=JET_errSuccess) return FALSE; if(JetInit(&parser->instance)!=JET_errSuccess) return FALSE; return TRUE; }
int main(int argc, char * argv[]) { //Linked list to contain the datatable columns metadata typedef struct _COLUMNLIST { int type; int id; char name[NAME_SIZE]; struct _COLUMNLIST * next; }COLUMNLIST; COLUMNLIST *columnList; COLUMNLIST *listHead = (COLUMNLIST *)malloc(sizeof(COLUMNLIST)); JET_ERR err; JET_INSTANCE instance = JET_instanceNil; JET_SESID sesid; JET_DBID dbid; JET_TABLEID tableid ; /* JET_COLUMNDEF *columndefid = malloc(sizeof(JET_COLUMNDEF)); JET_COLUMNDEF *columndeftype = malloc(sizeof(JET_COLUMNDEF)); JET_COLUMNDEF *columndeftypecol = malloc(sizeof(JET_COLUMNDEF)); JET_COLUMNDEF *columndefname = malloc(sizeof(JET_COLUMNDEF)); JET_COLUMNDEF *columndefobjid = malloc(sizeof(JET_COLUMNDEF)); */ JET_COLUMNDEF _columndefid; JET_COLUMNDEF _columndeftype; JET_COLUMNDEF _columndeftypecol; JET_COLUMNDEF _columndefname; JET_COLUMNDEF _columndefobjid; JET_COLUMNDEF *columndefid = &_columndefid; JET_COLUMNDEF *columndeftype = &_columndeftype; JET_COLUMNDEF *columndeftypecol = &_columndeftypecol; JET_COLUMNDEF *columndefname = &_columndefname; JET_COLUMNDEF *columndefobjid = &_columndefobjid; unsigned long a,b,c,d,e; long bufferid[16]; char buffertype[256]; char buffertypecol[8]; char buffername[NAME_SIZE]; long bufferobjid[8]; //Actually max buffer size should depend on the page size but it doesn't. Further investigation required. unsigned char jetBuffer[JET_BUFFER_SIZE]; unsigned long jetSize; char *baseName = argv[2]; char *targetTable; char *tableName; unsigned int datatableId = 0xffffffff; unsigned int i; FILE *dump; char dumpFileName[64]; //SYSTEMTIME lt; RPC_WSTR Guid = NULL; LPWSTR stringSid = NULL; long long sd_id = 0; listHead->next = NULL; columnList = listHead; if( argc < 3) PrintUsage(); if(!strcmp(argv[1],"ad") || !strcmp(argv[1],"sid") || !strcmp(argv[1],"att") || !strcmp(argv[1],"cat") || !strcmp(argv[1],"users")) targetTable = "datatable"; else if(!strcmp(argv[1],"ace")) targetTable = "sd_table"; else PrintUsage(); if(!strcmp(argv[1],"sid")) { printf("To dump Exchange Mailbox security descriptors, \nenter the ATT value for your specific Exchange Schema:\n(msDS-IntId value for msExchMailboxSecurityDescriptor, \nfound in 'esent_dump att' results)\n"); printf("Otherwise just input anything and press enter\n"); scanf_s("%s",&exchangeMailboxSDCol[4], 28); } //Our result file, don't modify if you want to use auto import scripts from dbbrowser //GetLocalTime(<); //sprintf_s(dumpFileName, 64, "%s_ntds_%02d-%02d-%04d_%02dh%02d.csv",argv[1], lt.wDay, lt.wMonth, lt.wYear, lt.wHour, lt.wMinute); sprintf_s(dumpFileName, 64, "%s-ntds.dit-dump.csv", argv[1]); fopen_s(&dump, dumpFileName, "w"); if (dump == 0) { printf("Could not open csv file for writing\n"); return(-1); } if(!strcmp(argv[1],"ace")) fprintf(dump, "sd_id\tPrimaryOwner\tPrimaryGroup\tACEType\tACEFlags\tAccessMask\tFlags\tObjectType\tInheritedObjectType\tTrusteeSID\n"); // Initialize ESENT. // See http://msdn.microsoft.com/en-us/library/windows/desktop/gg269297(v=exchg.10).aspx for error codes err = JetSetSystemParameter(0, JET_sesidNil, JET_paramDatabasePageSize, 8192, NULL); err = JetCreateInstance(&instance, "blabla"); err = JetInit(&instance); err = JetBeginSession(instance, &sesid, 0, 0); err = JetAttachDatabase(sesid, baseName, JET_bitDbReadOnly); if (err != 0) { printf("JetAttachDatabase : %i\n", err); return(-1); } err = JetOpenDatabase(sesid, baseName, 0, &dbid, 0); if (err != 0) { printf("JetOpenDatabase : %i\n", err); return(-1); } //Let's enumerate the metadata about datatable (AD table) tableName = "MSysObjects"; err = JetOpenTable(sesid, dbid, tableName, 0, 0, JET_bitTableReadOnly, &tableid); printf("[*]Opened table: %s\n", tableName); //Obtain structures with necessary information to retrieve column values err = JetGetColumnInfo(sesid, dbid, tableName, "Id", columndefid, sizeof(JET_COLUMNDEF), JET_ColInfo); err = JetGetColumnInfo(sesid, dbid, tableName, "Type", columndeftype, sizeof(JET_COLUMNDEF), JET_ColInfo); err = JetGetColumnInfo(sesid, dbid, tableName, "ColtypOrPgnoFDP", columndeftypecol, sizeof(JET_COLUMNDEF), JET_ColInfo); err = JetGetColumnInfo(sesid, dbid, tableName, "Name", columndefname, sizeof(JET_COLUMNDEF), JET_ColInfo); err = JetGetColumnInfo(sesid, dbid, tableName, "ObjIdTable", columndefobjid, sizeof(JET_COLUMNDEF), JET_ColInfo); //printf("Type de colonne :%d, de longueur : %d", columndef->coltyp, columndef->cbMax); //Position the cursor at the first record JetMove(sesid, tableid, JET_MoveFirst, 0); //Retrieve columns metadata do { JetRetrieveColumn(sesid, tableid, columndefid->columnid, 0, 0, &a, 0, 0); JetRetrieveColumn(sesid, tableid, columndefid->columnid, bufferid, a, 0, 0, 0); JetRetrieveColumn(sesid, tableid, columndeftype->columnid, 0, 0, &b, 0, 0); JetRetrieveColumn(sesid, tableid, columndeftype->columnid, buffertype, b, 0, 0, 0); JetRetrieveColumn(sesid, tableid, columndeftypecol->columnid, 0, 0, &e, 0, 0); JetRetrieveColumn(sesid, tableid, columndeftypecol->columnid, buffertypecol, e, 0, 0, 0); JetRetrieveColumn(sesid, tableid, columndefname->columnid, 0, 0, &c, 0, 0); JetRetrieveColumn(sesid, tableid, columndefname->columnid, buffername, c, 0, 0, 0); buffername[c]='\0'; if(datatableId == 0xffffffff && !strcmp(buffername, targetTable)) { //We found the target table in the metadata, pickup its id and make another pass datatableId = bufferid[0]; printf("[*]%s tableID found : %d\n", buffername, datatableId); JetMove(sesid, tableid, JET_MoveFirst, 0); continue; } JetRetrieveColumn(sesid, tableid, columndefobjid->columnid, 0, 0, &d, 0, 0); JetRetrieveColumn(sesid, tableid, columndefobjid->columnid, bufferobjid, d, 0, 0, 0); //We got the correct type and table id, let's dump the column name and add it to the column list if(buffertype[0] == 2 && bufferobjid[0] == datatableId) { unsigned int j; columnList->next = (COLUMNLIST *)malloc(sizeof(COLUMNLIST)); if(!columnList->next) { printf("Memory allocation failed during metadata dump\n"); return(-1); } columnList = columnList->next; columnList->next = NULL; for(j=0;j<c;j++) columnList->name[j] = buffername[j]; columnList->name[c] = '\0'; columnList->type = buffertypecol[0]; columnList->id = bufferid[0]; } }while(JetMove(sesid, tableid, JET_MoveNext, 0) == JET_errSuccess); JetCloseTable(sesid, tableid); //Let's use our metadata to dump the whole AD schema tableName = targetTable; err = JetOpenTable(sesid, dbid, tableName, 0, 0, JET_bitTableReadOnly, &tableid); printf("[*]Opened table: %s\n", tableName); printf("Dumping %s column names...\n", tableName); columnList = listHead; while(columnList->next) { columnList = columnList->next; if(!strcmp("ad",argv[1])) fprintf(dump,"%d:%s\t",columnList->type,columnList->name); else if(ValidateColumn(argv[1], columnList->name)) fprintf(dump, "%s\t", translateATT(columnList->name)); }; fprintf(dump,"\n"); printf("Dumping content...\n"); JetMove(sesid, tableid, JET_MoveFirst, 0); do { columnList = listHead; while(columnList->next) { columnList = columnList->next; if(ValidateColumn(argv[1], columnList->name)) { //NOTE that this approach implies post processing multi valued columns if you re-use this code... err = JetRetrieveColumn(sesid, tableid, columnList->id, 0, 0, &jetSize, 0, 0); #ifdef _DEBUG //positive are warnings, -1047 is invalid buffer size which is expected here if (err < 0 && err != -1047) { printf("JetRetrieveColumn error : %i, jetSize : %d\n", err, jetSize); return(-2); } if (jetSize > JET_BUFFER_SIZE) { printf("Jet Buffer incorrect size preset: %d bytes are needed\n",jetSize); return(-2); } #endif memset(jetBuffer,0,JET_BUFFER_SIZE); switch(columnList->type) { //signed int types case 4: JetRetrieveColumn(sesid, tableid, columnList->id, jetBuffer, jetSize, 0, 0, 0); //Specific useraccountcontrol code, currently dead code if(!strcmp("users",argv[1]) && !strcmp("ATTj589832",columnList->name)) { if(jetBuffer[0] & ADS_UF_ACCOUNTDISABLE) fprintf(dump,"disabled "); if(jetBuffer[0] & ADS_UF_DONT_EXPIRE_PASSWD) fprintf(dump,"dontexpire "); if(jetBuffer[0] & ADS_UF_LOCKOUT) fprintf(dump,"lockedout "); if(jetBuffer[0] & ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED) fprintf(dump,"reversiblepwd "); } else fprintf(dump,"%d",*(int *)jetBuffer); /* fprintf(dump,"%u_",*(unsigned int *)jetBuffer); for(unsigned int i=0;i<jetSize;i++) fprintf(dump,"%.2X",jetBuffer[i]); */ break; //signed long long type case 5: JetRetrieveColumn(sesid, tableid, columnList->id, jetBuffer, jetSize, 0, 0, 0); if(!strcmp("sd_id",columnList->name)) sd_id = *(long long *)jetBuffer; else fprintf(dump,"%lld",*(long long *)jetBuffer); break; //Raw binary types case 9: JetRetrieveColumn(sesid, tableid, columnList->id, jetBuffer, jetSize, 0, 0, 0); for(i=0;i<jetSize;i++) fprintf(dump,"%.2X",jetBuffer[i]); break; case 11: /* We check matches on security descriptor, then SID * to display accordingly, otherwise hex dump */ JetRetrieveColumn(sesid, tableid, columnList->id, jetBuffer, jetSize, 0, 0, 0); if(!strcmp("sd_value",columnList->name) && IsValidSecurityDescriptor(jetBuffer)) { //Correct sd_id because sd_id column is before sd_value column in sd_table DumpACE(sd_id, jetBuffer, dump); } else if(!strcmp("ATTr589970",columnList->name) && IsValidSid(jetBuffer)) { //AD SID storage swaps endianness in RID bytes (yeah !) unsigned char temp; temp = jetBuffer[24]; jetBuffer[24] = jetBuffer[27]; jetBuffer[27] = temp; temp = jetBuffer[25]; jetBuffer[25] = jetBuffer[26]; jetBuffer[26] = temp; ConvertSidToStringSid((PSID)jetBuffer, &stringSid); fwprintf(dump, L"%s", stringSid); LocalFree(stringSid); stringSid = NULL; } //NT Security Descriptor index to lookup in sd_table else if(!strcmp("sid",argv[1]) && ( !strcmp("ATTp131353",columnList->name) || !strcmp(exchangeMailboxSDCol,columnList->name) )) { fprintf(dump,"%d",*(int *)jetBuffer); } //Schema-Id-Guid else if(!strcmp("sid",argv[1]) && !strcmp("ATTk589972",columnList->name) ) { UuidToString((UUID *)jetBuffer, &Guid); fwprintf(dump,L"%s",Guid); RpcStringFree(&Guid); Guid = NULL; } else //hex dump for(i=0;i<jetSize;i++) fprintf(dump,"%.2X",jetBuffer[i]); /* dumping type 11 as int (?) else { fprintf(dump,"%d",*(int *)jetBuffer); printf("dump type 11 as int : %d\n", *(int *)jetBuffer); } */ break; //widechar text types case 10: case 12: JetRetrieveColumn(sesid, tableid, columnList->id, jetBuffer, jetSize, 0, 0, 0); for(i=0;i<jetSize/2;i++) if((wchar_t)jetBuffer[2*i] != '\t' || (wchar_t)jetBuffer[2*i] != '\n' || (wchar_t)jetBuffer[2*i] != '\r') fwprintf(dump,L"%c",(wchar_t)jetBuffer[2*i]); break; }; if(strcmp("ace",argv[1])) fprintf(dump,"\t"); } } if(strcmp("ace",argv[1])) fprintf(dump,"\n"); }while(JetMove(sesid, tableid, JET_MoveNext, 0) == JET_errSuccess); // cleanup printf("cleaning...\n"); JetCloseTable(sesid, tableid); JetEndSession(sesid, 0); JetTerm(instance); fclose(dump); return 0; }