Jump to content

EXE back to buildable project


Recommended Posts

3 hours ago, hooovahh said:

Years ago we were in a meeting with a few LabVIEW champions and LabVIEW R&D ...

I don't know if that was the same meeting I was in or if I was pulled in after the fact, but that was where I tried to argue against having password protection at all. The answer I got back was, "This isn't a security feature. It's a feature to keep developers and production line techs from accidentally modifying VIs they didn't intend to modify, and providing a way (by using the common password) to unlock specific subsets of VIs when editing is desired."

That seemed like a useful concept to me. Ever since then, I've been fine with basic security around the password, as long as we make it clear to users that the password isn't intended to protect intellectual property. And that's what we do:

Quote

From our online help for "Creating Password-Protected VIs":

Caution  VI password protection does not encrypt block diagrams. For maximum security, remove the block diagrams from your VIs. Refer to the KnowledgeBase at ni.com for more information about the security differences between password protection and removing block diagrams.

There's a lot more detail in that KB entry. We document this in a few other places as well.

Edited by Aristos Queue
Link to comment
9 minutes ago, Aristos Queue said:

That seemed like a useful concept to me. Ever since then, I've been fine with basic security around the password, as long as we make it clear to users that the password isn't intended to protect intellectual property.

Not trying to derail the thread even more, but every time I hear that argument I say that is why you can lock a VI without passwording it.  Which is what my Pre-Build action on building a package does.  Need to edit it and do a test?  Sure just unlock it.  Drilling down into a VI and not realize it is part of the reuse library?  You will when you see it is locked.  But whatever.

I still tell the quote from NI R&D saying off the record that the protection you get from password protecting a VI, is about the level of protection you get from tissue paper. 

Link to comment

I implemented both interface counting and sequential check (called it brute-force). Will try to check whether there's a pattern in interface selection - I would prefer not to base that on guessing, as I'd like a tool which exports the VI to a set of XMLs and BINs, and then re-creates VI from scratch, using only the exported files.

I could make the "salt interface index" a part of exported XMLs. But maybe the pattern is simple.

Link to comment
On 11/4/2019 at 1:14 PM, hooovahh said:

Not trying to derail the thread even more, but every time I hear that argument I say that is why you can lock a VI without passwording it.  Which is what my Pre-Build action on building a package does.  Need to edit it and do a test?  Sure just unlock it.  Drilling down into a VI and not realize it is part of the reuse library?  You will when you see it is locked.  But whatever.

I still tell the quote from NI R&D saying off the record that the protection you get from password protecting a VI, is about the level of protection you get from tissue paper. 

Just locking doesn't suffice:

1. It doesn't give you the ability to unlock specific subsets of VIs.

2. It doesn't keep production line engineers from "just unlocking it"

Link to comment
14 hours ago, Aristos Queue said:

Just locking doesn't suffice:

It really depends on what you are trying to do so I get that.  For me even just setting the VI file to read-only would be enough, but I ran into a few times when a mass compile would want to overwrite the VI despite it having separate compile code, but that was years ago.  For me the purpose was that a developer would be drilling into the code and not realize they were in a reuse function and would start messing around with it and changing things that will now make the program behave differently on one developers machine, than the others.  A gentle reminder to not mess with something was all we needed.  But I get your points.

  • Like 1
Link to comment
9 hours ago, hooovahh said:

It really depends on what you are trying to do so I get that. 

Different users, different use cases... and for some, the passwords have real value. So they linger.

Just occurred to me: maybe we should call it something other than a "password", since that sounds like security. Instead of "Set password", call it "Join editing region". Instead of "Enter password", use "Enable editing for region". It preserves the functionality but steps us away from this constant drumbeat of "your security is broken!"

Link to comment

Back to the salt - the algorithm seem to use some additional data to select which interface is used. It may be some kind of count.

I executed my reader on all the VIs built into LabView 2014 Well not quite.. I was too lazy to extract VIs from LLBs. But it was still over 13000 files. Anyway, in large majority of cases the counts were taken from LAST interface. For less than 4% only zeros were used instead, and for less than 1% - the interface used was previous to last, not the last. There were also single cases where even earlier interface was used.

