Getting a table from an Excel worksheet
Basically, this isn't recursion but just overloading methods being called from each other, which is a valid approach targeting the problem.  

But nevertheless, you could do better.  


Naming

Based on the naming guidelines method parameters should be nameed using camelCase casing.
If you have own naming guidelines you for sure should stick to them.  

Abbreviations for naming variables like loFound doesn't tell anything at all. You should name your variable as meaningful as possible. In that way Sam the maintainer won't have a hard time evaluating the purpose of the variable. That being said, I would have expected a name like foundTable inside a method named GetTable().  
Scope  

You should declare your variables as near as possible to their usage. It does not help readability if you declare them at the top of the method if you use them way down the method.  
Using the right type  

It doesn't make sense to use a List&lt;T&gt; to collect items and then calling ToArray() because the method to be called takes an array as parameter, at least if you can change it.  

I would like to suggest changing the parameter to IEnumerable&lt;T&gt; because you are only iterating over the array which can be done in the same way with an IEnumerable&lt;T&gt; and much better, if you want to pass an array, a List&lt;T&gt; or a ICollection&lt;T&gt; you can still do it.  

You should always try to code against interfaces and not against a concrete implementation.  
Spacing  

By adding vertical space to logicaly related code your code will improve readability.  




So let us take a look at this  


Public Overloads Function GetTable(ByVal SearchName As String, ByVal SearchBooks() As Workbook, Optional ByVal ExactMatch As Boolean = False) As ListObject
   Dim loFound As ListObject
   Dim wsList As New List(Of Worksheet)
   Try
       For Each wb In SearchBooks
           For Each ws In wb.Worksheets
               wsList.Add(ws)
           Next
           loFound = Me.GetTable(SearchName:=SearchName, SearchSheets:=wsList.ToArray, ExactMatch:=ExactMatch)
           If Not loFound Is Nothing Then Return loFound
       Next
   Catch ex As Exception
       MessageBox.Show(ex.ToString)
   End Try
   Return Nothing
End Function



The List&lt;T&gt; class has a method AddRange() to add a range of objects. This would improve the method regarding performance.  

But you would gain lot more performance if you would declare the List&lt;T&gt; just inside the outer loop. Why do you add all of the WorkSheets but never clear the List ? You will iterate over the whole list each time the searched item isn't found.  

So let us do this right. Because the Sheets interface implements IEnumerable we can use the overloaded constructor of List&lt;T&gt; and pass the IEnumerable like so   

Public Overloads Function GetTable(ByVal searchName As String, ByVal searchBooks As IEnumerable(Of Workbook), Optional ByVal exactMatch As Boolean = False) As ListObject()

    Try
        For Each wb In searchBooks
            Dim sheets As New List(Of Worksheet)(wb.Sheets.OfType(Of Worksheet))

            Dim foundTable As ListObject = Me.GetTable(searchName:=searchName, searchSheets:=sheets, exactMatch:=exactMatch)
            If Not foundTable Is Nothing Then Return foundTable

        Next
    Catch ex As Exception
        MessageBox.Show(ex.ToString)
    End Try
    Return Nothing
End Function