Jump to content

Mefistotelis

Members
  • Posts

    95
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by Mefistotelis

  1. 3 hours ago, Mefistotelis said:

    it gives us offsets within INSTRUMENT where each value is stored, so that we can cross-reference it

    A good example I just found:

    void InitButtonsHidden(INSTRUMENT **a1)
    {
      (*a1)->sr_field14 = gButtonsHidden[(*a1)->sr_field22];
    }

    Now we can rename one field to 'buttonsHidden', and can assume another field contains enum value representing either state or type.

     

  2. 5 hours ago, Rolf Kalbermatter said:

    Basically this is a pretty unexciting routine. It just copies the data structure from the memory stream on disk into a real data structure in memory and accounts

    for endian swapping on relevant platforms and massages some flags into a different format.

    You are completely right with the assessment of what this function does. But I can't agree it is unexciting:

    - It provides us with full information on how to divide the LVSR block into single values, and it even names one of the values.

    - It gives us offsets within INSTRUMENT where each value is stored, so that we can cross-reference it with other functions and check what they do

    (as you see, I already named the items within INSTRUMENT to "sr_field*" so that I can easily search ehere each of these is used further.

    So actually, almost everything about LVSR which is in my code, comes from this single function:

    https://github.com/mefistotelis/pylabview/blob/master/LVblock.py#L100

    4 hours ago, Cloedu72 said:

    If you are interested in older versions, I can provide you a link to LV3.1.1:
    ftp://ftp.ni.com/support/labview/updates/windows/win3x/31-to-311

    Thanks! I actually downloaded that whole FTP already; and yes, this is where I got LV3.1.1 from. There are 2 binaries - Win16 and WinNT; the WinNT one is better for analysis. But, as I previously stated - before LV6.0, the blocks within VI files were a bit different - so I prefer to work on more recent code.

    As an example, in LV5.0 there was LVIN block instead of the LVSR discussed above.

     

  3. I got a 3.5 inch floppy drive with USB interface - they were very cheap at some pint.

    Anyway, I browsed through various releases available in obscure places of the web. There's A LOT of things created by NI which either use the standard LV runtime environment, or use parts of the LV code.

    I downloaded > 100GB of various files when I decided it's time to stop. There was probably way more to find, but I have to limit my time.

    Findings:

    - Files from Windows platform are the worst port to reverse engineer, mostly because Windows libraries (.DLL) define exported routines explicitly.

    - UNIX base releases (solaris,linux) are the best to debug - compiled for popular CPU architectures, and shared libs (.SO) have all routines exported - meaning their names are retained

    - For some obscure platforms, I found static libraries (.a/.lib) files included in the release. These have the most info on source code retained, but not the whole code was in that form. Not the part I need anyway.

    - The best version to focus on seem to be LV6.0 - the code is a lot less bloated than in newer releases, and the core of the tool didn't seem to have changed much since that release

    (though I didn't found much LV5.0 releases - I can tell 4.0 is too old and does not have many blocks which exist in modern VI files, for 5.0 - I'm not sure)

     

    Here's the loading of LVSR block in LabView 6.0. Unfortunately, I still don't have struct definitions. But at least I know how the structs are named, thanks to C++ name mangling.

    void RToVI(SAVERECORD **sr, INSTRUMENT **instr)
    {
      char fld10a;
      char fld10b;
      INSTRUMENT *dInstr;
      int state;
    
      (*instr)->sr_field4 = (((*sr)->field_4 & 0xFF0000) >> 8) | ((unsigned int)(*sr)->field_4 >> 24) | (((*sr)->field_4 & 0xFF00) << 8) | ((*sr)->field_4 << 24);
      (*instr)->sr_field8 = (((*sr)->field_8 & 0xFF0000) >> 8) | ((unsigned int)(*sr)->field_8 >> 24) | (((*sr)->field_8 & 0xFF00) << 8) | ((*sr)->field_8 << 24);
      (*instr)->sr_fieldC = (((*sr)->field_C & 0xFF0000) >> 8) | ((unsigned int)(*sr)->field_C >> 24) | (((*sr)->field_C & 0xFF00) << 8) | ((*sr)->field_C << 24);
      (*instr)->sr_field12 = _byteswap_ushort((*sr)->field_12);
      (*instr)->instrState = (((*sr)->instrState & 0xFF0000) >> 8) | ((unsigned int)(*sr)->instrState >> 24) | (((*sr)->instrState & 0xFF00) << 8) | ((*sr)->instrState << 24);
      (*instr)->sr_field14 = _byteswap_ushort((*sr)->field_14);
      (*instr)->sr_field16 = _byteswap_ushort((*sr)->field_16);
      (*instr)->sr_field20 = _byteswap_ushort((*sr)->field_20);
      (*instr)->sr_field22 = _byteswap_ushort((*sr)->field_22);
      (*instr)->version = (((*sr)->version & 0xFF0000) >> 8) | ((unsigned int)(*sr)->version >> 24) | (((*sr)->version & 0xFF00) << 8) | ((*sr)->version << 24);
      (*instr)->sr_field24 = (((*sr)->field_24 & 0xFF0000) >> 8) | ((unsigned int)(*sr)->field_24 >> 24) | (((*sr)->field_24 & 0xFF00) << 8) | ((*sr)->field_24 << 24);
      (*instr)->sr_field1C = (((*sr)->field_1C & 0xFF0000) >> 8) | ((unsigned int)(*sr)->field_1C >> 24) | (((*sr)->field_1C & 0xFF00) << 8) | ((*sr)->field_1C << 24);
      qmemcpy(&(*instr)->sr_field34_md5, (*sr)->field34_md6, 0x10u);
      qmemcpy(&(*instr)->sr_field28, &(*sr)->field_28, 0xCu);
      RevBL(&(*instr)->sr_field28);
      RevBL(&(*instr)->field_2C);
      RevBL(&(*instr)->field_30);
      fld10a = (*sr)->field_10;
      fld10b = HIBYTE((*sr)->field_10);
      (*instr)->is_sr_field10_flag0200 = HIBYTE((*sr)->field_10) & 2;
      (*instr)->is_sr_field10_flag0100 = fld10b & 1;
      (*instr)->is_sr_field10_flag0400 = fld10b & 4;
      dInstr = *instr;
      if ( (*instr)->sr_field4 & 0x20000 )
      {
        state = dInstr->instrState;
        if ( state & 0x200 )
        {
          dInstr->instrState = state & 0xFFFFFDFF;
          DBPrintf("Fixing instrState, remove viDebugCapable from subroutine VI");
        }
      }
    }

     

  4. Thanks for all the info!

     

    On 11/22/2019 at 12:53 PM, Rolf Kalbermatter said:

    Thousends of releases? I kind of doubt it.

    Searching for various NI things on the Internet, I found quite a lot of packages which included the LV RT. Various toolsets, drivers, and labview-based solutions. Though most of these use standard release of the RT installer.

    Unfortunately I have no pre-release versions. And this is where I expect higher chance of having some debug info left.

    I've seen indications that VI Logger 1.1 had a pre-release RT in it, but I could only find the fixed 1.1.1.

     

    As of now, I couldn't find the LV 2.5 as well. I found LV 6.0 on one of my old CDs, that's the oldest version I have.

  5. Labview exists for decades. It had thousands of releases.

    When was the last time NI left debug symbols by mistake?

     

    How to recognize a release with debug symbols left:

    - Nowadays Visual Studio keeps the symbols in a PDB file - so probably lvrt.pdb, but it might also have different name - depends on whether the DLL is renamed after build.

    - Previously, up to around year 2000, debug symbols were stored in the EXE/DLL - so lvrt.dll file size would be extraordinarily large, circa 2x-3x the normal size

    - Most compilers can also generate MAP file - it doesn't store as much as full debug symbols do, but has all global variables and functions named - which is still way more than nothing

     

  6. 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.

    • Thanks 1
  7. 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

  8. 1 hour ago, Rolf Kalbermatter said:

    The desired call is not supported in the current LabVIEW version.

    I see; so for the XML function, the tool requires LV2015+.

    This also means the tool doesn't do VI conversion, just uses functionality which is part of the LabView RE.

    1 hour ago, Rolf Kalbermatter said:

    Why do you think this should work?

    I don't know much about LabView. For most of the tools I use, the default state is that they do 'work'. Didn't know I shouldn't expect that :P.

    There's also that:

    On 8/19/2015 at 7:55 AM, flarn2006 said:

    Second version is posted; this one should work in LabVIEW 2014

    In general, I'm looking into this as I'm planning to implement VI-to-XML conversion by myself, and I think it would be nice to keep the conventions introduced by NI.

    EDIT:

    Oh, this was actually already discussed, just a few posts before. Should've read before posting, sorry.

    On 8/27/2015 at 9:53 PM, Cloedu72 said:

    I always receive an error when executing this very interresting tool. The Message look like that (Calling :

    Error 53 occured at Invoke Node in Save VI with XML Heaps.vi

    possible reason:

    Labview: Manager call not supported

    Method Name: Call Internal Command

     

  9. 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.

  10. On 10/31/2019 at 6:19 PM, hooovahh said:

    Now that I'm searching for it I can't find much, but Flarn also had some code for getting file structures of a VI.  His personal site had a few things but seems to be down at the moment.

    http://flarn2006.dyndns.org/llvim/#downloads

    Just be aware that most of his stuff is viewing and editing the objects in a VI, so I'm not sure how useful it will be.  But he should have some general file parsing stuff.

    Thanks; I can look at the page using Wayback Machine, plus I found the related thread:

     

    The LVSR block I want to modify is used to compute checksums which are stored in BDPW (Block Diagram Password) block. So I need to be able to re-create the BDPW values in order to modify LVSR.

    Fields within BDPW, depend on counts of some connectors which are buried deep within VCTP (Virtual Connectors / Terminal Points).

    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.

     

  11. On 10/22/2019 at 2:41 PM, hooovahh said:

    you've probably come across Flarn's stuff

    Actually, I didn't. Tried searching after your post, but only found hidden options thread.

     

    I had a long fight with "conflicts" after I tried to update the reversed project, and now I'm seeing:

    "VI's record of owning library's password does not match library's actual password."

    I did removed password entries from library files. I see the copy of these passwords (i mean, md5 of passwords) in VI files (LVSR section). Will check if I can easily remove these.

     

  12. 7 hours ago, Mefistotelis said:

     if the current solution is broken

    I see that ambiguous wording got a strong reaction. Yes, the format is not broken/cracked currently.

    I actually only found two readers for VIs, both quite rudimentary: one in Python, other in PHP.

    1 hour ago, hooovahh said:

    I do hope you share anything you discover with the community

    I am typically sharing everything I can share. For the specific subject discussed in this thread, see here:

    https://github.com/mefistotelis/pylabview/commit/867dac8e2f249978defa380110efb744ff52c650

    1 hour ago, hooovahh said:

    You cannot keep the executable safe, while also having it be open enough to execute it


    Currently, yes. Though we already have certificates fused into out CPUs, ie. for Protected Audio Video Playback. And there is a lot more of them.

    On ARM, we recently see explosion of TrustZone use. Same principle - protect the code but allow its execution.

     

    I do hope the world will not go this way; but currently, as tools for reversing get better, the push towards protecting them by hardware also increases.

     

  13. Yes, you might be right @Rolf Kalbermatter.

    As long as the whole work can be divided into steps, this might be doable though. For example - there is probably a way to tell labview to compile the assembly. So only disassembling the code, still puts us one step closer, and allows us to create buildable project.

    Right now, I already can replace single VIs and re-build the project. Having ASM blocks would allow me to replace only single blocks inside VIs.

     

    For the people who fear for their code being stolen - if the current solution is broken, NI will put resources into making "real" security in next version - so such reversing effort actually makes the tool more secure, and forces it to move to modern standards.

     

    I'd have to learn about LabView in general to go any deeper; last time I made a project with it was circa 20 years ago. Not sure if I have enough time to go that way.

     

    • Like 1
  14. I mostly meant that this is internal tool used by a company, created years back. Not sure if it was created internally on by a contractor.

     

    Anyway, looks like the tool re-compiles properly from the reversed sources. Can't be completely sure as I don't have a related hardware, but various forms are properly linked to each other and are trying to display something.

    The original project probably had some fake dependencies in it - the smaller binary I built seem to do the same thing as original. (though I can't be sure there's no corner case where it will go "file not found")

    General steps:

    1. Extract EXE, decrypt ZIP inside

    2. Create a folder, create new LabView project there

    3. create sub-folder within project folder, ie. "app" or "lv" or however you want to call the labview app part; copy the files extracted from ZIP there

    4. Copy any config and data files (and folders) distributed with original binary to the project folder

    5. Copy options from BinryName.ini into your BinaryName.lvproj (created in step 2)

    6. Open the project in LabView

    7. Add each folder from your labview app part to the project; use "My Computer" -> "Add" -> "Folder (Auto-populating)"

    8. Make new build target; use "Build Specifications" -> "New" -> "Application"

    9. Set proper "Name: and "Target filename" in build target "Information" tab

    10. Find the starting form of the original app and add it as "Startup VIs" in build target "Source files" tab

    11. You shouldn't have to put anything in "Always included" list in build target "Source files" tab; but if you want - you can now

    12. Disable all the "Remove ..." and "Disconnect ..." options in build target "Additional Exclusions" tab

    13. Fix any "Missing items" in the project, by placing files in correct places or modifying *.lvlib files which point to locations of additional files

    14. Build the project

     

    Now I'm getting interested in the single VI files, and how to get their edit functionality back.

     

  15. Thanks for your answers.

     

    For my use case:

    I have an EXE of a tool which has some functions not working according to needs, I was asked to update these. Not anything desperately needed, but would increase user base of the tool.

    The tool is proprietary, and quite large - 30MB EXE. There is a lot of things inside, and I was hoping I won't have to look at details. Files go in thousands, didn't checked exactly.

    I am not planning on changing LV version; that would require more effort, and that's not really needed.

     

    For my progress:

    I see that LLB folders don't have to be merged into library - the LV itself has a set of folders with .llb extension, so that's normal.

    I looked at the VI files, and the do miss the edit functionalities. I will check other versions of the tool, but I expect that will be the case for every version.

    I tried creating a project and adding everything to it; but the resulting EXE is half of the size of original EXE - so maybe LV cannot see some dependencies? Or the original project has some unnecessary dependencies in it?

    I don't even understand all functionalities of the tool, so can't tell if my version lost something.

     

     

  16. Thanks for the background info, that's good to know.

     

    The ZIP format is chunked with recurring headers, so changing one might've not been enough. That's probably why the whole ZIP is xor'ed.

    This is actually quite poor design - the xor goes single-byte at a time, with key depending on previous results. 8-bit ops are slow on newer CPUs (compared to 32 or 64), plus it makes it impossible to use multiple threads. This makes the decryption unnecessarily slow.

    Anyone beyond student grade would now consider dividing the archive into blocks, and decrypting these blocks separately, on different CPU cores. But I guess back when the algorithm was created, that might not have been so obvious.

     

    For the VIs having some blocks removed from final EXE - it actually isn't possible to secure environment such as LabView completely. Just a matter of someone having enough free time. Though the amount of time required might be really considerable here..

    (not that this is wrong strategy on NIs side - after all, all the modern security algorithms are based on long time required to bypass)

     

  17. I have a built LabView 14 project which I want to get back to a form which would allow me to "build" it again.

    My programming skills are high, but LabView skill is almost non-existent.

     

    I found LLB file within the Windows Resources of PE Executable.

    I noticed the LLB file contains one, large "block" of data inside, called 'LVzp', which is encrypted.I wrote proper xor-based decryption algorithm.

    This resulted in a Zip file. I extracted the ZIP, and found many folders and files inside.

    Some folders have names which indicate they might've been libraries in original project, but were all extracted and put into directory structure instead. For example, I see a folder "vi.lib", and inside there's a folder "dlg_ctls.llb".

    Now to my questions:

    How should I prepare all that for re-building?

    Should I re-create all the LLB files from single VI files I see in extracted folders?

    Should I also create LIB files before adding everything to a new project? I understand that "New -> Library" in project view creates LLB file, how do I create LIBs?

    Or maybe adding everything to a project as-is will work as well?

    Are any specific actions needed to re-create a project out of these files? I figured all the "Remove ..." options in "Additional Exclusions" tab of build target need to be unchecked, anything more?

     

  18. A lot of time passed. Many new tools are available. Possibilities have evolved.

    On 4/24/2013 at 4:03 PM, hooovahh said:

    The LVzp block started with the same for the 2 EXEs I tested which is the following:

    Quote
    70 5A 6B D6 B4 55 AB 56 AD 5B

    What if I told you that it is still the same ZIP format?

    The LabView Runtime Library must be extracting this somehow, right? So it shouldn't be hard to find, if you know the chunk ID is 'LVzp' (possibly backwards due to endianness) and there's zip extractor around (unzip from zlib, version from circa 2012).

    Find my Github projects for details.

×
×
  • Create New...

Important Information

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