If anyone would like to take a look, attached it the result of the following commands:

find ./vi.lib -name '*.vi' -o  -name '*.ctl' | sed 's/'"'"'/\\'"'"'/g' | xargs -I {} ./readRSRC.py -vvv -p -i '{}' 2>&1 | tee log_vi_lib.txt

sed -n 's/^.*: \(Found matching salt .*\)$/\1/p' log_vi_lib.txt | sort | uniq -c

Figuring out the specifics of interface selection would require deep dive into RE libraries, so I'll skip it for now.

Now I want to make a function to export the data into some modificable form, and re-import again into proper VI. I will leave most data in binary form, only the parts I need will be fully parsed.

Any comments / advice?

lv14_builtin_vi_lib_all_salts.txt

Link to comment
On 11/8/2019 at 1:00 AM, Mefistotelis said:

Back to the salt - the algorithm seem to use some additional data to select which interface is used. It may be some kind of count.

Figuring out the specifics of interface selection would require deep dive into RE libraries, so I'll skip it for now.
...
Any comments / advice?

Well, in case you ever consider going that way, I'll recommend you start by looking at the LinkIdentity parts of the code ;)

Another vector for information could also be to look at the codestreams in the "Ned, the friendly debugger" interface.
While I haven't peeked much at Flarn's later progress, I do know that NED will let you switch the format of some VI resources into XML (Heap Save Format) - dunno if Flarn is utilizing that?!
(be warned though - this will most likely certainly cause LabVIEW to crash if trying to load the VI afterwards)

Also, for quick low-level access to the Resource Fork of LabVIEW VI's and a lot of other NI resource files -from inside LabVIEW- I suggest using the REdLoadResFile/REdSaveResFile (interface)functions found in LabVIEW.exe.
That at least cut away one level of abstraction for me, back when I had the time to immerse myself in this kind of 'research'.

Now off to figure out the "Keep code streams for heap peek" option..

Edited by Stinus Olsen
Added REdLoadResFile/REdSaveResFile info..
  • Like 1
Link to comment

Thanks @Stinus Olsen, will look into some of these.

 

The tool I made can now extract and re-create most VIs, like this:

./readRSRC.py -vvv -x -i './examples/empty_vifile_lv14f1.vi'
./readRSRC.py -vvv -c -m './empty_vifile_lv14f1.xml'
cmp -l './examples/empty_vifile_lv14f1.vi' './empty_vifile_lv14f1.vi'

Though there are still a few for which `cmp` shows difference between original file and re-created one (I've run it on the standard VIs from LV2014, on thousands of files only a few had differences).

Also, it currently leaves all Blocks as BIN files - does not parse their content.

Edited by Mefistotelis
  • Thanks 1
Link to comment
  • 2 weeks later...

How cute - NI is protecting some values stored in memory at runtime by XOR'ing them with seed which depends on the VMA.

Here's what it does to an MD5 checksum stored at `ptr` (hence size=16), code comes from LV14:

  seed = ptr ^ 0xDEADCAFE;
  i = 0;
  do
  {
    *(uint8_t *)(i++ + ptr) ^= seed;
    seed >>= 1;
  }
  while ( i < 16 );

 

Link to comment
  • 3 weeks later...

I need some example files to test my tool.

I am running it on all the LV14 standard VIs, but it looks like these are not using all possible features of the VI format.

In particular, I am not seeing use of some Refnum connectors. For example the type which 'Vi Explorer' calls "queue".

Anyone knows what to click in LabVIEW to get such connector within the VI file?

EDIT: Forced myself to read LabView help, now I know how the Queue works.

Still didn't found some refnums in documentation, ie. Device Refnum.

Edited by Mefistotelis
Link to comment

While I'm still working on parsers for all types of VI connectors, I also noticed the VICD block. Some old articles on its content:

https://web.archive.org/web/20110101230244/http://zone.ni.com/devzone/cda/tut/p/id/5315

https://web.archive.org/web/20120115152126/http://www.ni.com/devzone/lvzone/dr_vi_archived6.htm

Not sure if I'll be decoding that section further though - I believe the connectors block and default data block will be the only ones required to re-create front panel.

 

The binary format of Front Panel should be easy to figure out by comparing binary data to the XML representation which can be generated in newer LV versions; anybody tried that?

 

Link to comment
  • 3 weeks later...

Working on Front Panel now. This is what pylabview generates:

<?xml version='1.0' encoding='utf-8'?>
<SL__rootObject ScopeInfo="0" class="oHExt" uid="1">
  <root ScopeInfo="0" class="supC" uid="10">
    <objFlags ScopeInfo="1">010000</objFlags>
    <bounds ScopeInfo="1">0000000000000000</bounds>
    <MouseWheelSupport ScopeInfo="1">00</MouseWheelSupport>
    <ddoList ScopeInfo="0" elements="61">
      <SL__arrayElement ScopeInfo="1" uid="64" />
      <SL__arrayElement ScopeInfo="1" uid="96" />

And this is the same part generated by NED within LabView:

<SL__rootObject class="oHExt" uid="1">
  <root class="supC" uid="10">
    <objFlags>65536</objFlags>
    <bounds>(0, 0, 0, 0)</bounds>
    <MouseWheelSupport>0</MouseWheelSupport>
    <ddoList elements="61">
      <SL__arrayElement uid="64"/>
      <SL__arrayElement uid="96"/>

 

Link to comment
  • 1 month later...

Front Panel is now proper XML (though I only support "FPHb" now, older Labview has FPHP instead, and latest ones use FPHc - those are not parsed, as I don't really need them for my use).

Block Diagram is stored in exactly the same way, so I got "BDHb" support for free.

I used the same general format LabVIEWs NED uses for XML panels.

 

I can now either work to read "DFDS" section as well - it's quite complex as it isn't stand-alone section, meaning it needs data from other sections to parse.

Or I can ignore default data, and start working on Front Panel re-creation without that.

 

Link to comment
  • 1 month later...
On 11/2/2019 at 1:30 AM, Mefistotelis said:

I'm now baffled with how connector entries which affect the checksum are selected. It looks like one of interface connectors is used (also referred to as Terminal connector), but I have no idea how to pick which of the interfaces will be used.

To answer myself here:

- VCTP (VI Consolidated Types) ends with an array of "top level" types - the ones which are used in other sections.

- The top level type ID of the type which is used for the salt is stored in CPC2.

- The TypeID values used in diagrams are mapped through another level - DTHP contains list of top level types for that.

 

Btw, I now have Default Fill of Data Space figured out. Here's LabVIEW on the right, and extracted VI file with the values on the left.

 

labview_data_space_fill_xml.png

Edited by Mefistotelis
Link to comment
  • 1 month later...

If a VI is compiled for current platform, isn't the initialization code arbitrarly executed when VI is being loaded in LV? Isn't that like, very bad?

I mean, I could place a copy of Back Orifice there. The community here is exchanging VIs all the time, it would destroy the trust completely if a bad actor would do that.

And NI engineers are loading VIs from users as well, right? For example there is the version conversion forum.. I wonder how many of them have source code on the same computers. That would be a massive leak.

Though I must say I didn't checked if it's really executed, that isn't my point of interest.

 

Anyway, I'm near to finishing my involvement with LabVIEW. Will soon decide what to publish (most of what I did is already published).

Link to comment
3 hours ago, Mefistotelis said:

If a VI is compiled for current platform, isn't the initialization code arbitrarly executed when VI is being loaded in LV? Isn't that like, very bad?

I mean, I could place a copy of Back Orifice there. The community here is exchanging VIs all the time, it would destroy the trust completely if a bad actor would do that.

And NI engineers are loading VIs from users as well, right? For example there is the version conversion forum.. I wonder how many of them have source code on the same computers. That would be a massive leak.

Though I must say I didn't checked if it's really executed, that isn't my point of interest.

 

Anyway, I'm near to finishing my involvement with LabVIEW. Will soon decide what to publish (most of what I did is already published).

https://www.cvedetails.com/vulnerability-list/vendor_id-12786/product_id-25696/NI-Labview.html

Link to comment
  • 1 month later...

Mefistotelis

Hi! Did you try to do the similar operation with packed library (*.lvlibp)? I mean building it from a common .lvlib with any VIs inside, unpacking it into the initial VIs and rebuilding again. I just tried and it doesn't go well. For that I especially installed LV 2014 to have the library's resources in convenient LIBPLBVW and not in modern LEIF Fast File Format. This is what I did:

1. Made a .lvlibp build with one .lvlib, having one super-simple test VI inside.

2. Unpacked that .lvlibp with 7-Zip.

3. Grabbed \.rsrc\0\RCDATA\2 file and fed it into my own extractor (written a long ago) and finally got un-CRC-ed .zip archive.

4. Unpacked .zip and got NI_Embedded_Library.xml and my test VI.

Pretty the same steps, that I did many times to get the original VIs, CTLs etc. from a common EXE app. But that unpacked VI didn't want to load and reported, that it cannot find the owning packed library. Okay, then I created a .lvlib from NI_Embedded_Library.xml simply renaming it and fixing the URL path, it was referring to. Besides of that I also corrected the path in LIBN resource to point to that new .lvlib instead of the original .lvlibp. So after these manipulations the VI started to ask for some absent resource to load. So, to get it working I had to:

- add VCTP block from the original VI to the unpacked VI;

- replace LVSR and BDPW blocks with those from the original VI (to avoid 'tampered with password' message);

- replace LIvi block with that from the original VI;

- remove LIBN (to get the VI untied from any .lvlib(p)) (optional step, maybe).

I wonder, if there's some easier way to get the VI(s) workable, because for some third party .lvlibp it would be impossible to do, not having the original sources (to read out VCTP at least). Do you have any insights or thoughts on it?

Link to comment

Ok, here's what I did:

I found a lvlibp file in my LV14 installation, and extracted it:

$ file lv_icon.lvlibp
lv_icon.lvlibp: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows
$ wrestool -x --raw lv_icon.lvlibp -o ./
$ ls -l lv_icon*
-rwxr-xr-x 1 mefisto None 5377536 2014-06-25  lv_icon.lvlibp
-rw-r--r-- 1 mefisto None 5375712 06-10 12:47 lv_icon.lvlibp_10_2_0
-rw-r--r-- 1 mefisto None     704 06-10 12:47 lv_icon.lvlibp_16_1

Then checked the RSRC file from inside:

$ file lv_icon.lvlibp_10_2_0
lv_icon.lvlibp_10_2_0: National Instruments,
$ ./readRSRC.py -x -i 'lv_icon.lvlibp'
Error: [Errno RSRC {:d} Header sanity check failed.] 0

So, I never tried that before, and my tool doesn't currently support these files.

But it should be an easy fix, so I will patch it and get back to you with more info.

For fixing 'tampered with password' message - what I do is just removing the file from library when in extracted form (can't remember exactly, but I think 3 changes are required, one of them is removal of the LIBN which you mentioned).

Btw, NI is inconsistent here - they say the password is just 'unintended modification' avoidance, but the 'tampered' message suggests the intent for creating that functionality was to provide some impression of security.

EDIT: Fixed it!

Now I'm getting:

$ ./readRSRC.py -vv -x -i 'lv_icon.lvlibp_10_2_0'
lv_icon.lvlibp_10_2_0: Starting file parse for RSRC extraction
lv_icon.lvlibp_10_2_0: Block 'LVzp' index 0 recognized
lv_icon.lvlibp_10_2_0: Block b'LVzp' max data size set to 5273600 bytes
lv_icon.lvlibp_10_2_0: Block b'DATA' max data size set to 5375472 bytes
lv_icon.lvlibp_10_2_0: Writing block b'LVzp'
lv_icon.lvlibp_10_2_0: Storing block b'LVzp' section 0 binary in 'lv_icon_LVzp.bin'
lv_icon.lvlibp_10_2_0: Writing block b'DATA'
lv_icon.lvlibp_10_2_0: Storing block b'DATA' section 0 binary in 'lv_icon_DATA0.bin'
lv_icon.lvlibp_10_2_0: Storing block b'DATA' section 1 binary in 'lv_icon_DATA1.bin'
lv_icon.lvlibp_10_2_0: Storing block b'DATA' section 2 binary in 'lv_icon_DATA2.bin'
lv_icon.lvlibp_10_2_0: Storing block b'DATA' section 3 binary in 'lv_icon_DATA3.bin'
lv_icon.lvlibp_10_2_0: Storing block b'DATA' section 4 binary in 'lv_icon_DATA4.bin'
lv_icon.xml: Writing binding XML

The ZIP is auto-decrypted, so we can now extract it:

$ file lv_icon_LVzp.bin
lv_icon_LVzp.bin: Zip archive data, at least v2.0 to extract
# unzip lv_icon_LVzp.bin
Archive:  lv_icon_LVzp.bin
 extracting: NI_Embedded_Library.xml
 extracting: 1abvi3w/resource/dialog/lvconfig.llb/LV Config Read Boolean.vi
 extracting: 1abvi3w/resource/dialog/lvconfig.llb/LV Config Read Color.vi
 extracting: 1abvi3w/resource/dialog/lvconfig.llb/LV Config Read String.vi
 extracting: 1abvi3w/resource/dialog/lvconfig.llb/LV Config Write Boolean.vi
 extracting: 1abvi3w/resource/dialog/lvconfig.llb/LV Config Write Color.vi
 extracting: 1abvi3w/resource/dialog/lvconfig.llb/LV Config Write String.vi
[...]

Will update after I look at the files I got.

EDIT2: Looked at the files:

The only real issue is lack of VCTP section. The rest of removing the VI from library is trivial, if you check how the file looks before and after compiling the library.

VCTP sections from all files seem to be merged together (after all it stands for VI Consolidated Types), and stored in DATA resource of index 0. That resource is then compressed with ZLIB.

Looks like DATA0 is zlib'ed, while DATA1+ are not. I will have to update the tools to handle a situation where the same resource ID has compressed and uncompressed sections.

ps.

If anyone wonders about the strange shortcuts we're using, I've made a wiki page on this:

https://labviewwiki.org/wiki/Resource_Container

 

Edited by Mefistotelis
  • Thanks 1
Link to comment
3 hours ago, Mefistotelis said:

The only real issue is lack of VCTP section. The rest of removing the VI from library is trivial, if you check how the file looks before and after compiling the library.

I've got nearly the same result, using flarn's Resource Editor, so fixing LVSR and BDPW blocks is pretty easy. Untying from the library is no problem too. Tomorrow I'm gonna try your tools to see, how they'll go for me, and try to restore VCTP as well according to your info (manually maybe, but hope it could be automated one day). On success I could take a look at LEIF packed libraries to figure out, how to do the same.

3 hours ago, Mefistotelis said:

'tampered with password' message

I was kind of surprised here, because both EXEs and PPLs don't have block diagrams, unless you explicitly set 'debugging' option in the build properties to get the BDs saved. Thus that 'tampered' message is absolutely unnecessary in compiled app or library, but likely there's no additional check in lvrt.dll for such a case, when the checksums don't match.

Link to comment
1 hour ago, dadreamer said:

Tomorrow I'm gonna try your tools to see, how they'll go for me, and try to restore VCTP as well according to your info (manually maybe, but hope it could be automated one day).

ATM my tool doesn't treat the DATA0 section as VCTP, so it only extracts it to BIN file (it does decompress it already). If you rename the section to VCTP, re-pack and re-extract, it should treat that as VCTP data and if the format is identical to "normal" VCTP, it will get converted to XML.

Dividing the section into parts for each VI should be a bit easier in XML form.

Also, worth checking if the whole section can be just put inside each VI. I didn't checked if references to individual types within VIs are increased within lvlibp to refer to entries in the DATA0 section; if they are, dividing DATA0 would also require updating all TypeID references.

 

Edited by Mefistotelis
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.